@soyfri/shared-library 1.5.0 → 2.0.0-beta.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 (283) hide show
  1. package/dist/components/ActionMenu/ActionMenu.cjs +107 -0
  2. package/dist/components/ActionMenu/ActionMenu.cjs.map +1 -0
  3. package/dist/components/ActionMenu/ActionMenu.d.ts +60 -0
  4. package/dist/components/ActionMenu/ActionMenu.js +107 -0
  5. package/dist/components/ActionMenu/ActionMenu.js.map +1 -0
  6. package/dist/components/ActionMenu/index.d.ts +2 -0
  7. package/dist/components/ActionMenu.d.ts +6 -0
  8. package/dist/components/AppBar/AppBar.cjs +346 -0
  9. package/dist/components/AppBar/AppBar.cjs.map +1 -0
  10. package/dist/components/AppBar/AppBar.d.ts +55 -0
  11. package/dist/components/AppBar/AppBar.js +346 -0
  12. package/dist/components/AppBar/AppBar.js.map +1 -0
  13. package/dist/components/AppBar/AppBar.sx.d.ts +12 -0
  14. package/dist/components/AppBar/AppBarBrand.d.ts +31 -0
  15. package/dist/components/AppBar/AppBarContext.d.ts +18 -0
  16. package/dist/components/AppBar/AppBarMenuToggle.d.ts +39 -0
  17. package/dist/components/AppBar/AppBarUserMenu.d.ts +65 -0
  18. package/dist/components/AppBar/index.d.ts +12 -0
  19. package/dist/components/AppBar.d.ts +6 -0
  20. package/dist/components/Autocomplete/Autocomplete.cjs +259 -54
  21. package/dist/components/Autocomplete/Autocomplete.cjs.map +1 -1
  22. package/dist/components/Autocomplete/Autocomplete.d.ts +64 -9
  23. package/dist/components/Autocomplete/Autocomplete.definitions.d.ts +6 -0
  24. package/dist/components/Autocomplete/Autocomplete.helpers.d.ts +18 -0
  25. package/dist/components/Autocomplete/Autocomplete.js +261 -56
  26. package/dist/components/Autocomplete/Autocomplete.js.map +1 -1
  27. package/dist/components/Autocomplete/Autocomplete.sx.d.ts +7 -0
  28. package/dist/components/Autocomplete/Autocomplete.types.d.ts +1 -0
  29. package/dist/components/Autocomplete/_parts/AutocompleteChips.d.ts +19 -0
  30. package/dist/components/Autocomplete/_parts/AutocompleteLoader.d.ts +9 -0
  31. package/dist/components/Autocomplete/_parts/AutocompleteOption.d.ts +19 -0
  32. package/dist/components/Autocomplete/index.d.ts +2 -1
  33. package/dist/components/Autocomplete.d.ts +4 -0
  34. package/dist/components/Avatar/Avatar.cjs +116 -79
  35. package/dist/components/Avatar/Avatar.cjs.map +1 -1
  36. package/dist/components/Avatar/Avatar.d.ts +16 -2
  37. package/dist/components/Avatar/Avatar.definitions.d.ts +11 -0
  38. package/dist/components/Avatar/Avatar.js +117 -80
  39. package/dist/components/Avatar/Avatar.js.map +1 -1
  40. package/dist/components/Card/Card.cjs +168 -9
  41. package/dist/components/Card/Card.cjs.map +1 -1
  42. package/dist/components/Card/Card.d.ts +78 -8
  43. package/dist/components/Card/Card.js +170 -11
  44. package/dist/components/Card/Card.js.map +1 -1
  45. package/dist/components/Card/Card.sx.d.ts +17 -0
  46. package/dist/components/Card/index.d.ts +4 -1
  47. package/dist/components/Card.d.ts +4 -0
  48. package/dist/components/DatePicker/DatePicker.cjs +201 -3
  49. package/dist/components/DatePicker/DatePicker.cjs.map +1 -1
  50. package/dist/components/DatePicker/DatePicker.d.ts +47 -9
  51. package/dist/components/DatePicker/DatePicker.definitions.d.ts +1 -0
  52. package/dist/components/DatePicker/DatePicker.helpers.d.ts +7 -0
  53. package/dist/components/DatePicker/DatePicker.js +200 -2
  54. package/dist/components/DatePicker/DatePicker.js.map +1 -1
  55. package/dist/components/DatePicker/DatePicker.sx.d.ts +9 -0
  56. package/dist/components/DatePicker/DatePicker.types.d.ts +1 -0
  57. package/dist/components/DatePicker/index.d.ts +2 -1
  58. package/dist/components/DatePicker.d.ts +4 -0
  59. package/dist/components/DateTimePicker/DateTimePicker.cjs +152 -138
  60. package/dist/components/DateTimePicker/DateTimePicker.cjs.map +1 -1
  61. package/dist/components/DateTimePicker/DateTimePicker.d.ts +46 -9
  62. package/dist/components/DateTimePicker/DateTimePicker.definitions.d.ts +1 -0
  63. package/dist/components/DateTimePicker/DateTimePicker.helpers.d.ts +11 -0
  64. package/dist/components/DateTimePicker/DateTimePicker.js +152 -138
  65. package/dist/components/DateTimePicker/DateTimePicker.js.map +1 -1
  66. package/dist/components/DateTimePicker/DateTimePicker.sx.d.ts +7 -0
  67. package/dist/components/DateTimePicker/DateTimePicker.types.d.ts +1 -0
  68. package/dist/components/DateTimePicker/index.d.ts +2 -1
  69. package/dist/components/DateTimePicker.d.ts +4 -0
  70. package/dist/components/Drawer/Drawer.cjs +271 -0
  71. package/dist/components/Drawer/Drawer.cjs.map +1 -0
  72. package/dist/components/Drawer/Drawer.d.ts +51 -0
  73. package/dist/components/Drawer/Drawer.js +271 -0
  74. package/dist/components/Drawer/Drawer.js.map +1 -0
  75. package/dist/components/Drawer/Drawer.sx.d.ts +23 -0
  76. package/dist/components/Drawer/DrawerContext.d.ts +18 -0
  77. package/dist/components/Drawer/DrawerItem.d.ts +35 -0
  78. package/dist/components/Drawer/index.d.ts +6 -0
  79. package/dist/components/Drawer.d.ts +6 -0
  80. package/dist/components/Icon/Icon.cjs +44 -3
  81. package/dist/components/Icon/Icon.cjs.map +1 -1
  82. package/dist/components/Icon/Icon.d.ts +34 -1
  83. package/dist/components/Icon/Icon.js +44 -3
  84. package/dist/components/Icon/Icon.js.map +1 -1
  85. package/dist/components/Input/Input.cjs +173 -3
  86. package/dist/components/Input/Input.cjs.map +1 -1
  87. package/dist/components/Input/Input.d.ts +20 -15
  88. package/dist/components/Input/Input.definitions.d.ts +5 -2
  89. package/dist/components/Input/Input.helpers.d.ts +14 -0
  90. package/dist/components/Input/Input.js +172 -2
  91. package/dist/components/Input/Input.js.map +1 -1
  92. package/dist/components/Input/Input.sx.d.ts +8 -0
  93. package/dist/components/Input/Input.types.d.ts +1 -0
  94. package/dist/components/Input/index.d.ts +2 -1
  95. package/dist/components/Input.d.ts +4 -0
  96. package/dist/components/InputGroup/InputGroup.cjs +104 -91
  97. package/dist/components/InputGroup/InputGroup.cjs.map +1 -1
  98. package/dist/components/InputGroup/InputGroup.d.ts +37 -1
  99. package/dist/components/InputGroup/InputGroup.definitions.d.ts +6 -0
  100. package/dist/components/InputGroup/InputGroup.js +106 -93
  101. package/dist/components/InputGroup/InputGroup.js.map +1 -1
  102. package/dist/components/Modal/Modal.cjs +226 -116
  103. package/dist/components/Modal/Modal.cjs.map +1 -1
  104. package/dist/components/Modal/Modal.d.ts +38 -2
  105. package/dist/components/Modal/Modal.js +227 -117
  106. package/dist/components/Modal/Modal.js.map +1 -1
  107. package/dist/components/Modal/ModalFooter.d.ts +9 -1
  108. package/dist/components/Modal/index.d.ts +5 -0
  109. package/dist/components/PageLoader/PageLoader.cjs +61 -0
  110. package/dist/components/PageLoader/PageLoader.cjs.map +1 -0
  111. package/dist/components/PageLoader/PageLoader.d.ts +38 -0
  112. package/dist/components/PageLoader/PageLoader.js +61 -0
  113. package/dist/components/PageLoader/PageLoader.js.map +1 -0
  114. package/dist/components/PageLoader/index.d.ts +2 -0
  115. package/dist/components/PageLoader.d.ts +6 -0
  116. package/dist/components/ScrollTopButton/ScrollTopButton.cjs +79 -0
  117. package/dist/components/ScrollTopButton/ScrollTopButton.cjs.map +1 -0
  118. package/dist/components/ScrollTopButton/ScrollTopButton.d.ts +48 -0
  119. package/dist/components/ScrollTopButton/ScrollTopButton.js +79 -0
  120. package/dist/components/ScrollTopButton/ScrollTopButton.js.map +1 -0
  121. package/dist/components/ScrollTopButton/index.d.ts +4 -0
  122. package/dist/components/ScrollTopButton/scrollToTop.d.ts +29 -0
  123. package/dist/components/ScrollTopButton.d.ts +6 -0
  124. package/dist/components/Select/Select.cjs +446 -4
  125. package/dist/components/Select/Select.cjs.map +1 -1
  126. package/dist/components/Select/Select.d.ts +33 -13
  127. package/dist/components/Select/Select.definitions.d.ts +3 -0
  128. package/dist/components/Select/Select.helpers.d.ts +28 -0
  129. package/dist/components/Select/Select.js +445 -3
  130. package/dist/components/Select/Select.js.map +1 -1
  131. package/dist/components/Select/Select.sx.d.ts +7 -0
  132. package/dist/components/Select/Select.types.d.ts +1 -0
  133. package/dist/components/Select/_parts/SelectMenuItem.d.ts +20 -0
  134. package/dist/components/Select/_parts/SelectSearchHeader.d.ts +15 -0
  135. package/dist/components/Select/_parts/SelectValue.d.ts +22 -0
  136. package/dist/components/Select/index.d.ts +2 -1
  137. package/dist/components/Select.d.ts +4 -0
  138. package/dist/components/Stat/Stat.cjs +1 -1
  139. package/dist/components/Stat/Stat.js +1 -1
  140. package/dist/components/Stepper/Stepper.cjs +4 -1
  141. package/dist/components/Stepper/Stepper.cjs.map +1 -1
  142. package/dist/components/Stepper/Stepper.d.ts +5 -0
  143. package/dist/components/Stepper/Stepper.js +4 -1
  144. package/dist/components/Stepper/Stepper.js.map +1 -1
  145. package/dist/components/_shared/formField.sx.d.ts +33 -0
  146. package/dist/components/_shared/resolvePreset.d.ts +18 -0
  147. package/dist/formField.sx-CQ1mbk9M.cjs +76 -0
  148. package/dist/formField.sx-CQ1mbk9M.cjs.map +1 -0
  149. package/dist/formField.sx-DfVbMe0V.js +77 -0
  150. package/dist/formField.sx-DfVbMe0V.js.map +1 -0
  151. package/dist/hooks/Wizard/Wizard.cjs +7 -0
  152. package/dist/hooks/Wizard/Wizard.cjs.map +1 -0
  153. package/dist/hooks/Wizard/Wizard.js +7 -0
  154. package/dist/hooks/Wizard/Wizard.js.map +1 -0
  155. package/dist/hooks/Wizard/WizardContext.d.ts +67 -0
  156. package/dist/hooks/Wizard/index.d.ts +3 -0
  157. package/dist/hooks/Wizard/useWizard.d.ts +9 -0
  158. package/dist/hooks/Wizard.d.ts +2 -0
  159. package/dist/index.cjs +99 -1
  160. package/dist/index.cjs.map +1 -1
  161. package/dist/index.d.ts +3 -0
  162. package/dist/index.js +31 -2
  163. package/dist/index.js.map +1 -1
  164. package/dist/mui.d.ts +5 -0
  165. package/dist/resolvePreset-B-IB0ehH.js +15 -0
  166. package/dist/resolvePreset-B-IB0ehH.js.map +1 -0
  167. package/dist/resolvePreset-CT3kU-K2.cjs +14 -0
  168. package/dist/resolvePreset-CT3kU-K2.cjs.map +1 -0
  169. package/dist/styles.css +3 -112
  170. package/dist/theme/componentStyles.d.ts +32 -0
  171. package/dist/theme/tokens.d.ts +28 -0
  172. package/dist/useWizard-CWdIxZzX.cjs +94 -0
  173. package/dist/useWizard-CWdIxZzX.cjs.map +1 -0
  174. package/dist/useWizard-CWq--C3o.js +95 -0
  175. package/dist/useWizard-CWq--C3o.js.map +1 -0
  176. package/package.json +1 -1
  177. package/src/components/ActionMenu/ActionMenu.stories.tsx +230 -0
  178. package/src/components/ActionMenu/ActionMenu.tsx +174 -0
  179. package/src/components/ActionMenu/index.ts +2 -0
  180. package/src/components/AppBar/AppBar.stories.tsx +272 -0
  181. package/src/components/AppBar/AppBar.sx.ts +32 -0
  182. package/src/components/AppBar/AppBar.tsx +123 -0
  183. package/src/components/AppBar/AppBarBrand.tsx +120 -0
  184. package/src/components/AppBar/AppBarContext.ts +25 -0
  185. package/src/components/AppBar/AppBarMenuToggle.tsx +90 -0
  186. package/src/components/AppBar/AppBarUserMenu.tsx +217 -0
  187. package/src/components/AppBar/index.ts +25 -0
  188. package/src/components/Autocomplete/Autocomplete.definitions.ts +223 -0
  189. package/src/components/Autocomplete/Autocomplete.helpers.ts +60 -0
  190. package/src/components/Autocomplete/Autocomplete.stories.tsx +363 -2
  191. package/src/components/Autocomplete/Autocomplete.sx.ts +30 -0
  192. package/src/components/Autocomplete/Autocomplete.tsx +312 -90
  193. package/src/components/Autocomplete/Autocomplete.types.ts +13 -0
  194. package/src/components/Autocomplete/_parts/AutocompleteChips.tsx +55 -0
  195. package/src/components/Autocomplete/_parts/AutocompleteLoader.tsx +17 -0
  196. package/src/components/Autocomplete/_parts/AutocompleteOption.tsx +31 -0
  197. package/src/components/Autocomplete/index.ts +12 -1
  198. package/src/components/Avatar/Avatar.definitions.ts +162 -0
  199. package/src/components/Avatar/Avatar.stories.tsx +205 -1
  200. package/src/components/Avatar/Avatar.tsx +166 -103
  201. package/src/components/Card/Card.stories.tsx +205 -16
  202. package/src/components/Card/Card.sx.ts +104 -0
  203. package/src/components/Card/Card.tsx +191 -35
  204. package/src/components/Card/index.ts +9 -1
  205. package/src/components/DatePicker/DatePicker.definitions.ts +24 -1
  206. package/src/components/DatePicker/DatePicker.helpers.ts +24 -0
  207. package/src/components/DatePicker/DatePicker.stories.tsx +29 -2
  208. package/src/components/DatePicker/DatePicker.sx.ts +33 -0
  209. package/src/components/DatePicker/DatePicker.tsx +163 -139
  210. package/src/components/DatePicker/DatePicker.types.ts +10 -0
  211. package/src/components/DatePicker/index.ts +9 -1
  212. package/src/components/DateTimePicker/DateTimePicker.definitions.ts +24 -0
  213. package/src/components/DateTimePicker/DateTimePicker.helpers.ts +38 -0
  214. package/src/components/DateTimePicker/DateTimePicker.stories.tsx +29 -1
  215. package/src/components/DateTimePicker/DateTimePicker.sx.ts +30 -0
  216. package/src/components/DateTimePicker/DateTimePicker.tsx +200 -166
  217. package/src/components/DateTimePicker/DateTimePicker.types.ts +10 -0
  218. package/src/components/DateTimePicker/index.ts +9 -1
  219. package/src/components/Drawer/Drawer.stories.tsx +270 -0
  220. package/src/components/Drawer/Drawer.sx.ts +106 -0
  221. package/src/components/Drawer/Drawer.tsx +214 -0
  222. package/src/components/Drawer/DrawerContext.ts +26 -0
  223. package/src/components/Drawer/DrawerItem.tsx +110 -0
  224. package/src/components/Drawer/index.ts +10 -0
  225. package/src/components/Flyout/Flyout.stories.tsx +26 -18
  226. package/src/components/Icon/Icon.stories.tsx +68 -1
  227. package/src/components/Icon/Icon.tsx +87 -6
  228. package/src/components/Input/Input.definitions.ts +74 -2
  229. package/src/components/Input/Input.helpers.ts +49 -0
  230. package/src/components/Input/Input.stories.tsx +116 -4
  231. package/src/components/Input/Input.sx.ts +42 -0
  232. package/src/components/Input/Input.tsx +117 -162
  233. package/src/components/Input/Input.types.ts +10 -0
  234. package/src/components/Input/index.ts +9 -1
  235. package/src/components/InputGroup/InputGroup.definitions.ts +158 -0
  236. package/src/components/InputGroup/InputGroup.stories.tsx +159 -28
  237. package/src/components/InputGroup/InputGroup.tsx +159 -116
  238. package/src/components/Modal/Modal.stories.tsx +434 -6
  239. package/src/components/Modal/Modal.tsx +303 -121
  240. package/src/components/Modal/ModalFooter.tsx +22 -12
  241. package/src/components/Modal/index.ts +6 -1
  242. package/src/components/PageLoader/PageLoader.stories.tsx +217 -0
  243. package/src/components/PageLoader/PageLoader.tsx +96 -0
  244. package/src/components/PageLoader/index.ts +2 -0
  245. package/src/components/ScrollTopButton/ScrollTopButton.stories.tsx +158 -0
  246. package/src/components/ScrollTopButton/ScrollTopButton.tsx +135 -0
  247. package/src/components/ScrollTopButton/index.ts +8 -0
  248. package/src/components/ScrollTopButton/scrollToTop.ts +37 -0
  249. package/src/components/Select/Select.definitions.ts +114 -0
  250. package/src/components/Select/Select.helpers.ts +71 -0
  251. package/src/components/Select/Select.stories.tsx +126 -8
  252. package/src/components/Select/Select.sx.ts +14 -0
  253. package/src/components/Select/Select.tsx +246 -285
  254. package/src/components/Select/Select.types.ts +15 -0
  255. package/src/components/Select/_parts/SelectMenuItem.tsx +40 -0
  256. package/src/components/Select/_parts/SelectSearchHeader.tsx +51 -0
  257. package/src/components/Select/_parts/SelectValue.tsx +96 -0
  258. package/src/components/Select/index.ts +14 -1
  259. package/src/components/Stepper/Stepper.tsx +17 -1
  260. package/src/components/Tooltip/Tooltip.stories.tsx +15 -3
  261. package/src/components/_shared/formField.sx.ts +118 -0
  262. package/src/components/_shared/resolvePreset.ts +35 -0
  263. package/src/hooks/Wizard/Wizard.stories.tsx +301 -0
  264. package/src/hooks/Wizard/WizardContext.tsx +166 -0
  265. package/src/hooks/Wizard/index.ts +6 -0
  266. package/src/hooks/Wizard/useWizard.ts +13 -0
  267. package/src/index.ts +17 -1
  268. package/src/mui.ts +44 -0
  269. package/src/theme/componentStyles.ts +47 -0
  270. package/src/theme/tokens.ts +43 -0
  271. package/dist/DatePicker-BSNboVhN.js +0 -201
  272. package/dist/DatePicker-BSNboVhN.js.map +0 -1
  273. package/dist/DatePicker-BoqxWAhj.cjs +0 -200
  274. package/dist/DatePicker-BoqxWAhj.cjs.map +0 -1
  275. package/dist/Input-DFHs7cJ_.js +0 -171
  276. package/dist/Input-DFHs7cJ_.js.map +0 -1
  277. package/dist/Input-c8MwNNPg.cjs +0 -170
  278. package/dist/Input-c8MwNNPg.cjs.map +0 -1
  279. package/dist/Select-BO2N56sm.cjs +0 -411
  280. package/dist/Select-BO2N56sm.cjs.map +0 -1
  281. package/dist/Select-BcLkyHSE.js +0 -412
  282. package/dist/Select-BcLkyHSE.js.map +0 -1
  283. package/dist/index.css +0 -3
@@ -1,7 +1,24 @@
1
- import React, { useState, useImperativeHandle, forwardRef } from 'react'; // 👈 Importa useImperativeHandle y forwardRef
2
- import { Modal as MuiModal, Box, Paper, useTheme, useMediaQuery } from '@mui/material';
1
+ import React, {
2
+ useState,
3
+ useImperativeHandle,
4
+ forwardRef,
5
+ type ReactNode,
6
+ } from 'react';
7
+ import {
8
+ Modal as MuiModal,
9
+ Paper,
10
+ useTheme,
11
+ useMediaQuery,
12
+ Box,
13
+ Stack,
14
+ Typography,
15
+ } from '@mui/material';
16
+ import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
17
+ import WarningAmberIcon from '@mui/icons-material/WarningAmber';
18
+ import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
19
+ import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
3
20
 
4
- import { DialogProps } from '@mui/material/Dialog';
21
+ import type { DialogProps } from '@mui/material/Dialog';
5
22
  import { ModalAction, ModalFooter, ModalFooterProps } from './ModalFooter';
6
23
  import { ModalHeader } from './ModalHeader';
7
24
  import { ModalBody } from './ModalBody';
@@ -12,153 +29,318 @@ export interface ModalRef {
12
29
  close: () => void;
13
30
  }
14
31
 
32
+ export type ModalMode = 'default' | 'confirm';
33
+ export type ModalSeverity = 'info' | 'warning' | 'error' | 'success';
34
+
15
35
  interface ModalProps {
16
- // La prop 'open' ahora es opcional si se usa con ref, pero aún puede ser controlada externamente
36
+ /**
37
+ * Modo del modal.
38
+ * - `default` (default): modal genérico con slots `Header`/`Body`/`Footer` y
39
+ * `actions` custom.
40
+ * - `confirm`: reemplaza al `ConfirmModal` legacy. Renderiza un layout
41
+ * focalizado con icono por severidad, mensaje y botones "Cancelar" /
42
+ * "Confirmar".
43
+ */
44
+ mode?: ModalMode;
45
+
46
+ // ── Props comunes ────────────────────────────────────────────────────
47
+ /** Controlado externamente. Omitir si se usa vía ref. */
17
48
  open?: boolean;
18
- onClose?: () => void; // 'onClose' ahora es opcional ya que el modal puede cerrarse internamente
49
+ /** Callback al cerrar. También se dispara al confirmar/cancelar. */
50
+ onClose?: () => void;
19
51
  title?: string;
20
- children: React.ReactNode;
52
+ children?: ReactNode;
21
53
  showCloseButton?: boolean;
22
54
  closeButtonText?: string;
23
55
  closeButtonDisabled?: boolean;
24
56
  actions?: ModalAction[];
25
57
  maxWidth?: DialogProps['maxWidth'];
26
- hiddenFooter?: boolean
58
+ hiddenFooter?: boolean;
59
+
60
+ // ── Props del modo confirm ───────────────────────────────────────────
61
+ /**
62
+ * Callback de confirmación. Soporta promesa — si devuelve `Promise`, el
63
+ * botón muestra estado `disabled` mientras resuelve.
64
+ */
65
+ onConfirm?: () => void | Promise<void>;
66
+ /** Texto del botón primario en modo `confirm`. Default: "Confirmar". */
67
+ confirmText?: string;
68
+ /** Deshabilita el botón de confirmar. */
69
+ confirmDisabled?: boolean;
70
+ /**
71
+ * Severidad visual en modo `confirm`. Controla el icono y el color del
72
+ * botón de confirmación.
73
+ * - `info` (default): primary
74
+ * - `warning`: warning (amarillo)
75
+ * - `error`: error (rojo) — típico para "Eliminar"
76
+ * - `success`: success (verde) — típico para "Aprobar"
77
+ */
78
+ severity?: ModalSeverity;
79
+ /**
80
+ * Mensaje del confirm. Puede ser string o cualquier ReactNode. Si se omite,
81
+ * se usa `children`.
82
+ */
83
+ confirmMessage?: ReactNode;
27
84
  }
28
85
 
29
86
  const modalStyle = {
30
- position: 'absolute' as 'absolute',
87
+ position: 'absolute' as const,
31
88
  top: '50%',
32
89
  left: '50%',
33
90
  transform: 'translate(-50%, -50%)',
34
91
  width: '90%',
35
92
  maxHeight: '90vh',
36
93
  display: 'flex',
37
- flexDirection: 'column',
94
+ flexDirection: 'column' as const,
38
95
  outline: 'none',
39
96
  };
40
97
 
41
- // Envuelve el componente en forwardRef
42
- export const Modal = forwardRef<ModalRef, ModalProps>(({
43
- open: controlledOpen, // Renombra la prop 'open' si se pasa externamente
44
- onClose: controlledOnClose, // Renombra la prop 'onClose' si se pasa externamente
45
- title,
46
- children,
47
- showCloseButton = true,
48
- closeButtonText = "Cerrar",
49
- closeButtonDisabled = false,
50
- actions = [],
51
- maxWidth = 'sm',
52
- hiddenFooter = false,
53
- }, ref) => { // Recibe la ref
54
- // Estado interno para gestionar la visibilidad si no es controlado externamente
55
- const [internalOpen, setInternalOpen] = useState(false);
56
-
57
- // Determina si el modal está abierto, priorizando la prop externa
58
- const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;
59
-
60
- // Expone métodos 'open' y 'close' a través de la ref
61
- useImperativeHandle(ref, () => ({
62
- open: () => setInternalOpen(true),
63
- close: () => {
64
- setInternalOpen(false);
65
- controlledOnClose?.(); // Llama al onClose externo si existe
98
+ const severityConfig: Record<
99
+ ModalSeverity,
100
+ { color: ModalAction['color']; icon: ReactNode; bg: string }
101
+ > = {
102
+ info: {
103
+ color: 'primary',
104
+ icon: <InfoOutlinedIcon sx={{ fontSize: 48 }} />,
105
+ bg: 'primary.light',
106
+ },
107
+ warning: {
108
+ color: 'warning',
109
+ icon: <WarningAmberIcon sx={{ fontSize: 48 }} />,
110
+ bg: 'warning.light',
111
+ },
112
+ error: {
113
+ color: 'error',
114
+ icon: <ErrorOutlineIcon sx={{ fontSize: 48 }} />,
115
+ bg: 'error.light',
116
+ },
117
+ success: {
118
+ color: 'success',
119
+ icon: <CheckCircleOutlineIcon sx={{ fontSize: 48 }} />,
120
+ bg: 'success.light',
121
+ },
122
+ };
123
+
124
+ export const Modal = forwardRef<ModalRef, ModalProps>(
125
+ (
126
+ {
127
+ mode = 'default',
128
+ open: controlledOpen,
129
+ onClose: controlledOnClose,
130
+ title,
131
+ children,
132
+ showCloseButton = true,
133
+ closeButtonText = 'Cerrar',
134
+ closeButtonDisabled = false,
135
+ actions = [],
136
+ maxWidth = 'sm',
137
+ hiddenFooter = false,
138
+
139
+ // Props del modo confirm
140
+ onConfirm,
141
+ confirmText = 'Confirmar',
142
+ confirmDisabled = false,
143
+ severity = 'info',
144
+ confirmMessage,
66
145
  },
67
- }));
68
-
69
- const handleCloseInternal = () => {
70
- setInternalOpen(false);
71
- controlledOnClose?.(); // Llama al onClose externo si existe
72
- };
73
-
74
- const theme = useTheme();
75
- const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
76
-
77
- const getWidth = () => {
78
- if (isMobile) return '95%';
79
- switch (maxWidth) {
80
- case 'xs': return 300;
81
- case 'sm': return 500;
82
- case 'md': return 700;
83
- case 'lg': return 900;
84
- case 'xl': return 1100;
85
- case false: return 'auto';
86
- default: return 500;
87
- }
88
- };
89
-
90
- const renderChildren = () => {
91
- let header: React.ReactNode | null = null;
92
- let body: React.ReactNode | null = null;
93
- let footer: React.ReactNode | null = null;
94
-
95
- React.Children.forEach(children, (child) => {
96
- if (React.isValidElement(child)) {
97
- if (child.type === ModalHeader) {
98
- header = child;
99
- } else if (child.type === ModalBody) {
100
- body = child;
101
- } else if (child.type === ModalFooter) {
102
- const footerChild = child as React.ReactElement<ModalFooterProps>;
103
- const {
104
- showCloseButton: childShowCloseButton,
105
- closeButtonText: childCloseButtonText,
106
- closeButtonDisabled: childCloseButtonDisabled,
107
- onClose: childOnClose,
108
- actions: childActions,
109
- ...restOfFooterProps
110
- } = footerChild.props;
111
-
112
- footer = React.cloneElement(footerChild, {
113
- showCloseButton,
114
- closeButtonText,
115
- closeButtonDisabled,
116
- onClose: handleCloseInternal, // Usa la función de cierre interna
117
- actions,
118
- ...restOfFooterProps,
119
- });
146
+ ref,
147
+ ) => {
148
+ const [internalOpen, setInternalOpen] = useState(false);
149
+ const [confirmLoading, setConfirmLoading] = useState(false);
150
+
151
+ const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;
152
+
153
+ useImperativeHandle(ref, () => ({
154
+ open: () => setInternalOpen(true),
155
+ close: () => {
156
+ setInternalOpen(false);
157
+ controlledOnClose?.();
158
+ },
159
+ }));
160
+
161
+ const handleCloseInternal = () => {
162
+ setInternalOpen(false);
163
+ controlledOnClose?.();
164
+ };
165
+
166
+ const handleConfirm = async () => {
167
+ if (!onConfirm) {
168
+ handleCloseInternal();
169
+ return;
170
+ }
171
+ try {
172
+ const result = onConfirm();
173
+ if (result instanceof Promise) {
174
+ setConfirmLoading(true);
175
+ await result;
120
176
  }
177
+ } finally {
178
+ setConfirmLoading(false);
179
+ handleCloseInternal();
121
180
  }
122
- });
123
-
124
- if (!footer && !hiddenFooter) {
125
- footer = (
126
- <ModalFooter
127
- showCloseButton={showCloseButton}
128
- closeButtonText={closeButtonText}
129
- closeButtonDisabled={closeButtonDisabled}
130
- onClose={handleCloseInternal} // Usa la función de cierre interna
131
- actions={actions}
132
- />
181
+ };
182
+
183
+ const theme = useTheme();
184
+ const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
185
+
186
+ const getWidth = () => {
187
+ if (isMobile) return '95%';
188
+ switch (maxWidth) {
189
+ case 'xs':
190
+ return 300;
191
+ case 'sm':
192
+ return 500;
193
+ case 'md':
194
+ return 700;
195
+ case 'lg':
196
+ return 900;
197
+ case 'xl':
198
+ return 1100;
199
+ case false:
200
+ return 'auto';
201
+ default:
202
+ return 500;
203
+ }
204
+ };
205
+
206
+ // ── Render modo CONFIRM ─────────────────────────────────────────────
207
+ if (mode === 'confirm') {
208
+ const config = severityConfig[severity];
209
+ const message = confirmMessage ?? children;
210
+
211
+ return (
212
+ <MuiModal
213
+ open={isOpen}
214
+ onClose={handleCloseInternal}
215
+ aria-labelledby="modal-title"
216
+ closeAfterTransition
217
+ >
218
+ <Paper sx={{ ...modalStyle, width: getWidth() }}>
219
+ <Stack spacing={2.5} sx={{ p: 3, alignItems: 'center', textAlign: 'center' }}>
220
+ <Box
221
+ sx={{
222
+ width: 72,
223
+ height: 72,
224
+ borderRadius: '50%',
225
+ backgroundColor: (t) =>
226
+ t.palette[severity === 'info' ? 'primary' : severity].light,
227
+ color: (t) =>
228
+ t.palette[severity === 'info' ? 'primary' : severity].dark,
229
+ display: 'flex',
230
+ alignItems: 'center',
231
+ justifyContent: 'center',
232
+ opacity: 0.9,
233
+ }}
234
+ >
235
+ {config.icon}
236
+ </Box>
237
+ {title && (
238
+ <Typography variant="h6" component="h2" sx={{ fontWeight: 700 }}>
239
+ {title}
240
+ </Typography>
241
+ )}
242
+ {message && (
243
+ <Typography variant="body2" color="text.secondary">
244
+ {message}
245
+ </Typography>
246
+ )}
247
+ </Stack>
248
+ <ModalFooter
249
+ showCloseButton={showCloseButton}
250
+ closeButtonText={closeButtonText}
251
+ closeButtonDisabled={closeButtonDisabled || confirmLoading}
252
+ onClose={handleCloseInternal}
253
+ actions={[
254
+ {
255
+ text: confirmText,
256
+ onClick: handleConfirm,
257
+ disabled: confirmDisabled || confirmLoading,
258
+ variant: 'contained',
259
+ color: config.color,
260
+ },
261
+ ]}
262
+ />
263
+ </Paper>
264
+ </MuiModal>
133
265
  );
134
266
  }
135
267
 
268
+ // ── Render modo DEFAULT (legacy) ────────────────────────────────────
269
+ const renderChildren = () => {
270
+ let header: ReactNode | null = null;
271
+ let body: ReactNode | null = null;
272
+ let footer: ReactNode | null = null;
273
+
274
+ React.Children.forEach(children, (child) => {
275
+ if (React.isValidElement(child)) {
276
+ if (child.type === ModalHeader) {
277
+ header = child;
278
+ } else if (child.type === ModalBody) {
279
+ body = child;
280
+ } else if (child.type === ModalFooter) {
281
+ const footerChild = child as React.ReactElement<ModalFooterProps>;
282
+ const {
283
+ showCloseButton: childShowCloseButton,
284
+ closeButtonText: childCloseButtonText,
285
+ closeButtonDisabled: childCloseButtonDisabled,
286
+ onClose: childOnClose,
287
+ actions: childActions,
288
+ ...restOfFooterProps
289
+ } = footerChild.props;
290
+
291
+ footer = React.cloneElement(footerChild, {
292
+ showCloseButton,
293
+ closeButtonText,
294
+ closeButtonDisabled,
295
+ onClose: handleCloseInternal,
296
+ actions,
297
+ ...restOfFooterProps,
298
+ });
299
+ }
300
+ }
301
+ });
302
+
303
+ if (!footer && !hiddenFooter) {
304
+ footer = (
305
+ <ModalFooter
306
+ showCloseButton={showCloseButton}
307
+ closeButtonText={closeButtonText}
308
+ closeButtonDisabled={closeButtonDisabled}
309
+ onClose={handleCloseInternal}
310
+ actions={actions}
311
+ />
312
+ );
313
+ }
314
+
315
+ return (
316
+ <>
317
+ {header || (title && <ModalHeader>{title}</ModalHeader>)}
318
+ {body}
319
+ {footer}
320
+ </>
321
+ );
322
+ };
323
+
136
324
  return (
137
- <>
138
- {header || (title && <ModalHeader>{title}</ModalHeader>)}
139
- {body}
140
- {footer}
141
- </>
325
+ <MuiModal
326
+ open={isOpen}
327
+ onClose={handleCloseInternal}
328
+ aria-labelledby="modal-title"
329
+ aria-describedby="modal-description"
330
+ closeAfterTransition
331
+ >
332
+ <Paper sx={{ ...modalStyle, width: getWidth() }}>
333
+ {renderChildren()}
334
+ </Paper>
335
+ </MuiModal>
142
336
  );
143
- };
144
-
145
- return (
146
- <MuiModal
147
- open={isOpen} // Usa el estado de visibilidad determinado
148
- onClose={handleCloseInternal} // Usa la función de cierre interna
149
- aria-labelledby="modal-title"
150
- aria-describedby="modal-description"
151
- closeAfterTransition
152
- >
153
- <Paper sx={{ ...modalStyle, width: getWidth() }}>
154
- {renderChildren()}
155
- </Paper>
156
- </MuiModal>
157
- );
158
- });
337
+ },
338
+ );
159
339
 
160
340
  // Define los sub-componentes como propiedades estáticas con tipos explícitos
161
- type ModalComponent = React.ForwardRefExoticComponent<ModalProps & React.RefAttributes<ModalRef>> & {
341
+ type ModalComponent = React.ForwardRefExoticComponent<
342
+ ModalProps & React.RefAttributes<ModalRef>
343
+ > & {
162
344
  Header: typeof ModalHeader;
163
345
  Body: typeof ModalBody;
164
346
  Footer: typeof ModalFooter;
@@ -170,4 +352,4 @@ ModalWithStatics.Header = ModalHeader;
170
352
  ModalWithStatics.Body = ModalBody;
171
353
  ModalWithStatics.Footer = ModalFooter;
172
354
 
173
- export default ModalWithStatics;
355
+ export default ModalWithStatics;
@@ -5,10 +5,16 @@ import { ButtonProps } from '@mui/material/Button';
5
5
  // Interfaz para acciones personalizadas (se mantiene aquí)
6
6
  export interface ModalAction {
7
7
  text: string;
8
- onClick: () => void;
8
+ onClick?: () => void;
9
9
  disabled?: boolean;
10
10
  variant?: ButtonProps['variant'];
11
11
  color?: ButtonProps['color'];
12
+ /**
13
+ * Props adicionales que se forwardean al `<Button>` interno. Útil para casos
14
+ * avanzados como conectar el botón con un `<form id="...">` externo usando
15
+ * `buttonProps={{ type: 'submit', form: 'my-form-id' }}`.
16
+ */
17
+ buttonProps?: Partial<ButtonProps> & { form?: string };
12
18
  }
13
19
 
14
20
  export interface ModalFooterProps { // Renombrado
@@ -42,17 +48,21 @@ export const ModalFooter: React.FC<ModalFooterProps> = ({ // Renombrado
42
48
  {closeButtonText}
43
49
  </Button>
44
50
  )}
45
- {actions.map((action, index) => (
46
- <Button
47
- key={index}
48
- onClick={action.onClick}
49
- disabled={action.disabled}
50
- variant={action.variant || 'contained'}
51
- color={action.color || 'primary'}
52
- >
53
- {action.text}
54
- </Button>
55
- ))}
51
+ {actions.map((action, index) => {
52
+ const { buttonProps } = action;
53
+ return (
54
+ <Button
55
+ key={index}
56
+ onClick={action.onClick}
57
+ disabled={action.disabled}
58
+ variant={action.variant || 'contained'}
59
+ color={action.color || 'primary'}
60
+ {...(buttonProps as any)}
61
+ >
62
+ {action.text}
63
+ </Button>
64
+ );
65
+ })}
56
66
  </Stack>
57
67
  </Box>
58
68
  );
@@ -1 +1,6 @@
1
- export {default as Modal } from './Modal';
1
+ export { default as Modal } from './Modal';
2
+ export type { ModalRef, ModalMode, ModalSeverity } from './Modal';
3
+ export { ModalHeader } from './ModalHeader';
4
+ export { ModalBody } from './ModalBody';
5
+ export { ModalFooter } from './ModalFooter';
6
+ export type { ModalAction, ModalFooterProps } from './ModalFooter';