@soyfri/shared-library 2.0.0-beta.2 → 2.0.0-beta.4

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 (187) hide show
  1. package/.dockerignore +8 -0
  2. package/.github/workflows/publish.yml +107 -0
  3. package/.prettierrc +3 -0
  4. package/.storybook/main.ts +19 -0
  5. package/.storybook/preview.ts +14 -0
  6. package/.storybook/vitest.setup.ts +9 -0
  7. package/Dockerfile +37 -0
  8. package/build.js +102 -0
  9. package/chromatic.config.json +5 -0
  10. package/cleanDirectories.js +40 -0
  11. package/dist/README.md +243 -0
  12. package/dist/components/Icon/Icon.js +1 -1
  13. package/dist/components/Table/Table.js +1 -1
  14. package/dist/index.cjs +24 -0
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +7 -1
  17. package/dist/mui.d.ts +1 -0
  18. package/dist/package.json +197 -0
  19. package/package.json +4 -32
  20. package/rollup.config.cjs +87 -0
  21. package/src/components/ActionMenu/ActionMenu.stories.tsx +230 -0
  22. package/src/components/ActionMenu/ActionMenu.tsx +174 -0
  23. package/src/components/ActionMenu/index.ts +2 -0
  24. package/src/components/AppBar/AppBar.stories.tsx +272 -0
  25. package/src/components/AppBar/AppBar.sx.ts +32 -0
  26. package/src/components/AppBar/AppBar.tsx +123 -0
  27. package/src/components/AppBar/AppBarBrand.tsx +120 -0
  28. package/src/components/AppBar/AppBarContext.ts +25 -0
  29. package/src/components/AppBar/AppBarMenuToggle.tsx +90 -0
  30. package/src/components/AppBar/AppBarUserMenu.tsx +217 -0
  31. package/src/components/AppBar/index.ts +25 -0
  32. package/src/components/Autocomplete/Autocomplete.definitions.ts +477 -0
  33. package/src/components/Autocomplete/Autocomplete.helpers.ts +60 -0
  34. package/src/components/Autocomplete/Autocomplete.stories.tsx +748 -0
  35. package/src/components/Autocomplete/Autocomplete.sx.ts +30 -0
  36. package/src/components/Autocomplete/Autocomplete.tsx +361 -0
  37. package/src/components/Autocomplete/Autocomplete.types.ts +13 -0
  38. package/src/components/Autocomplete/_parts/AutocompleteChips.tsx +55 -0
  39. package/src/components/Autocomplete/_parts/AutocompleteLoader.tsx +17 -0
  40. package/src/components/Autocomplete/_parts/AutocompleteOption.tsx +31 -0
  41. package/src/components/Autocomplete/index.ts +12 -0
  42. package/src/components/Avatar/Avatar.definitions.ts +162 -0
  43. package/src/components/Avatar/Avatar.stories.tsx +258 -0
  44. package/src/components/Avatar/Avatar.tsx +206 -0
  45. package/src/components/Avatar/index.ts +1 -0
  46. package/src/components/Button/Button.definition.ts +97 -0
  47. package/src/components/Button/Button.stories.tsx +285 -0
  48. package/src/components/Button/Button.tsx +67 -0
  49. package/src/components/Button/index.ts +1 -0
  50. package/src/components/Card/Card.definition.ts +5 -0
  51. package/src/components/Card/Card.stories.tsx +221 -0
  52. package/src/components/Card/Card.sx.ts +104 -0
  53. package/src/components/Card/Card.tsx +200 -0
  54. package/src/components/Card/index.ts +9 -0
  55. package/src/components/Chip/Chip.definitions.ts +167 -0
  56. package/src/components/Chip/Chip.stories.tsx +265 -0
  57. package/src/components/Chip/Chip.tsx +61 -0
  58. package/src/components/Chip/index.ts +1 -0
  59. package/src/components/Column/Column.tsx +29 -0
  60. package/src/components/Column/index.ts +1 -0
  61. package/src/components/DatePicker/DatePicker.definitions.ts +228 -0
  62. package/src/components/DatePicker/DatePicker.helpers.ts +24 -0
  63. package/src/components/DatePicker/DatePicker.stories.tsx +309 -0
  64. package/src/components/DatePicker/DatePicker.sx.ts +33 -0
  65. package/src/components/DatePicker/DatePicker.tsx +189 -0
  66. package/src/components/DatePicker/DatePicker.types.ts +10 -0
  67. package/src/components/DatePicker/index.ts +9 -0
  68. package/src/components/DateRangePicker/DateRangePicker.definitions.ts +191 -0
  69. package/src/components/DateRangePicker/DateRangePicker.stories.tsx +252 -0
  70. package/src/components/DateRangePicker/DateRangePicker.tsx +56 -0
  71. package/src/components/DateRangePicker/index.ts +1 -0
  72. package/src/components/DateTimePicker/DateTimePicker.definitions.ts +256 -0
  73. package/src/components/DateTimePicker/DateTimePicker.helpers.ts +38 -0
  74. package/src/components/DateTimePicker/DateTimePicker.stories.tsx +418 -0
  75. package/src/components/DateTimePicker/DateTimePicker.sx.ts +30 -0
  76. package/src/components/DateTimePicker/DateTimePicker.tsx +225 -0
  77. package/src/components/DateTimePicker/DateTimePicker.types.ts +10 -0
  78. package/src/components/DateTimePicker/index.ts +9 -0
  79. package/src/components/Drawer/Drawer.stories.tsx +270 -0
  80. package/src/components/Drawer/Drawer.sx.ts +106 -0
  81. package/src/components/Drawer/Drawer.tsx +214 -0
  82. package/src/components/Drawer/DrawerContext.ts +26 -0
  83. package/src/components/Drawer/DrawerItem.tsx +110 -0
  84. package/src/components/Drawer/index.ts +10 -0
  85. package/src/components/Flyout/Flyout.stories.tsx +282 -0
  86. package/src/components/Flyout/Flyout.tsx +122 -0
  87. package/src/components/Flyout/index.ts +1 -0
  88. package/src/components/Gallery/Gallery.definition.tsx +37 -0
  89. package/src/components/Gallery/Gallery.stories.tsx +82 -0
  90. package/src/components/Gallery/Gallery.tsx +118 -0
  91. package/src/components/Gallery/GalleryLightbox.tsx +170 -0
  92. package/src/components/Gallery/GalleryMain.tsx +84 -0
  93. package/src/components/Gallery/GalleryThumbnails.tsx +106 -0
  94. package/src/components/Gallery/index.ts +1 -0
  95. package/src/components/Icon/Icon.stories.tsx +121 -0
  96. package/src/components/Icon/Icon.tsx +175 -0
  97. package/src/components/Icon/index.ts +2 -0
  98. package/src/components/Input/Input.definitions.ts +324 -0
  99. package/src/components/Input/Input.helpers.ts +49 -0
  100. package/src/components/Input/Input.stories.tsx +499 -0
  101. package/src/components/Input/Input.sx.ts +42 -0
  102. package/src/components/Input/Input.tsx +141 -0
  103. package/src/components/Input/Input.types.ts +10 -0
  104. package/src/components/Input/index.ts +9 -0
  105. package/src/components/InputGroup/InputGroup.definitions.ts +158 -0
  106. package/src/components/InputGroup/InputGroup.stories.tsx +267 -0
  107. package/src/components/InputGroup/InputGroup.tsx +179 -0
  108. package/src/components/InputGroup/index.ts +1 -0
  109. package/src/components/MenuButton/MenuButton.stories.tsx +197 -0
  110. package/src/components/MenuButton/MenuButton.tsx +100 -0
  111. package/src/components/MenuButton/index.ts +1 -0
  112. package/src/components/Modal/Modal.stories.tsx +721 -0
  113. package/src/components/Modal/Modal.tsx +355 -0
  114. package/src/components/Modal/ModalBody.tsx +16 -0
  115. package/src/components/Modal/ModalFooter.tsx +71 -0
  116. package/src/components/Modal/ModalHeader.tsx +18 -0
  117. package/src/components/Modal/index.ts +6 -0
  118. package/src/components/PageLoader/PageLoader.stories.tsx +217 -0
  119. package/src/components/PageLoader/PageLoader.tsx +96 -0
  120. package/src/components/PageLoader/index.ts +2 -0
  121. package/src/components/ScrollTopButton/ScrollTopButton.stories.tsx +158 -0
  122. package/src/components/ScrollTopButton/ScrollTopButton.tsx +135 -0
  123. package/src/components/ScrollTopButton/index.ts +8 -0
  124. package/src/components/ScrollTopButton/scrollToTop.ts +37 -0
  125. package/src/components/Select/Select.definitions.ts +602 -0
  126. package/src/components/Select/Select.helpers.ts +71 -0
  127. package/src/components/Select/Select.stories.tsx +687 -0
  128. package/src/components/Select/Select.sx.ts +14 -0
  129. package/src/components/Select/Select.tsx +429 -0
  130. package/src/components/Select/Select.types.ts +15 -0
  131. package/src/components/Select/_parts/SelectMenuItem.tsx +40 -0
  132. package/src/components/Select/_parts/SelectSearchHeader.tsx +51 -0
  133. package/src/components/Select/_parts/SelectValue.tsx +96 -0
  134. package/src/components/Select/index.ts +14 -0
  135. package/src/components/Stat/Stat.stories.tsx +85 -0
  136. package/src/components/Stat/Stat.tsx +117 -0
  137. package/src/components/Stat/index.ts +2 -0
  138. package/src/components/StatusMessage/StatusMessage.stories.tsx +130 -0
  139. package/src/components/StatusMessage/StatusMessage.tsx +162 -0
  140. package/src/components/StatusMessage/index.ts +2 -0
  141. package/src/components/Stepper/Step.tsx +21 -0
  142. package/src/components/Stepper/Stepper.definition.ts +75 -0
  143. package/src/components/Stepper/Stepper.stories.tsx +122 -0
  144. package/src/components/Stepper/Stepper.tsx +75 -0
  145. package/src/components/Stepper/index.ts +2 -0
  146. package/src/components/Table/EmptyTable.png +0 -0
  147. package/src/components/Table/Table.definition.ts +580 -0
  148. package/src/components/Table/Table.stories.tsx +853 -0
  149. package/src/components/Table/Table.tsx +495 -0
  150. package/src/components/Table/data.ts +134 -0
  151. package/src/components/Table/exportsUtils.ts +195 -0
  152. package/src/components/Table/index.ts +3 -0
  153. package/src/components/Table/types.ts +34 -0
  154. package/src/components/Tabs/Tab.definition.ts +53 -0
  155. package/src/components/Tabs/Tab.tsx +19 -0
  156. package/src/components/Tabs/Tabs.stories.tsx +118 -0
  157. package/src/components/Tabs/Tabs.tsx +99 -0
  158. package/src/components/Tabs/_tabUtils.tsx +4 -0
  159. package/src/components/Tabs/index.ts +2 -0
  160. package/src/components/Timeline/Timeline.definition.ts +43 -0
  161. package/src/components/Timeline/Timeline.stories.tsx +108 -0
  162. package/src/components/Timeline/Timeline.tsx +49 -0
  163. package/src/components/Timeline/TimelineItem.tsx +31 -0
  164. package/src/components/Timeline/index.ts +2 -0
  165. package/src/components/Tooltip/Tooltip.stories.tsx +129 -0
  166. package/src/components/Tooltip/Tooltip.tsx +58 -0
  167. package/src/components/Tooltip/index.ts +1 -0
  168. package/src/components/_shared/formField.sx.ts +118 -0
  169. package/src/components/_shared/resolvePreset.ts +35 -0
  170. package/src/hooks/ClipBoard/ClipBoard.stories.tsx +168 -0
  171. package/src/hooks/ClipBoard/ClipBoard.tsx +131 -0
  172. package/src/hooks/ClipBoard/ClipboardUnifiedDemo.tsx +111 -0
  173. package/src/hooks/ClipBoard/index.ts +1 -0
  174. package/src/hooks/Wizard/Wizard.stories.tsx +301 -0
  175. package/src/hooks/Wizard/WizardContext.tsx +166 -0
  176. package/src/hooks/Wizard/index.ts +6 -0
  177. package/src/hooks/Wizard/useWizard.ts +13 -0
  178. package/src/index.ts +17 -0
  179. package/src/mui.ts +54 -0
  180. package/src/styles.css +3 -0
  181. package/src/theme/componentStyles.ts +47 -0
  182. package/src/theme/tokens.ts +43 -0
  183. package/tailwind.config.js +10 -0
  184. package/tsconfig.json +48 -0
  185. package/tsup.config.js +41 -0
  186. package/vite.config.js +132 -0
  187. package/vitest.config.ts +35 -0
@@ -0,0 +1,418 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import React, { useState, useMemo } from 'react';
3
+ import {
4
+ Box,
5
+ Typography,
6
+ } from '@mui/material';
7
+
8
+ // Importaciones de @mui/x-date-pickers y dayjs
9
+ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
10
+ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
11
+ import { DateTimePicker as MuiDateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
12
+ import { DateValidationError } from '@mui/x-date-pickers/models';
13
+ import dayjs, { Dayjs } from 'dayjs';
14
+ import { renderMultiSectionDigitalClockTimeView } from '@mui/x-date-pickers/timeViewRenderers';
15
+
16
+ // Importar las definiciones de las historias
17
+ import {
18
+ BasicDateTimePickerDefinition,
19
+ DateTimePickerWithMinMaxDefinition,
20
+ DateTimePickerDisabledDefinition,
21
+ DateTimePickerReadOnlyDefinition,
22
+ DateTimePickerWithInitialNullDefinition,
23
+ DateTimePickerSmallSizeDefinition,
24
+ DateTimePickerWithCustomButtonTextDefinition,
25
+ DateTimePickerWithButtonsDefinition,
26
+ DateTimePickerWithCustomInputFormatDefinition,
27
+ DateTimePickerEmptyWithMaskDefinition,
28
+ } from './DateTimePicker.definitions'; // Asegúrate de que esta ruta sea correcta
29
+ import { DateTimePicker } from './DateTimePicker';
30
+
31
+
32
+ const meta: Meta<typeof DateTimePicker> = {
33
+ title: 'Components/DateTimePicker',
34
+ component: DateTimePicker,
35
+ tags: ['autodocs'],
36
+ parameters: {
37
+ layout: 'centered',
38
+ docs: {
39
+ description: {
40
+ component: 'Un componente `DateTimePicker` personalizado de Material UI que permite seleccionar tanto la fecha como la hora.',
41
+ },
42
+ },
43
+ },
44
+ argTypes: {
45
+ label: { control: 'text', description: 'Etiqueta para el selector de fecha y hora.' },
46
+ selectedDateTime: { control: 'object', description: 'La fecha y hora actualmente seleccionada.', type: { name: 'object', required: false, value: {} } },
47
+ onDateTimeChange: { action: 'dateTimeChanged', description: 'Callback que se dispara cuando la fecha y hora cambian.' },
48
+ minDateTime: { control: 'object', description: 'La fecha y hora mínima permitida.' },
49
+ maxDateTime: { control: 'object', description: 'La fecha y hora máxima permitida.' },
50
+ disabled: { control: 'boolean', description: 'Si es verdadero, el selector estará deshabilitado.' },
51
+ readOnly: { control: 'boolean', description: 'Si es verdadero, el selector estará en modo de solo lectura.' },
52
+ inputFormat: { control: 'text', description: 'Formato de la fecha y hora en el campo de entrada (ej. "DD/MM/YYYY HH:mm").' }, // Nuevo argType
53
+ slotProps: { control: 'object', description: 'Propiedades pasadas a los slots internos del DateTimePicker (e.g., `textField`, `actionBar`).' },
54
+ clearButtonText: { control: 'text', description: 'Texto personalizado para el botón "Limpiar".', if: { arg: 'slotProps.actionBar.actions', eq: 'clear' } },
55
+ cancelButtonText: { control: 'text', description: 'Texto personalizado para el botón "Cancelar".', if: { arg: 'slotProps.actionBar.actions', eq: 'cancel' } },
56
+ acceptButtonText: { control: 'text', description: 'Texto personalizado para el botón "Aceptar".', if: { arg: 'slotProps.actionBar.actions', eq: 'accept' } },
57
+ },
58
+ };
59
+
60
+ export default meta;
61
+ type Story = StoryObj<typeof DateTimePicker>;
62
+
63
+ // =============================================================================
64
+ // Historias
65
+ // =============================================================================
66
+
67
+ export const BasicDateTimePicker: Story = {
68
+ render: () => {
69
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs());
70
+ return (
71
+ <Box sx={{ width: 300 }}>
72
+ <DateTimePicker
73
+ label="Seleccionar Fecha y Hora"
74
+ selectedDateTime={selectedDateTime}
75
+ onDateTimeChange={setSelectedDateTime}
76
+ />
77
+ <Typography sx={{ mt: 2 }}>
78
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
79
+ </Typography>
80
+ </Box>
81
+ );
82
+ },
83
+ parameters: {
84
+ docs: {
85
+ description: {
86
+ story: "Un `DateTimePicker` básico con selección de fecha y hora actual."
87
+ },
88
+ source: { code: BasicDateTimePickerDefinition.trim() }
89
+ }
90
+ }
91
+ };
92
+
93
+ export const DateTimePickerWithMinMax: Story = {
94
+ render: () => {
95
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs('2023-06-15T10:00'));
96
+ const minDateTime = dayjs('2023-06-01T09:00');
97
+ const maxDateTime = dayjs('2023-06-30T17:00');
98
+ return (
99
+ <Box sx={{ width: 300 }}>
100
+ <DateTimePicker
101
+ label="Fecha y Hora en Junio (Rango)"
102
+ selectedDateTime={selectedDateTime}
103
+ onDateTimeChange={setSelectedDateTime}
104
+ minDateTime={minDateTime}
105
+ maxDateTime={maxDateTime}
106
+ />
107
+ <Typography sx={{ mt: 2 }}>
108
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
109
+ </Typography>
110
+ <Typography variant="caption" color="text.secondary">
111
+ (Rango: ${minDateTime.format('YYYY-MM-DD HH:mm')} a ${maxDateTime.format('YYYY-MM-DD HH:mm')})
112
+ </Typography>
113
+ </Box>
114
+ );
115
+ },
116
+ parameters: {
117
+ docs: {
118
+ description: {
119
+ story: "Muestra un `DateTimePicker` con límites de fecha y hora mínimos y máximos."
120
+ },
121
+ source: { code: DateTimePickerWithMinMaxDefinition.trim() }
122
+ }
123
+ }
124
+ };
125
+
126
+ export const DateTimePickerDisabled: Story = {
127
+ render: () => {
128
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs());
129
+ return (
130
+ <Box sx={{ width: 300 }}>
131
+ <DateTimePicker
132
+ label="Fecha y Hora (Deshabilitado)"
133
+ selectedDateTime={selectedDateTime}
134
+ onDateTimeChange={setSelectedDateTime}
135
+ disabled
136
+ />
137
+ <Typography sx={{ mt: 2 }}>
138
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
139
+ </Typography>
140
+ </Box>
141
+ );
142
+ },
143
+ parameters: {
144
+ docs: {
145
+ description: {
146
+ story: "Demuestra un `DateTimePicker` en estado deshabilitado."
147
+ },
148
+ source: { code: DateTimePickerDisabledDefinition.trim() }
149
+ }
150
+ }
151
+ };
152
+
153
+ export const DateTimePickerReadOnly: Story = {
154
+ render: () => {
155
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs('2024-07-24T14:30'));
156
+ return (
157
+ <Box sx={{ width: 300 }}>
158
+ <DateTimePicker
159
+ label="Fecha y Hora (Solo Lectura)"
160
+ selectedDateTime={selectedDateTime}
161
+ onDateTimeChange={() => {}} // No permite cambios
162
+ readOnly
163
+ />
164
+ <Typography sx={{ mt: 2 }}>
165
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
166
+ </Typography>
167
+ </Box>
168
+ );
169
+ },
170
+ parameters: {
171
+ docs: {
172
+ description: {
173
+ story: "Muestra el `DateTimePicker` en modo de solo lectura."
174
+ },
175
+ source: { code: DateTimePickerReadOnlyDefinition.trim() }
176
+ }
177
+ }
178
+ };
179
+
180
+ export const DateTimePickerWithInitialNull: Story = {
181
+ render: () => {
182
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(null);
183
+ return (
184
+ <Box sx={{ width: 300 }}>
185
+ <DateTimePicker
186
+ label="Fecha y Hora (Sin Selección Inicial)"
187
+ selectedDateTime={selectedDateTime}
188
+ onDateTimeChange={setSelectedDateTime}
189
+ />
190
+ <Typography sx={{ mt: 2 }}>
191
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
192
+ </Typography>
193
+ </Box>
194
+ );
195
+ },
196
+ parameters: {
197
+ docs: {
198
+ description: {
199
+ story: "Muestra un `DateTimePicker` sin fecha y hora seleccionadas inicialmente."
200
+ },
201
+ source: { code: DateTimePickerWithInitialNullDefinition.trim() }
202
+ }
203
+ }
204
+ };
205
+
206
+ export const DateTimePickerEmptyWithMask: Story = {
207
+ render: () => {
208
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(null);
209
+ return (
210
+ <Box sx={{ width: 300 }}>
211
+ <DateTimePicker
212
+ label="Fecha y Hora"
213
+ selectedDateTime={selectedDateTime}
214
+ onDateTimeChange={setSelectedDateTime}
215
+ inputFormat="DD/MM/YY HH:mm"
216
+ />
217
+ <Typography sx={{ mt: 2 }} variant="caption" color="text.secondary">
218
+ Al estar vacío, el campo muestra la máscara del formato (DD/MM/AA HH:MM).
219
+ </Typography>
220
+ </Box>
221
+ );
222
+ },
223
+ parameters: {
224
+ docs: {
225
+ description: {
226
+ story:
227
+ "DateTimePicker vacío. Al no haber valor seleccionado, cada sección del campo muestra su placeholder según el `inputFormat` (por ejemplo `DD/MM/AA HH:MM`), funcionando como máscara visual."
228
+ },
229
+ source: { code: DateTimePickerEmptyWithMaskDefinition.trim() }
230
+ }
231
+ }
232
+ };
233
+
234
+ export const DateTimePickerSmallSize: Story = {
235
+ render: () => {
236
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs());
237
+ return (
238
+ <Box sx={{ width: 250 }}>
239
+ <DateTimePicker
240
+ label="Fecha y Hora (Pequeño)"
241
+ selectedDateTime={selectedDateTime}
242
+ onDateTimeChange={setSelectedDateTime}
243
+ slotProps={{ textField: { size: 'small' } }}
244
+ />
245
+ <Typography sx={{ mt: 2 }}>
246
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
247
+ </Typography>
248
+ </Box>
249
+ );
250
+ },
251
+ parameters: {
252
+ docs: {
253
+ description: {
254
+ story: "Demuestra cómo aplicar un tamaño más pequeño al `DateTimePicker`."
255
+ },
256
+ source: { code: DateTimePickerSmallSizeDefinition.trim() }
257
+ }
258
+ }
259
+ };
260
+
261
+ export const DateTimePickerWithButtons: Story = {
262
+ render: () => {
263
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs());
264
+ return (
265
+ <Box sx={{ width: 300 }}>
266
+ <DateTimePicker
267
+ label="Fecha y Hora (Con Botones por Defecto)"
268
+ selectedDateTime={selectedDateTime}
269
+ onDateTimeChange={setSelectedDateTime}
270
+ slotProps={{
271
+ actionBar: {
272
+ actions: ['clear', 'cancel', 'accept'],
273
+ },
274
+ }}
275
+ />
276
+ <Typography sx={{ mt: 2 }}>
277
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
278
+ </Typography>
279
+ </Box>
280
+ );
281
+ },
282
+ parameters: {
283
+ docs: {
284
+ description: {
285
+ story: "Muestra el `DateTimePicker` con botones de acción ('Limpiar', 'Cancelar', 'Aceptar') en el pie del selector."
286
+ },
287
+ source: { code: DateTimePickerWithButtonsDefinition.trim() }
288
+ }
289
+ }
290
+ };
291
+
292
+ export const DateTimePickerWithCustomButtonText: Story = {
293
+ render: () => {
294
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs());
295
+ return (
296
+ <Box sx={{ width: 300 }}>
297
+ <DateTimePicker
298
+ label="Fecha y Hora (Botones Personalizados)"
299
+ selectedDateTime={selectedDateTime}
300
+ onDateTimeChange={setSelectedDateTime}
301
+ clearButtonText="Limpiar Todo"
302
+ cancelButtonText="Descartar"
303
+ acceptButtonText="Confirmar Selección"
304
+ slotProps={{
305
+ actionBar: {
306
+ actions: ['clear', 'cancel', 'accept'],
307
+ },
308
+ }}
309
+ />
310
+ <Typography sx={{ mt: 2 }}>
311
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
312
+ </Typography>
313
+ </Box>
314
+ );
315
+ },
316
+ parameters: {
317
+ docs: {
318
+ description: {
319
+ story: "Demuestra cómo personalizar el texto de los botones de acción ('Limpiar', 'Cancelar', 'Aceptar') en el `DateTimePicker`."
320
+ },
321
+ source: { code: DateTimePickerWithCustomButtonTextDefinition.trim() }
322
+ }
323
+ }
324
+ };
325
+
326
+ export const DateTimePickerWithCustomInputFormat: Story = {
327
+ render: () => {
328
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs());
329
+ return (
330
+ <Box sx={{ width: 300 }}>
331
+ <DateTimePicker
332
+ label="Fecha y Hora (Formato dd/MM/YYYY HH:mm)"
333
+ selectedDateTime={selectedDateTime}
334
+ onDateTimeChange={setSelectedDateTime}
335
+ inputFormat="DD/MM/YYYY HH:mm" // Custom date format
336
+ />
337
+ <Typography sx={{ mt: 2 }}>
338
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
339
+ </Typography>
340
+ </Box>
341
+ );
342
+ },
343
+ parameters: {
344
+ docs: {
345
+ description: {
346
+ story: "Muestra el `DateTimePicker` con un formato de fecha y hora personalizado en el campo de entrada, por ejemplo `DD/MM/YYYY HH:mm`."
347
+ },
348
+ source: { code: DateTimePickerWithCustomInputFormatDefinition.trim() }
349
+ }
350
+ }
351
+ };
352
+
353
+ export const DateTimePickerWithAllMinutes: Story = {
354
+ render: () => {
355
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs('2023-06-15T10:00'));
356
+
357
+ return (
358
+ <Box sx={{ width: 300 }}>
359
+ <DateTimePicker
360
+ label="Fecha y Hora en Junio (Rango)"
361
+ selectedDateTime={selectedDateTime}
362
+ onDateTimeChange={setSelectedDateTime}
363
+ viewRenderers={{
364
+ hours: renderMultiSectionDigitalClockTimeView,
365
+ minutes: renderMultiSectionDigitalClockTimeView,
366
+ }}
367
+ minutesStep={1}
368
+ timeSteps={{ minutes: 1 }} // <-- clave en varias versiones
369
+ />
370
+ <Typography sx={{ mt: 2 }}>
371
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
372
+ </Typography>
373
+ </Box>
374
+ );
375
+ },
376
+ parameters: {
377
+ docs: {
378
+ description: {
379
+ story: "Muestra un `DateTimePicker` con todos los minutos habiles."
380
+ },
381
+ source: { code: DateTimePickerWithMinMaxDefinition.trim() }
382
+ }
383
+ }
384
+ };
385
+
386
+ export const DateTimePicker24h: Story = {
387
+ render: () => {
388
+ const [selectedDateTime, setSelectedDateTime] = useState<Dayjs | null>(dayjs('2023-06-15T10:00'));
389
+
390
+ return (
391
+ <Box sx={{ width: 300 }}>
392
+ <DateTimePicker
393
+ label="Fecha y Hora en Junio (Rango)"
394
+ selectedDateTime={selectedDateTime}
395
+ onDateTimeChange={setSelectedDateTime}
396
+ viewRenderers={{
397
+ hours: renderMultiSectionDigitalClockTimeView,
398
+ minutes: renderMultiSectionDigitalClockTimeView,
399
+ }}
400
+ minutesStep={1}
401
+ timeSteps={{ minutes: 1 }} // <-- clave en varias versiones
402
+ ampm={true}
403
+ />
404
+ <Typography sx={{ mt: 2 }}>
405
+ Seleccionado: {selectedDateTime ? selectedDateTime.format('YYYY-MM-DD HH:mm') : 'Ninguna'}
406
+ </Typography>
407
+ </Box>
408
+ );
409
+ },
410
+ parameters: {
411
+ docs: {
412
+ description: {
413
+ story: "Muestra un `DateTimePicker` con formato de 24 horas."
414
+ },
415
+ source: { code: DateTimePickerWithMinMaxDefinition.trim() }
416
+ }
417
+ }
418
+ };
@@ -0,0 +1,30 @@
1
+ import type { SxProps, Theme } from '@mui/material';
2
+
3
+ import { buildFormFieldSx } from '../_shared/formField.sx';
4
+ import { FIELD_INPUT_PADDING_Y } from '../../theme/tokens';
5
+ import type { LabelPosition } from './DateTimePicker';
6
+
7
+ /**
8
+ * Builder de sx para el DateTimePicker. Mismo patrón que DatePicker.
9
+ * Usa `includePickersApi: true` para soportar la API nueva de MUI X v8.
10
+ */
11
+ export const buildDateTimePickerSx = (
12
+ borderRadius: number | string,
13
+ labelPosition: LabelPosition,
14
+ ): SxProps<Theme> =>
15
+ buildFormFieldSx({
16
+ borderRadius,
17
+ labelPosition,
18
+ includePickersApi: true,
19
+ extraOutsideSx: {
20
+ '& .MuiInputBase-input': {
21
+ paddingTop: FIELD_INPUT_PADDING_Y,
22
+ paddingBottom: FIELD_INPUT_PADDING_Y,
23
+ },
24
+
25
+ '& .MuiPickersInputBase-sectionsContainer': {
26
+ paddingTop: FIELD_INPUT_PADDING_Y,
27
+ paddingBottom: FIELD_INPUT_PADDING_Y,
28
+ },
29
+ },
30
+ });
@@ -0,0 +1,225 @@
1
+ import React, { useMemo } from 'react';
2
+ import type { SxProps, Theme } from '@mui/material';
3
+ import { useTheme } from '@mui/material/styles';
4
+ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
5
+ import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
6
+ import {
7
+ DateTimePicker as MuiDateTimePicker,
8
+ type DateTimePickerProps as MuiDateTimePickerProps,
9
+ } from '@mui/x-date-pickers/DateTimePicker';
10
+ import { DateValidationError } from '@mui/x-date-pickers/models';
11
+ import { Dayjs } from 'dayjs';
12
+ import { Controller, type Control, type RegisterOptions } from 'react-hook-form';
13
+
14
+ import { buildDateTimePickerSx } from './DateTimePicker.sx';
15
+ import {
16
+ buildLocaleText,
17
+ getDateTimeValidationMessage,
18
+ } from './DateTimePicker.helpers';
19
+ import { resolvePreset } from '../_shared/resolvePreset';
20
+
21
+ // ── Tipos de dominio ─────────────────────────────────────────────────────
22
+ export type LabelPosition = 'outside' | 'floating';
23
+ export type DateTimePickerSize = 'small' | 'medium';
24
+
25
+ // ── Props base ───────────────────────────────────────────────────────────
26
+ export interface BaseDateTimePickerProps
27
+ extends Omit<MuiDateTimePickerProps, 'value' | 'onChange' | 'slotProps' | 'format'> {
28
+ label?: string;
29
+ minDateTime?: Dayjs;
30
+ maxDateTime?: Dayjs;
31
+ disabled?: boolean;
32
+ readOnly?: boolean;
33
+ /** Formato de la fecha/hora. Default: 'DD/MM/YYYY HH:mm'. */
34
+ inputFormat?: string;
35
+ /** Border radius del input. Default: 10. */
36
+ borderRadius?: number | string;
37
+ /** "outside" (default) o "floating". */
38
+ labelPosition?: LabelPosition;
39
+ /** Tamaño del TextField. Default: 'small'. */
40
+ size?: DateTimePickerSize;
41
+ helperText?: string;
42
+ error?: boolean;
43
+ sx?: SxProps<Theme>;
44
+ className?: string;
45
+ /**
46
+ * Nombre del preset de estilo registrado en `theme.styles.DateTimePicker`.
47
+ * - `"default"` (o ausente) = estilo built-in del paquete.
48
+ * - Cualquier otro string = mergea el preset encima del estilo built-in.
49
+ */
50
+ preset?: string;
51
+ /** Locale del adaptador dayjs. */
52
+ adapterLocale?: string;
53
+ /** Textos de los botones del popover. */
54
+ clearButtonText?: string;
55
+ cancelButtonText?: string;
56
+ acceptButtonText?: string;
57
+ minutesStep?: number;
58
+ minTime?: Dayjs;
59
+ customClass?: string;
60
+ viewRenderers?: any;
61
+ timeSteps?: any;
62
+ /** Si es true usa formato 12h, false = 24h. Default: false. */
63
+ ampm?: boolean;
64
+ textFieldProps?: Record<string, any>;
65
+ /** Passthrough completo a slotProps del MuiDateTimePicker. */
66
+ slotProps?: MuiDateTimePickerProps['slotProps'];
67
+ }
68
+
69
+ // ── Variantes discriminadas (RHF vs controlado) ──────────────────────────
70
+ export interface RHFDateTimePickerProps extends BaseDateTimePickerProps {
71
+ name: string;
72
+ control: Control<any>;
73
+ validation?: RegisterOptions;
74
+ selectedDateTime?: never;
75
+ onDateTimeChange?: never;
76
+ }
77
+
78
+ export interface ControlledDateTimePickerProps extends BaseDateTimePickerProps {
79
+ name?: string;
80
+ control?: never;
81
+ validation?: never;
82
+ selectedDateTime: Dayjs | null;
83
+ onDateTimeChange: (dateTime: Dayjs | null) => void;
84
+ }
85
+
86
+ // ── API pública final ────────────────────────────────────────────────────
87
+ export type DateTimePickerProps =
88
+ | RHFDateTimePickerProps
89
+ | ControlledDateTimePickerProps;
90
+
91
+ export const DateTimePicker: React.FC<DateTimePickerProps> = (props) => {
92
+ const {
93
+ label,
94
+ minDateTime,
95
+ maxDateTime,
96
+ disabled,
97
+ readOnly,
98
+ inputFormat,
99
+ borderRadius = 10,
100
+ labelPosition = 'outside',
101
+ size = 'small',
102
+ helperText,
103
+ error: errorProp,
104
+ sx,
105
+ className,
106
+ preset,
107
+ adapterLocale,
108
+ clearButtonText,
109
+ cancelButtonText,
110
+ acceptButtonText,
111
+ minutesStep,
112
+ minTime,
113
+ customClass,
114
+ viewRenderers,
115
+ timeSteps,
116
+ ampm = false,
117
+ textFieldProps,
118
+ slotProps: slotPropsProp,
119
+ ...rest
120
+ } = props as ControlledDateTimePickerProps & {
121
+ control?: Control<any>;
122
+ validation?: RegisterOptions;
123
+ };
124
+
125
+ const [validationError, setValidationError] = React.useState<DateValidationError | null>(null);
126
+
127
+ const validationErrorMessage = useMemo(
128
+ () => getDateTimeValidationMessage(validationError),
129
+ [validationError],
130
+ );
131
+
132
+ const customLocaleText = useMemo(
133
+ () => buildLocaleText(clearButtonText, cancelButtonText, acceptButtonText),
134
+ [clearButtonText, cancelButtonText, acceptButtonText],
135
+ );
136
+
137
+ const theme = useTheme();
138
+ const presetSx = resolvePreset('DateTimePicker', preset, theme);
139
+
140
+ const mergedSx = [
141
+ buildDateTimePickerSx(borderRadius, labelPosition),
142
+ ...(presetSx ? [presetSx] : []),
143
+ ...(Array.isArray(sx) ? sx : [sx]),
144
+ ];
145
+
146
+ const renderPicker = (
147
+ value: Dayjs | null,
148
+ onChange: (date: Dayjs | null) => void,
149
+ onBlur?: () => void,
150
+ inputRef?: React.Ref<any>,
151
+ rhfError?: boolean,
152
+ rhfHelperText?: string,
153
+ ) => {
154
+ const finalError = rhfError || !!validationErrorMessage || !!errorProp;
155
+ const finalHelperText = rhfHelperText || validationErrorMessage || helperText;
156
+
157
+ return (
158
+ <LocalizationProvider
159
+ dateAdapter={AdapterDayjs}
160
+ {...(adapterLocale ? { adapterLocale } : {})}
161
+ >
162
+ <MuiDateTimePicker
163
+ className={customClass || className}
164
+ label={label}
165
+ value={value}
166
+ onChange={onChange}
167
+ onError={setValidationError}
168
+ minDateTime={minDateTime}
169
+ maxDateTime={maxDateTime}
170
+ minutesStep={minutesStep}
171
+ disabled={disabled}
172
+ readOnly={readOnly}
173
+ minTime={minTime}
174
+ format={inputFormat ?? 'DD/MM/YYYY HH:mm'}
175
+ viewRenderers={viewRenderers}
176
+ timeSteps={timeSteps}
177
+ ampm={ampm}
178
+ sx={mergedSx}
179
+ slotProps={{
180
+ ...slotPropsProp,
181
+ textField: {
182
+ fullWidth: true,
183
+ size,
184
+ variant: 'outlined',
185
+ onBlur,
186
+ inputRef,
187
+ error: !!finalError,
188
+ helperText: finalHelperText,
189
+ ...(slotPropsProp?.textField as Record<string, any> | undefined),
190
+ ...textFieldProps,
191
+ } as any,
192
+ }}
193
+ localeText={customLocaleText}
194
+ {...(rest as any)}
195
+ />
196
+ </LocalizationProvider>
197
+ );
198
+ };
199
+
200
+ if ('control' in props && props.control) {
201
+ const { name, control, validation } = props as RHFDateTimePickerProps;
202
+ return (
203
+ <Controller
204
+ name={name}
205
+ control={control}
206
+ rules={validation}
207
+ render={({ field, fieldState: { error: fieldError } }) =>
208
+ renderPicker(
209
+ field.value ?? null,
210
+ field.onChange,
211
+ field.onBlur,
212
+ field.ref,
213
+ !!fieldError,
214
+ fieldError?.message,
215
+ )
216
+ }
217
+ />
218
+ );
219
+ }
220
+
221
+ const { selectedDateTime, onDateTimeChange } = props as ControlledDateTimePickerProps;
222
+ return renderPicker(selectedDateTime, onDateTimeChange);
223
+ };
224
+
225
+ export default DateTimePicker;
@@ -0,0 +1,10 @@
1
+ // Re-export barrel para compatibilidad con imports antiguos.
2
+ // Los tipos ahora viven dentro de DateTimePicker.tsx.
3
+ export type {
4
+ LabelPosition,
5
+ DateTimePickerSize,
6
+ BaseDateTimePickerProps,
7
+ RHFDateTimePickerProps,
8
+ ControlledDateTimePickerProps,
9
+ DateTimePickerProps,
10
+ } from './DateTimePicker';
@@ -0,0 +1,9 @@
1
+ export { DateTimePicker, default } from './DateTimePicker';
2
+ export type {
3
+ DateTimePickerProps,
4
+ BaseDateTimePickerProps,
5
+ RHFDateTimePickerProps,
6
+ ControlledDateTimePickerProps,
7
+ LabelPosition,
8
+ DateTimePickerSize,
9
+ } from './DateTimePicker.types';