anteriority-ui 1.0.0

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 (199) hide show
  1. package/.github/workflows/ci.yml +31 -0
  2. package/.github/workflows/publish.yml +45 -0
  3. package/.npmrc.bak +1 -0
  4. package/.storybook/main.js +15 -0
  5. package/.storybook/preview.jsx +26 -0
  6. package/AnteriorityUI.md +2400 -0
  7. package/CLAUDE.md +91 -0
  8. package/README.md +182 -0
  9. package/assets/anteriorityUI/AnteriorityUI.logo.jpeg +0 -0
  10. package/assets/favicon/anteriorityUI.ico +0 -0
  11. package/common/api/client.js +43 -0
  12. package/common/storage/LocalStorage.js +13 -0
  13. package/common/styles/typography.css +5 -0
  14. package/common/styles/variables.css +192 -0
  15. package/common/theme/muiTheme.js +9 -0
  16. package/features/password-reset/api.js +39 -0
  17. package/features/user-profile/api.js +5 -0
  18. package/hooks/useAdminPasswordReset.js +133 -0
  19. package/index.js +57 -0
  20. package/package.json +57 -0
  21. package/pnpm-workspace.yaml +3 -0
  22. package/screens/components/AlertModal/AlertModal.jsx +259 -0
  23. package/screens/components/AlertModal/AlertModal.module.css +185 -0
  24. package/screens/components/AlertModal/AlertModal.stories.jsx +87 -0
  25. package/screens/components/Avatar/index.jsx +0 -0
  26. package/screens/components/Avatar/index.module.css +0 -0
  27. package/screens/components/Avatar/utils.js +0 -0
  28. package/screens/components/Badge/index.jsx +33 -0
  29. package/screens/components/Badge/index.module.css +18 -0
  30. package/screens/components/Badge/index.stories.jsx +40 -0
  31. package/screens/components/Barnner/index.jsx +21 -0
  32. package/screens/components/Barnner/index.module.css +33 -0
  33. package/screens/components/Barnner/index.stories.jsx +39 -0
  34. package/screens/components/Barnner/utils.js +0 -0
  35. package/screens/components/BlueLink/index.jsx +27 -0
  36. package/screens/components/BlueLink/index.module.css +11 -0
  37. package/screens/components/BlueLink/index.stories.jsx +29 -0
  38. package/screens/components/Breadcrumbs/index.jsx +62 -0
  39. package/screens/components/Breadcrumbs/index.module.css +158 -0
  40. package/screens/components/Breadcrumbs/index.stories.jsx +37 -0
  41. package/screens/components/Button/index.jsx +169 -0
  42. package/screens/components/Button/index.module.css +168 -0
  43. package/screens/components/Button/index.stories.jsx +71 -0
  44. package/screens/components/Button/utils.js +28 -0
  45. package/screens/components/CalendarComponent/CustomDatePicker.jsx +248 -0
  46. package/screens/components/CalendarComponent/CustomDatePicker.module.css +323 -0
  47. package/screens/components/CalendarComponent/CustomDatePicker.stories.jsx +45 -0
  48. package/screens/components/CalendarPicker/Constants.js +12 -0
  49. package/screens/components/CalendarPicker/index.jsx +263 -0
  50. package/screens/components/CalendarPicker/index.module.css +147 -0
  51. package/screens/components/CalendarPicker/index.stories.jsx +45 -0
  52. package/screens/components/CalendarPicker/utils.js +42 -0
  53. package/screens/components/CardV1/index.jsx +165 -0
  54. package/screens/components/CardV1/index.module.css +232 -0
  55. package/screens/components/CardV1/index.stories.jsx +62 -0
  56. package/screens/components/CardV1/utils.js +49 -0
  57. package/screens/components/ChatWindow/index.jsx +251 -0
  58. package/screens/components/ChatWindow/index.module.css +311 -0
  59. package/screens/components/ChatWindow/index.stories.jsx +62 -0
  60. package/screens/components/Checks/index.jsx +31 -0
  61. package/screens/components/Checks/index.module.css +32 -0
  62. package/screens/components/Checks/index.stories.jsx +32 -0
  63. package/screens/components/Container/index.jsx +36 -0
  64. package/screens/components/Container/index.module.css +24 -0
  65. package/screens/components/Container/index.stories.jsx +32 -0
  66. package/screens/components/CopyText/index.jsx +42 -0
  67. package/screens/components/CopyText/index.module.css +52 -0
  68. package/screens/components/CopyText/index.stories.jsx +24 -0
  69. package/screens/components/CountdownBar/constants.js +3 -0
  70. package/screens/components/CountdownBar/index.jsx +81 -0
  71. package/screens/components/CountdownBar/index.module.css +45 -0
  72. package/screens/components/CountdownBar/index.stories.jsx +43 -0
  73. package/screens/components/CountdownBar/utils.js +119 -0
  74. package/screens/components/DateTag/index.jsx +33 -0
  75. package/screens/components/DateTag/index.module.css +12 -0
  76. package/screens/components/DateTag/index.stories.jsx +29 -0
  77. package/screens/components/DesplegablePanel/constants.js +0 -0
  78. package/screens/components/DesplegablePanel/index.jsx +61 -0
  79. package/screens/components/DesplegablePanel/index.module.css +120 -0
  80. package/screens/components/DesplegablePanel/index.stories.jsx +44 -0
  81. package/screens/components/DesplegablePanel/utils.js +0 -0
  82. package/screens/components/DrawPanel/index.jsx +217 -0
  83. package/screens/components/DrawPanel/index.module.css +252 -0
  84. package/screens/components/DrawPanel/index.stories.jsx +66 -0
  85. package/screens/components/DrawPanel/utils.js +0 -0
  86. package/screens/components/Filter/index.jsx +105 -0
  87. package/screens/components/Filter/index.module.css +91 -0
  88. package/screens/components/Filter/index.stories.jsx +46 -0
  89. package/screens/components/Filter/utils.js +0 -0
  90. package/screens/components/FormControls/FormControls.module.css +86 -0
  91. package/screens/components/FormControls/index.jsx +51 -0
  92. package/screens/components/FormControls/index.stories.jsx +36 -0
  93. package/screens/components/Frame/index.jsx +54 -0
  94. package/screens/components/Frame/index.module.css +102 -0
  95. package/screens/components/Frame/index.stories.jsx +37 -0
  96. package/screens/components/Frame/utils.js +0 -0
  97. package/screens/components/GreenHighlight/index.jsx +11 -0
  98. package/screens/components/GreenHighlight/index.module.css +7 -0
  99. package/screens/components/GreenHighlight/index.stories.jsx +26 -0
  100. package/screens/components/GreenHighlight/utils.jsx +45 -0
  101. package/screens/components/HoursPicker/Constants.js +26 -0
  102. package/screens/components/HoursPicker/index.jsx +350 -0
  103. package/screens/components/HoursPicker/index.module.css +99 -0
  104. package/screens/components/HoursPicker/index.stories.jsx +44 -0
  105. package/screens/components/HoursPicker/utils.js +48 -0
  106. package/screens/components/InfoTooltip/index.jsx +59 -0
  107. package/screens/components/InfoTooltip/index.module.css +98 -0
  108. package/screens/components/InfoTooltip/index.stories.jsx +35 -0
  109. package/screens/components/Input/index.jsx +36 -0
  110. package/screens/components/Input/index.module.css +49 -0
  111. package/screens/components/Input/index.stories.jsx +37 -0
  112. package/screens/components/Input/utils.js +0 -0
  113. package/screens/components/Loading/index.jsx +76 -0
  114. package/screens/components/Loading/index.module.css +193 -0
  115. package/screens/components/Loading/index.stories.jsx +38 -0
  116. package/screens/components/Loading/utils.js +0 -0
  117. package/screens/components/MarkdownContent/index.jsx +16 -0
  118. package/screens/components/MarkdownContent/index.module.css +149 -0
  119. package/screens/components/MarkdownContent/index.stories.jsx +30 -0
  120. package/screens/components/MarkdownEditor/index.jsx +430 -0
  121. package/screens/components/MarkdownEditor/index.module.css +192 -0
  122. package/screens/components/MarkdownEditor/index.stories.jsx +50 -0
  123. package/screens/components/Material-UI/Components/InputWithIcon/index.jsx +87 -0
  124. package/screens/components/Material-UI/Components/InputWithIcon/index.stories.jsx +49 -0
  125. package/screens/components/Material-UI/Components/MenuPopover/index.jsx +117 -0
  126. package/screens/components/Material-UI/Components/MenuPopover/index.stories.jsx +36 -0
  127. package/screens/components/Material-UI/Components/MultilinePlaceholder/index.jsx +44 -0
  128. package/screens/components/Material-UI/Components/MultilinePlaceholder/index.stories.jsx +45 -0
  129. package/screens/components/Material-UI/Components/Paginador/index.jsx +79 -0
  130. package/screens/components/Material-UI/Components/Paginador/index.stories.jsx +49 -0
  131. package/screens/components/Material-UI/Components/Search/index.jsx +81 -0
  132. package/screens/components/Material-UI/Components/Search/index.stories.jsx +68 -0
  133. package/screens/components/Material-UI/Components/Selector/index.jsx +100 -0
  134. package/screens/components/Material-UI/Components/Selector/index.module.css +0 -0
  135. package/screens/components/Material-UI/Components/Selector/index.stories.jsx +52 -0
  136. package/screens/components/Material-UI/Components/Selector/utils.js +0 -0
  137. package/screens/components/Material-UI/Components/TextField/index.jsx +61 -0
  138. package/screens/components/Material-UI/Components/TextField/index.stories.jsx +53 -0
  139. package/screens/components/ModalTooltip/ModalTooltip.jsx +122 -0
  140. package/screens/components/ModalTooltip/ModalTooltip.module.css +65 -0
  141. package/screens/components/ModalTooltip/ModalTooltip.stories.jsx +39 -0
  142. package/screens/components/Notification/Error/ErrorMessage.jsx +30 -0
  143. package/screens/components/Notification/Error/ErrorMessage.module.css +57 -0
  144. package/screens/components/Notification/Error/ErrorMessage.stories.jsx +37 -0
  145. package/screens/components/PasswordResetPanel/index.jsx +325 -0
  146. package/screens/components/PasswordResetPanel/index.stories.jsx +26 -0
  147. package/screens/components/PlaceholderButton/index.jsx +169 -0
  148. package/screens/components/PlaceholderButton/index.module.css +162 -0
  149. package/screens/components/PlaceholderButton/index.stories.jsx +69 -0
  150. package/screens/components/PlaceholderButton/utils.js +42 -0
  151. package/screens/components/Profile/Avatar/index.jsx +125 -0
  152. package/screens/components/Profile/Avatar/index.module.css +86 -0
  153. package/screens/components/Profile/Avatar/index.stories.jsx +48 -0
  154. package/screens/components/Profile/Avatar/utils.js +18 -0
  155. package/screens/components/Profile/index.jsx +58 -0
  156. package/screens/components/Profile/index.module.css +0 -0
  157. package/screens/components/Profile/index.stories.jsx +38 -0
  158. package/screens/components/Profile/utils.js +0 -0
  159. package/screens/components/ScrollBar/index.jsx +62 -0
  160. package/screens/components/ScrollBar/index.module.css +78 -0
  161. package/screens/components/ScrollBar/index.stories.jsx +64 -0
  162. package/screens/components/ScrollBar/utils.js +127 -0
  163. package/screens/components/Sidebar/constants.js +16 -0
  164. package/screens/components/Sidebar/index.jsx +399 -0
  165. package/screens/components/Sidebar/index.module.css +405 -0
  166. package/screens/components/Sidebar/index.stories.jsx +86 -0
  167. package/screens/components/Sidebar/utils.js +75 -0
  168. package/screens/components/Skeleton/index.jsx +11 -0
  169. package/screens/components/Skeleton/index.module.css +26 -0
  170. package/screens/components/Skeleton/index.stories.jsx +42 -0
  171. package/screens/components/SubSidebarLayout/index.jsx +44 -0
  172. package/screens/components/SubSidebarLayout/index.module.css +80 -0
  173. package/screens/components/SubSidebarLayout/index.stories.jsx +51 -0
  174. package/screens/components/SummaryCard/index.jsx +50 -0
  175. package/screens/components/SummaryCard/index.module.css +30 -0
  176. package/screens/components/SummaryCard/index.stories.jsx +29 -0
  177. package/screens/components/Swich/constants.js +4 -0
  178. package/screens/components/Swich/index.jsx +85 -0
  179. package/screens/components/Swich/index.module.css +68 -0
  180. package/screens/components/Swich/index.stories.jsx +44 -0
  181. package/screens/components/Swich/utils.js +0 -0
  182. package/screens/components/TableA/index.jsx +156 -0
  183. package/screens/components/TableA/index.module.css +105 -0
  184. package/screens/components/TableA/index.stories.jsx +116 -0
  185. package/screens/components/TableA/utils.js +11 -0
  186. package/screens/components/TableB/index.jsx +222 -0
  187. package/screens/components/TableB/index.module.css +295 -0
  188. package/screens/components/TableB/index.stories.jsx +110 -0
  189. package/screens/components/TableB/utils.js +11 -0
  190. package/screens/components/ToggleCard/index.jsx +64 -0
  191. package/screens/components/ToggleCard/index.module.css +111 -0
  192. package/screens/components/ToggleCard/index.stories.jsx +49 -0
  193. package/screens/components/UserEditPopover/index.jsx +102 -0
  194. package/screens/components/UserEditPopover/index.module.css +97 -0
  195. package/screens/components/UserEditPopover/index.stories.jsx +49 -0
  196. package/scripts/build.mjs +129 -0
  197. package/scripts/check-case.mjs +127 -0
  198. package/scripts/verify-dist.mjs +45 -0
  199. package/vitest.config.js +36 -0
@@ -0,0 +1,169 @@
1
+ import React from 'react';
2
+ import MuiButton from '@mui/material/Button';
3
+ import CircularProgress from '@mui/material/CircularProgress';
4
+ import { VARIANTS, SIZES, COLORS } from './utils';
5
+ import styles from './index.module.css';
6
+ import ModalTooltip from '../ModalTooltip/ModalTooltip';
7
+
8
+ const Button = React.forwardRef(({
9
+ children,
10
+ variant = 'primary',
11
+ size = 'medium',
12
+ active = false,
13
+ fullWidth = false,
14
+ icon: Icon,
15
+ onClick,
16
+ disabled = false,
17
+ type = 'button',
18
+ className = '',
19
+ color,
20
+ border,
21
+ borderColor,
22
+ style = {},
23
+ loading = false,
24
+ success = undefined,
25
+ circle = false,
26
+ ToolTip = false,
27
+ title,
28
+ ...props
29
+ }, ref) => {
30
+
31
+ // Map custom variant to MUI variant
32
+ let muiVariant = 'contained';
33
+ if (variant === 'outline') muiVariant = 'outlined';
34
+ if (variant === 'ghost' || variant === 'tab' || variant === 'list-item' || color === 'transparent') muiVariant = 'text';
35
+
36
+ // Map custom size to MUI size
37
+ const muiSize = size === 'large' ? 'large' : size === 'small' ? 'small' : 'medium';
38
+
39
+ // Map standard colors to MUI color prop if possible
40
+ let muiColor = 'primary';
41
+ if (variant === 'danger' || color === 'var(--color-danger)' || color === 'var(--cancel-button)' || color === 'red') muiColor = 'error';
42
+ if (variant === 'secondary' || color === 'var(--color-secondary)') muiColor = 'secondary';
43
+ if (color === 'var(--button-green)' || color === 'green') muiColor = 'success';
44
+ if (color === 'transparent' || variant === 'list-item') muiColor = 'inherit';
45
+ if (border || borderColor) { muiVariant = 'outlined'; }
46
+
47
+ // "list-item": fila seleccionable de ancho completo, alineada a la izquierda (pickers,
48
+ // listas dentro de un DrawPanel/popover). Los colores quedan pensados para paneles oscuros
49
+ // por default, pero se pueden pisar con el prop "style" como cualquier otro variant.
50
+ const listItemStyle = variant === 'list-item' ? {
51
+ width: '100%',
52
+ justifyContent: 'flex-start',
53
+ textAlign: 'left',
54
+ padding: '0.65rem 0.85rem',
55
+ borderRadius: '8px',
56
+ border: '1px solid rgba(255, 255, 255, 0.06)',
57
+ backgroundColor: 'rgba(255, 255, 255, 0.02)',
58
+ color: '#e6e8ec',
59
+ fontWeight: 500,
60
+ fontSize: '0.85rem',
61
+ '&:hover': {
62
+ backgroundColor: 'rgba(255, 255, 255, 0.05)',
63
+ },
64
+ } : {};
65
+
66
+ // Check if we need to apply custom color overrides via sx
67
+ const standardMuiColors = ['inherit', 'primary', 'secondary', 'success', 'error', 'info', 'warning'];
68
+ const isCustomColor = color && color !== 'transparent' && !standardMuiColors.includes(muiColor) && !standardMuiColors.includes(color);
69
+
70
+ // Active state styling
71
+ const activeStyle = active ? { backgroundColor: 'rgba(0, 0, 0, 0.08)' } : {};
72
+
73
+ // Circle styling
74
+ const circleStyle = circle ? {
75
+ borderRadius: '50%',
76
+ minWidth: 0,
77
+ padding: size === 'small' ? '6px' : (size === 'large' ? '12px' : '8px')
78
+ } : {};
79
+
80
+ // Custom colors processing
81
+ const customColors = {};
82
+ if (isCustomColor) {
83
+ if (muiVariant === 'contained') {
84
+ customColors.backgroundColor = color;
85
+ customColors.color = '#fff';
86
+ customColors['&:hover'] = { backgroundColor: color, filter: 'brightness(0.9)' };
87
+ } else if (muiVariant === 'outlined') {
88
+ customColors.borderColor = color;
89
+ customColors.color = color;
90
+ customColors['&:hover'] = { borderColor: color, backgroundColor: 'rgba(0, 0, 0, 0.04)' };
91
+ } else {
92
+ customColors.color = color;
93
+ customColors['&:hover'] = { backgroundColor: 'rgba(0, 0, 0, 0.04)' };
94
+ }
95
+ }
96
+
97
+ // Handle explicit border and borderColor
98
+ if (border || borderColor) {
99
+ const bColor = borderColor || border || 'black';
100
+ customColors.border = `1px solid ${bColor} !important`;
101
+ if (!isCustomColor) {
102
+ customColors.borderColor = `${bColor} !important`;
103
+ customColors.color = `${bColor} !important`;
104
+ }
105
+ }
106
+
107
+ // Handle icon size
108
+ const iconSize = size === 'small' ? 16 : size === 'large' ? 22 : 18;
109
+
110
+ const isButtonDisabled = disabled || loading || (success === false);
111
+
112
+ const handleClick = (e) => {
113
+ if (isButtonDisabled) {
114
+ e.preventDefault();
115
+ return;
116
+ }
117
+ if (onClick) onClick(e);
118
+ };
119
+
120
+ const buttonElement = (
121
+ <MuiButton
122
+ ref={ref}
123
+ type={type}
124
+ variant={muiVariant}
125
+ size={muiSize}
126
+ color={isCustomColor ? undefined : (standardMuiColors.includes(color) ? color : muiColor)}
127
+ fullWidth={fullWidth}
128
+ disabled={isButtonDisabled}
129
+ onClick={handleClick}
130
+ className={className}
131
+ startIcon={!circle && !loading && Icon ? <span style={{ display: 'inline-flex' }}><Icon size={iconSize} /></span> : undefined}
132
+ sx={{
133
+ textTransform: 'none',
134
+ borderRadius: '8px',
135
+ fontWeight: 600,
136
+ boxShadow: (variant === 'primary' && color !== 'transparent' && !isButtonDisabled) ? '0 4px 6px -1px rgba(14, 165, 233, 0.2)' : 'none',
137
+ ...listItemStyle,
138
+ ...circleStyle,
139
+ ...activeStyle,
140
+ ...customColors,
141
+ ...style
142
+ }}
143
+ {...props}
144
+ >
145
+ {/* If it's a circle button with an icon, we render the icon inside as children, without startIcon spacing */}
146
+ {loading ? (
147
+ <CircularProgress size={iconSize} color="inherit" />
148
+ ) : circle && Icon ? (
149
+ <span style={{ display: 'inline-flex' }}><Icon size={iconSize} /></span>
150
+ ) : (
151
+ children
152
+ )}
153
+ </MuiButton>
154
+ );
155
+
156
+ const tooltipText = typeof ToolTip === 'string' ? ToolTip : title;
157
+ if (ToolTip && tooltipText) {
158
+ return <ModalTooltip text={tooltipText}>{buttonElement}</ModalTooltip>;
159
+ }
160
+
161
+ return buttonElement;
162
+ });
163
+
164
+ Button.VARIANTS = VARIANTS;
165
+ Button.SIZES = SIZES;
166
+ Button.COLORS = COLORS;
167
+
168
+ export { VARIANTS, SIZES, COLORS };
169
+ export default Button;
@@ -0,0 +1,168 @@
1
+ .button {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ gap: 8px;
6
+ font-family: 'Inter', 'Segoe UI', sans-serif;
7
+ font-weight: 500;
8
+ border-radius: 5px;
9
+ border: 1px solid transparent;
10
+ cursor: pointer;
11
+ transition: all 0.2s ease-in-out;
12
+ outline: none;
13
+ position: relative;
14
+ overflow: hidden;
15
+ }
16
+
17
+ .button:disabled {
18
+ opacity: 0.6;
19
+ cursor: not-allowed;
20
+ }
21
+
22
+ .iconWrapper {
23
+ display: inline-flex;
24
+ align-items: center;
25
+ }
26
+
27
+ /* SIZES */
28
+ .small {
29
+ padding: 6px 12px;
30
+ font-size: 0.875rem;
31
+ }
32
+ .medium {
33
+ padding: 8px 16px;
34
+ font-size: 0.95rem;
35
+ }
36
+ .large {
37
+ padding: 12px 24px;
38
+ font-size: 1.1rem;
39
+ }
40
+ .fullWidth {
41
+ width: 100%;
42
+ }
43
+
44
+ /* VARIANTS */
45
+ .primary {
46
+ background-color: #0ea5e9;
47
+ color: white;
48
+ }
49
+ .primary:hover:not(:disabled) {
50
+ background-color: #0284c7;
51
+ }
52
+
53
+ .secondary {
54
+ background-color: #f1f5f9;
55
+ color: #334155;
56
+ border-color: #e2e8f0;
57
+ }
58
+ .secondary:hover:not(:disabled) {
59
+ background-color: #e2e8f0;
60
+ color: #0f172a;
61
+ }
62
+
63
+ .ghost {
64
+ background-color: transparent;
65
+ color: #64748b;
66
+ }
67
+ .ghost:hover:not(:disabled) {
68
+ background-color: #f1f5f9;
69
+ color: #334155;
70
+ }
71
+
72
+ .outline {
73
+ background-color: transparent;
74
+ border-color: #0ea5e9;
75
+ color: #0ea5e9;
76
+ }
77
+ .outline:hover:not(:disabled) {
78
+ background-color: #f0f9ff;
79
+ }
80
+
81
+ .danger {
82
+ background-color: #ef4444;
83
+ color: white;
84
+ }
85
+ .danger:hover:not(:disabled) {
86
+ background-color: #dc2626;
87
+ }
88
+
89
+ /* TAB Variant */
90
+ .tab {
91
+ background-color: transparent;
92
+ color: #64748b;
93
+ border-bottom: 2px solid transparent;
94
+ border-radius: 0;
95
+ padding: 8px 12px;
96
+ }
97
+ .tab:hover:not(:disabled) {
98
+ color: #0ea5e9;
99
+ background-color: #f8fafc;
100
+ }
101
+ .tab.active {
102
+ color: #0ea5e9;
103
+ border-bottom-color: #0ea5e9;
104
+ background-color: #f0f9ff;
105
+ }
106
+
107
+ .ripple {
108
+ position: absolute;
109
+ border-radius: 50%;
110
+ transform: scale(0);
111
+ animation: ripple 0.6s linear;
112
+ background-color: rgba(255, 255, 255, 0.4);
113
+ pointer-events: none;
114
+ }
115
+
116
+ .secondary .ripple,
117
+ .ghost .ripple,
118
+ .outline .ripple,
119
+ .tab .ripple {
120
+ background-color: rgba(0, 0, 0, 0.1);
121
+ }
122
+
123
+ @keyframes ripple {
124
+ to {
125
+ transform: scale(4);
126
+ opacity: 0;
127
+ }
128
+ }
129
+
130
+ .spinning {
131
+ animation: spin 1s linear infinite;
132
+ }
133
+
134
+ @keyframes spin {
135
+ from {
136
+ transform: rotate(0deg);
137
+ }
138
+ to {
139
+ transform: rotate(360deg);
140
+ }
141
+ }
142
+
143
+ /* Transparent color override */
144
+ .transparentColor {
145
+ background-color: transparent !important;
146
+ border-color: transparent !important;
147
+ color: inherit !important;
148
+ }
149
+ .transparentColor:hover:not(:disabled) {
150
+ background-color: #e2e8f0 !important;
151
+ }
152
+ .transparentColor .ripple {
153
+ background-color: rgba(0, 0, 0, 0.25) !important;
154
+ }
155
+
156
+ /* Circle Button */
157
+ .circle {
158
+ border-radius: 50% !important;
159
+ padding: 8px !important;
160
+ width: 36px;
161
+ height: 36px;
162
+ display: inline-flex;
163
+ align-items: center;
164
+ justify-content: center;
165
+ }
166
+ .circle .iconWrapper {
167
+ margin: 0;
168
+ }
@@ -0,0 +1,71 @@
1
+ import React from 'react';
2
+ import { Star, Trash2, Plus } from 'lucide-react';
3
+ import Button, { VARIANTS, SIZES, COLORS } from './index';
4
+
5
+ export default {
6
+ title: 'Components/Button',
7
+ component: Button,
8
+ };
9
+
10
+ export const Primary = {
11
+ args: {
12
+ variant: VARIANTS.PRIMARY,
13
+ size: SIZES.MEDIUM,
14
+ children: 'Guardar',
15
+ onClick: () => console.log('clicked'),
16
+ },
17
+ };
18
+
19
+ export const Secondary = {
20
+ args: {
21
+ variant: VARIANTS.SECONDARY,
22
+ children: 'Cancelar',
23
+ onClick: () => console.log('clicked'),
24
+ },
25
+ };
26
+
27
+ export const Danger = {
28
+ args: {
29
+ variant: VARIANTS.DANGER,
30
+ icon: Trash2,
31
+ children: 'Eliminar',
32
+ onClick: () => console.log('clicked'),
33
+ },
34
+ };
35
+
36
+ export const WithIcon = {
37
+ args: {
38
+ variant: VARIANTS.OUTLINE,
39
+ icon: Plus,
40
+ children: 'Agregar',
41
+ onClick: () => console.log('clicked'),
42
+ },
43
+ };
44
+
45
+ export const Loading = {
46
+ args: {
47
+ variant: VARIANTS.PRIMARY,
48
+ loading: true,
49
+ children: 'Guardando...',
50
+ },
51
+ };
52
+
53
+ export const Disabled = {
54
+ args: {
55
+ variant: VARIANTS.PRIMARY,
56
+ disabled: true,
57
+ children: 'No disponible',
58
+ },
59
+ };
60
+
61
+ export const CircleWithTooltip = {
62
+ args: {
63
+ variant: VARIANTS.GHOST,
64
+ circle: true,
65
+ icon: Star,
66
+ color: COLORS.GREEN,
67
+ ToolTip: true,
68
+ title: 'Marcar como favorito',
69
+ onClick: () => console.log('clicked'),
70
+ },
71
+ };
@@ -0,0 +1,28 @@
1
+ export const VARIANTS = {
2
+ PRIMARY: 'primary',
3
+ SECONDARY: 'secondary',
4
+ GHOST: 'ghost',
5
+ DANGER: 'danger',
6
+ OUTLINE: 'outline',
7
+ TAB: 'tab',
8
+ LIST_ITEM: 'list-item'
9
+ };
10
+
11
+ export const SIZES = {
12
+ SMALL: 'small',
13
+ MEDIUM: 'medium',
14
+ LARGE: 'large'
15
+ };
16
+
17
+ export const COLORS = {
18
+ PRIMARY: 'var(--color-primary)',
19
+ SECONDARY: 'var(--color-secondary)',
20
+ DANGER: 'var(--color-danger)',
21
+ LOGIN: 'var(--btn-login)',
22
+ GREEN: 'var(--button-green)',
23
+ BLUE: 'var(--btn-blue)',
24
+ RED: 'var(--cancel-button)',
25
+ BLACK: 'var(--color-black)',
26
+ WHITE: 'var(--color-white)',
27
+ TRANSPARENT: 'transparent',
28
+ };
@@ -0,0 +1,248 @@
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { format, addMonths, subMonths, startOfMonth, endOfMonth, eachDayOfInterval, isSameDay, isSameMonth, startOfWeek, setMonth, setYear } from 'date-fns';
3
+ import { es } from 'date-fns/locale';
4
+ import { ChevronLeft, ChevronRight, CalendarDays, X, ChevronDown } from 'lucide-react';
5
+ import styles from './CustomDatePicker.module.css';
6
+ import TextField from '../Material-UI/Components/TextField/index';
7
+
8
+ const CustomDatePicker = ({ label, name, value, onChange, required = false, disabled = false, selectedColor, accentColor }) => {
9
+ const [currentDate, setCurrentDate] = useState(new Date());
10
+ const [isOpen, setIsOpen] = useState(false);
11
+ const [showSelectors, setShowSelectors] = useState(false);
12
+ const modalRef = useRef(null);
13
+
14
+ let selectedDate = null;
15
+ if (value instanceof Date && !Number.isNaN(value.getTime())) {
16
+ selectedDate = value;
17
+ } else if (typeof value === 'string' && value.trim() !== '') {
18
+ const match = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
19
+ if (match) {
20
+ const year = Number(match[1]);
21
+ const month = Number(match[2]);
22
+ const day = Number(match[3]);
23
+ selectedDate = new Date(year, month - 1, day);
24
+ } else {
25
+ const fallbackDate = new Date(value);
26
+ if (!Number.isNaN(fallbackDate.getTime())) {
27
+ selectedDate = new Date(
28
+ fallbackDate.getUTCFullYear(),
29
+ fallbackDate.getUTCMonth(),
30
+ fallbackDate.getUTCDate()
31
+ );
32
+ }
33
+ }
34
+ }
35
+
36
+ const monthStart = startOfMonth(currentDate);
37
+ const monthEnd = endOfMonth(monthStart);
38
+ const startDate = startOfWeek(monthStart, { weekStartsOn: 1 });
39
+
40
+ const daysInterval = eachDayOfInterval({
41
+ start: startDate,
42
+ end: monthEnd,
43
+ });
44
+
45
+ useEffect(() => {
46
+ const handleKeyDown = (e) => {
47
+ if (e.key === 'Escape') {
48
+ setIsOpen(false);
49
+ setShowSelectors(false);
50
+ }
51
+ };
52
+ if (isOpen) {
53
+ document.body.style.overflow = 'hidden';
54
+ window.addEventListener('keydown', handleKeyDown);
55
+ }
56
+ return () => {
57
+ document.body.style.overflow = '';
58
+ window.removeEventListener('keydown', handleKeyDown);
59
+ };
60
+ }, [isOpen]);
61
+
62
+ const handleNextMonth = () => setCurrentDate(addMonths(currentDate, 1));
63
+ const handlePrevMonth = () => setCurrentDate(subMonths(currentDate, 1));
64
+
65
+ const handleDateClick = (day) => {
66
+ if (isSameMonth(day, monthStart)) {
67
+ const yyyy = day.getFullYear();
68
+ const mm = String(day.getMonth() + 1).padStart(2, '0');
69
+ const dd = String(day.getDate()).padStart(2, '0');
70
+ const formattedDate = `${yyyy}-${mm}-${dd}`;
71
+
72
+ const event = {
73
+ target: {
74
+ name: name,
75
+ value: formattedDate,
76
+ type: 'date',
77
+ },
78
+ };
79
+ if (typeof onChange === 'function') {
80
+ onChange(event);
81
+ }
82
+ setIsOpen(false);
83
+ }
84
+ };
85
+
86
+ const handleSetToday = () => {
87
+ const today = new Date();
88
+ setCurrentDate(today);
89
+ handleDateClick(today);
90
+ };
91
+
92
+ const handleClear = () => {
93
+ const event = {
94
+ target: { name, value: '', type: 'date' },
95
+ };
96
+ if (typeof onChange === 'function') {
97
+ onChange(event);
98
+ }
99
+ setIsOpen(false);
100
+ };
101
+
102
+ const handleMonthChange = (e) => {
103
+ setCurrentDate(setMonth(currentDate, parseInt(e.target.value)));
104
+ };
105
+
106
+ const handleYearChange = (e) => {
107
+ setCurrentDate(setYear(currentDate, parseInt(e.target.value)));
108
+ };
109
+
110
+ const dayNames = ['L', 'M', 'X', 'J', 'V', 'S', 'D'];
111
+
112
+ const currentYear = new Date().getFullYear();
113
+ const years = Array.from({ length: 110 }, (_, i) => currentYear + 5 - i);
114
+ const months = [
115
+ 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
116
+ 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'
117
+ ];
118
+
119
+ return (
120
+ <div
121
+ className={styles.inputGroup}
122
+ onClick={(e) => e.stopPropagation()}
123
+ style={{
124
+ ...(selectedColor ? { '--cdp-selected': selectedColor } : {}),
125
+ ...(accentColor ? { '--cdp-accent': accentColor } : {}),
126
+ }}
127
+ >
128
+ <TextField
129
+ label={label}
130
+ value={selectedDate ? format(selectedDate, 'dd/MM/yyyy') : ''}
131
+ readOnly
132
+ placeholder="dd/mm/aaaa"
133
+ onClick={() => !disabled && setIsOpen(true)}
134
+ disabled={disabled}
135
+ required={required}
136
+ slotProps={{
137
+ input: {
138
+ endAdornment: (
139
+ <CalendarDays
140
+ size={16}
141
+ style={{ cursor: 'pointer', color: '#64748b' }}
142
+ onClick={() => !disabled && setIsOpen(true)}
143
+ />
144
+ )
145
+ }
146
+ }}
147
+ />
148
+
149
+ {isOpen && (
150
+ <div className={styles.modalBackdrop} onClick={() => { setIsOpen(false); setShowSelectors(false); }}>
151
+ <div className={styles.calendarModal} ref={modalRef} onClick={(e) => e.stopPropagation()}>
152
+
153
+ <div className={styles.header}>
154
+ <div className={styles.headerTitleContainer} onClick={() => setShowSelectors(!showSelectors)}>
155
+ <span className={styles.monthName}>
156
+ {format(currentDate, 'MMMM yyyy', { locale: es })}
157
+ </span>
158
+ <ChevronDown size={14} className={`${styles.dropdownChevron} ${showSelectors ? styles.chevronChevronOpen : ''}`} />
159
+ </div>
160
+
161
+ <div className={styles.navigation}>
162
+ {!showSelectors && (
163
+ <>
164
+ <button type="button" onClick={handlePrevMonth} className={styles.navButton}>
165
+ <ChevronLeft size={18} />
166
+ </button>
167
+ <button type="button" onClick={handleNextMonth} className={styles.navButton}>
168
+ <ChevronRight size={18} />
169
+ </button>
170
+ </>
171
+ )}
172
+ <button type="button" onClick={() => { setIsOpen(false); setShowSelectors(false); }} className={styles.closeModalBtn}>
173
+ <X size={18} />
174
+ </button>
175
+ </div>
176
+ </div>
177
+
178
+ {showSelectors ? (
179
+ <div className={styles.selectorsPanel}>
180
+ <div className={styles.selectorGroup}>
181
+ <label>Mes</label>
182
+ <select value={currentDate.getMonth()} onChange={handleMonthChange} className={styles.elegantSelect}>
183
+ {months.map((m, index) => (
184
+ <option key={m} value={index}>{m}</option>
185
+ ))}
186
+ </select>
187
+ </div>
188
+ <div className={styles.selectorGroup}>
189
+ <label>Año</label>
190
+ <select value={currentDate.getFullYear()} onChange={handleYearChange} className={styles.elegantSelect}>
191
+ {years.map(y => (
192
+ <option key={y} value={y}>{y}</option>
193
+ ))}
194
+ </select>
195
+ </div>
196
+ <button type="button" className={styles.applySelectorsBtn} onClick={() => setShowSelectors(false)}>
197
+ Confirmar Selección
198
+ </button>
199
+ </div>
200
+ ) : (
201
+ <>
202
+ <div className={styles.weekDaysGrid}>
203
+ {dayNames.map(day => (
204
+ <div key={day} className={styles.weekDayName}>{day}</div>
205
+ ))}
206
+ </div>
207
+
208
+ <div className={styles.daysGrid}>
209
+ {daysInterval.map((day, index) => {
210
+ const isCurrentMonth = isSameMonth(day, monthStart);
211
+ const isSelected = selectedDate && isSameDay(day, selectedDate);
212
+ const isToday = isSameDay(day, new Date());
213
+
214
+ let dayClassName = styles.dayCell;
215
+ if (!isCurrentMonth) dayClassName += ` ${styles.otherMonth}`;
216
+ if (isSelected) dayClassName += ` ${styles.selectedDay}`;
217
+ if (isToday && !isSelected) dayClassName += ` ${styles.todayDay}`;
218
+
219
+ return (
220
+ <div
221
+ key={index}
222
+ className={dayClassName}
223
+ onClick={() => isCurrentMonth && handleDateClick(day)}
224
+ >
225
+ {format(day, 'd')}
226
+ </div>
227
+ );
228
+ })}
229
+ </div>
230
+ </>
231
+ )}
232
+
233
+ <div className={styles.footer}>
234
+ <button type="button" className={styles.clearButton} onClick={handleClear}>
235
+ Borrar
236
+ </button>
237
+ <button type="button" className={styles.todayButton} onClick={handleSetToday}>
238
+ Hoy
239
+ </button>
240
+ </div>
241
+ </div>
242
+ </div>
243
+ )}
244
+ </div>
245
+ );
246
+ };
247
+
248
+ export default CustomDatePicker;