@soyfri/shared-library 3.2.1 → 4.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 (236) hide show
  1. package/DataRow-B7fJ5taA.js +55 -0
  2. package/DataRow-B7fJ5taA.js.map +1 -0
  3. package/DataRow-CfCaSdaJ.cjs +54 -0
  4. package/DataRow-CfCaSdaJ.cjs.map +1 -0
  5. package/EmptyState-DJj9KOEy.cjs +47 -0
  6. package/EmptyState-DJj9KOEy.cjs.map +1 -0
  7. package/EmptyState-kEoDkg1B.js +48 -0
  8. package/EmptyState-kEoDkg1B.js.map +1 -0
  9. package/{Modal-C_QY7ZzY.js → Modal-BqW0Nk3l.js} +12 -2
  10. package/{Modal-C_QY7ZzY.js.map → Modal-BqW0Nk3l.js.map} +1 -1
  11. package/{Modal-D_6ZdSzw.cjs → Modal-Cfyr-RsW.cjs} +12 -2
  12. package/{Modal-D_6ZdSzw.cjs.map → Modal-Cfyr-RsW.cjs.map} +1 -1
  13. package/PageHeader-BQZOqjNr.cjs +37 -0
  14. package/PageHeader-BQZOqjNr.cjs.map +1 -0
  15. package/PageHeader-DDYi6Nhy.js +38 -0
  16. package/PageHeader-DDYi6Nhy.js.map +1 -0
  17. package/{Table-DaNgX7PO.cjs → Table-BpnAkCgd.cjs} +4 -3
  18. package/Table-BpnAkCgd.cjs.map +1 -0
  19. package/{Table-aNFAOuQk.js → Table-BuALBQWX.js} +4 -3
  20. package/Table-BuALBQWX.js.map +1 -0
  21. package/{Tooltip-BB77JBcg.js → Tooltip-B15a34_o.js} +4 -6
  22. package/Tooltip-B15a34_o.js.map +1 -0
  23. package/{Tooltip-DpAsWGpN.cjs → Tooltip-CEEDkwds.cjs} +4 -6
  24. package/Tooltip-CEEDkwds.cjs.map +1 -0
  25. package/components/ActionMenu.d.ts +3 -3
  26. package/components/Alert.d.ts +3 -3
  27. package/components/AppBar.d.ts +3 -3
  28. package/components/Autocomplete.d.ts +3 -3
  29. package/components/Avatar.d.ts +1 -1
  30. package/components/Breadcrumbs.d.ts +3 -3
  31. package/components/Button.d.ts +1 -1
  32. package/components/ButtonGroup.d.ts +3 -3
  33. package/components/Card.d.ts +3 -3
  34. package/components/Checkbox.d.ts +3 -3
  35. package/components/Chip.d.ts +3 -3
  36. package/components/Column.d.ts +1 -1
  37. package/components/DataRow/DataRow.cjs +6 -0
  38. package/components/DataRow/DataRow.cjs.map +1 -0
  39. package/components/DataRow/DataRow.js +6 -0
  40. package/components/DataRow/DataRow.js.map +1 -0
  41. package/components/DataRow.d.ts +6 -0
  42. package/components/DatePicker.d.ts +3 -3
  43. package/components/DateTimePicker.d.ts +3 -3
  44. package/components/Divider.d.ts +3 -3
  45. package/components/Drawer.d.ts +3 -3
  46. package/components/EmptyState/EmptyState.cjs +6 -0
  47. package/components/EmptyState/EmptyState.cjs.map +1 -0
  48. package/components/EmptyState/EmptyState.js +6 -0
  49. package/components/EmptyState/EmptyState.js.map +1 -0
  50. package/components/EmptyState.d.ts +6 -0
  51. package/components/Flyout.d.ts +1 -1
  52. package/components/Gallery.d.ts +3 -3
  53. package/components/Icon.d.ts +3 -3
  54. package/components/Input.d.ts +3 -3
  55. package/components/InputGroup.d.ts +3 -3
  56. package/components/MenuButton.d.ts +1 -1
  57. package/components/Modal/Modal.cjs +1 -1
  58. package/components/Modal/Modal.js +1 -1
  59. package/components/Modal.d.ts +3 -3
  60. package/components/PageHeader/PageHeader.cjs +6 -0
  61. package/components/PageHeader/PageHeader.cjs.map +1 -0
  62. package/components/PageHeader/PageHeader.js +6 -0
  63. package/components/PageHeader/PageHeader.js.map +1 -0
  64. package/components/PageHeader.d.ts +6 -0
  65. package/components/RadioGroup.d.ts +3 -3
  66. package/components/Select.d.ts +3 -3
  67. package/components/Spinner.d.ts +3 -3
  68. package/components/Stat.d.ts +3 -3
  69. package/components/StatusMessage.d.ts +3 -3
  70. package/components/Stepper.d.ts +3 -3
  71. package/components/Switch.d.ts +3 -3
  72. package/components/Table/Table.cjs +1 -1
  73. package/components/Table/Table.js +1 -1
  74. package/components/Table.d.ts +1 -1
  75. package/components/Tabs.d.ts +3 -3
  76. package/components/Timeline.d.ts +3 -3
  77. package/components/Tooltip/Tooltip.cjs +1 -1
  78. package/components/Tooltip/Tooltip.js +1 -1
  79. package/components/Tooltip.d.ts +1 -1
  80. package/hooks/ClipBoard.d.ts +1 -1
  81. package/index.cjs +9 -3
  82. package/index.cjs.map +1 -1
  83. package/index.d.ts +2 -56
  84. package/index.js +15 -9
  85. package/index.js.map +1 -1
  86. package/package.json +16 -1
  87. package/src/components/DataRow/DataRow.d.ts +44 -0
  88. package/src/components/DataRow/index.d.ts +2 -0
  89. package/src/components/EmptyState/EmptyState.d.ts +24 -0
  90. package/src/components/EmptyState/index.d.ts +2 -0
  91. package/src/components/PageHeader/PageHeader.d.ts +25 -0
  92. package/src/components/PageHeader/index.d.ts +2 -0
  93. package/{components → src/components}/Table/Table.d.ts +10 -1
  94. package/src/demos/themes.d.ts +29 -0
  95. package/src/index.d.ts +62 -0
  96. package/{theme → src/theme}/componentStyles.d.ts +1 -1
  97. package/Table-DaNgX7PO.cjs.map +0 -1
  98. package/Table-aNFAOuQk.js.map +0 -1
  99. package/Tooltip-BB77JBcg.js.map +0 -1
  100. package/Tooltip-DpAsWGpN.cjs.map +0 -1
  101. package/styles.css +0 -375
  102. /package/{components → src/components}/ActionMenu/ActionMenu.d.ts +0 -0
  103. /package/{components → src/components}/ActionMenu/index.d.ts +0 -0
  104. /package/{components → src/components}/Alert/Alert.d.ts +0 -0
  105. /package/{components → src/components}/Alert/index.d.ts +0 -0
  106. /package/{components → src/components}/AppBar/AppBar.d.ts +0 -0
  107. /package/{components → src/components}/AppBar/AppBar.sx.d.ts +0 -0
  108. /package/{components → src/components}/AppBar/AppBarContext.d.ts +0 -0
  109. /package/{components → src/components}/AppBar/AppBarMenuToggle.d.ts +0 -0
  110. /package/{components → src/components}/AppBar/index.d.ts +0 -0
  111. /package/{components → src/components}/Autocomplete/Autocomplete.d.ts +0 -0
  112. /package/{components → src/components}/Autocomplete/Autocomplete.definitions.d.ts +0 -0
  113. /package/{components → src/components}/Autocomplete/Autocomplete.helpers.d.ts +0 -0
  114. /package/{components → src/components}/Autocomplete/Autocomplete.sx.d.ts +0 -0
  115. /package/{components → src/components}/Autocomplete/_parts/AutocompleteChips.d.ts +0 -0
  116. /package/{components → src/components}/Autocomplete/_parts/AutocompleteLoader.d.ts +0 -0
  117. /package/{components → src/components}/Autocomplete/_parts/AutocompleteOption.d.ts +0 -0
  118. /package/{components → src/components}/Autocomplete/index.d.ts +0 -0
  119. /package/{components → src/components}/Avatar/Avatar.d.ts +0 -0
  120. /package/{components → src/components}/Avatar/Avatar.definitions.d.ts +0 -0
  121. /package/{components → src/components}/Avatar/index.d.ts +0 -0
  122. /package/{components → src/components}/Breadcrumbs/Breadcrumbs.d.ts +0 -0
  123. /package/{components → src/components}/Breadcrumbs/index.d.ts +0 -0
  124. /package/{components → src/components}/Button/Button.d.ts +0 -0
  125. /package/{components → src/components}/Button/Button.definition.d.ts +0 -0
  126. /package/{components → src/components}/Button/index.d.ts +0 -0
  127. /package/{components → src/components}/ButtonGroup/ButtonGroup.d.ts +0 -0
  128. /package/{components → src/components}/ButtonGroup/index.d.ts +0 -0
  129. /package/{components → src/components}/Card/Card.d.ts +0 -0
  130. /package/{components → src/components}/Card/Card.definition.d.ts +0 -0
  131. /package/{components → src/components}/Card/Card.sx.d.ts +0 -0
  132. /package/{components → src/components}/Card/index.d.ts +0 -0
  133. /package/{components → src/components}/Checkbox/Checkbox.d.ts +0 -0
  134. /package/{components → src/components}/Checkbox/Checkbox.sx.d.ts +0 -0
  135. /package/{components → src/components}/Checkbox/index.d.ts +0 -0
  136. /package/{components → src/components}/Chip/Chip.d.ts +0 -0
  137. /package/{components → src/components}/Chip/Chip.definitions.d.ts +0 -0
  138. /package/{components → src/components}/Chip/index.d.ts +0 -0
  139. /package/{components → src/components}/Column/Column.d.ts +0 -0
  140. /package/{components → src/components}/Column/index.d.ts +0 -0
  141. /package/{components → src/components}/DatePicker/DatePicker.d.ts +0 -0
  142. /package/{components → src/components}/DatePicker/DatePicker.definitions.d.ts +0 -0
  143. /package/{components → src/components}/DatePicker/DatePicker.helpers.d.ts +0 -0
  144. /package/{components → src/components}/DatePicker/DatePicker.sx.d.ts +0 -0
  145. /package/{components → src/components}/DatePicker/index.d.ts +0 -0
  146. /package/{components → src/components}/DateTimePicker/DateTimePicker.d.ts +0 -0
  147. /package/{components → src/components}/DateTimePicker/DateTimePicker.definitions.d.ts +0 -0
  148. /package/{components → src/components}/DateTimePicker/DateTimePicker.helpers.d.ts +0 -0
  149. /package/{components → src/components}/DateTimePicker/DateTimePicker.sx.d.ts +0 -0
  150. /package/{components → src/components}/DateTimePicker/index.d.ts +0 -0
  151. /package/{components → src/components}/Divider/Divider.d.ts +0 -0
  152. /package/{components → src/components}/Divider/index.d.ts +0 -0
  153. /package/{components → src/components}/Drawer/Drawer.d.ts +0 -0
  154. /package/{components → src/components}/Drawer/Drawer.sx.d.ts +0 -0
  155. /package/{components → src/components}/Drawer/DrawerContext.d.ts +0 -0
  156. /package/{components → src/components}/Drawer/DrawerItem.d.ts +0 -0
  157. /package/{components → src/components}/Drawer/index.d.ts +0 -0
  158. /package/{components → src/components}/Flyout/Flyout.d.ts +0 -0
  159. /package/{components → src/components}/Flyout/index.d.ts +0 -0
  160. /package/{components → src/components}/Gallery/Gallery.d.ts +0 -0
  161. /package/{components → src/components}/Gallery/Gallery.definition.d.ts +0 -0
  162. /package/{components → src/components}/Gallery/GalleryLightbox.d.ts +0 -0
  163. /package/{components → src/components}/Gallery/GalleryMain.d.ts +0 -0
  164. /package/{components → src/components}/Gallery/GalleryThumbnails.d.ts +0 -0
  165. /package/{components → src/components}/Gallery/index.d.ts +0 -0
  166. /package/{components → src/components}/Icon/Icon.d.ts +0 -0
  167. /package/{components → src/components}/Icon/index.d.ts +0 -0
  168. /package/{components → src/components}/Input/Input.d.ts +0 -0
  169. /package/{components → src/components}/Input/Input.definitions.d.ts +0 -0
  170. /package/{components → src/components}/Input/Input.helpers.d.ts +0 -0
  171. /package/{components → src/components}/Input/Input.sx.d.ts +0 -0
  172. /package/{components → src/components}/Input/index.d.ts +0 -0
  173. /package/{components → src/components}/InputGroup/InputGroup.d.ts +0 -0
  174. /package/{components → src/components}/InputGroup/InputGroup.definitions.d.ts +0 -0
  175. /package/{components → src/components}/InputGroup/index.d.ts +0 -0
  176. /package/{components → src/components}/MenuButton/MenuButton.d.ts +0 -0
  177. /package/{components → src/components}/MenuButton/index.d.ts +0 -0
  178. /package/{components → src/components}/Modal/Modal.d.ts +0 -0
  179. /package/{components → src/components}/Modal/ModalBody.d.ts +0 -0
  180. /package/{components → src/components}/Modal/ModalFooter.d.ts +0 -0
  181. /package/{components → src/components}/Modal/ModalHeader.d.ts +0 -0
  182. /package/{components → src/components}/Modal/index.d.ts +0 -0
  183. /package/{components → src/components}/RadioGroup/RadioGroup.d.ts +0 -0
  184. /package/{components → src/components}/RadioGroup/RadioGroup.definitions.d.ts +0 -0
  185. /package/{components → src/components}/RadioGroup/RadioGroup.sx.d.ts +0 -0
  186. /package/{components → src/components}/RadioGroup/index.d.ts +0 -0
  187. /package/{components → src/components}/Select/Select.d.ts +0 -0
  188. /package/{components → src/components}/Select/Select.helpers.d.ts +0 -0
  189. /package/{components → src/components}/Select/Select.sx.d.ts +0 -0
  190. /package/{components → src/components}/Select/_parts/SelectMenuItem.d.ts +0 -0
  191. /package/{components → src/components}/Select/_parts/SelectValue.d.ts +0 -0
  192. /package/{components → src/components}/Select/index.d.ts +0 -0
  193. /package/{components → src/components}/Spinner/Spinner.d.ts +0 -0
  194. /package/{components → src/components}/Spinner/index.d.ts +0 -0
  195. /package/{components → src/components}/Stat/Stat.d.ts +0 -0
  196. /package/{components → src/components}/Stat/index.d.ts +0 -0
  197. /package/{components → src/components}/StatusMessage/StatusMessage.d.ts +0 -0
  198. /package/{components → src/components}/StatusMessage/index.d.ts +0 -0
  199. /package/{components → src/components}/Stepper/Step.d.ts +0 -0
  200. /package/{components → src/components}/Stepper/Stepper.d.ts +0 -0
  201. /package/{components → src/components}/Stepper/Stepper.definition.d.ts +0 -0
  202. /package/{components → src/components}/Stepper/StepperContext.d.ts +0 -0
  203. /package/{components → src/components}/Stepper/_hooks/useHorizontalScroll.d.ts +0 -0
  204. /package/{components → src/components}/Stepper/_parts/StepperScrollArrow.d.ts +0 -0
  205. /package/{components → src/components}/Stepper/index.d.ts +0 -0
  206. /package/{components → src/components}/Switch/Switch.d.ts +0 -0
  207. /package/{components → src/components}/Switch/Switch.definitions.d.ts +0 -0
  208. /package/{components → src/components}/Switch/Switch.sx.d.ts +0 -0
  209. /package/{components → src/components}/Switch/Switch.types.d.ts +0 -0
  210. /package/{components → src/components}/Switch/index.d.ts +0 -0
  211. /package/{components → src/components}/Table/Table.definition.d.ts +0 -0
  212. /package/{components → src/components}/Table/data.d.ts +0 -0
  213. /package/{components → src/components}/Table/exportsUtils.d.ts +0 -0
  214. /package/{components → src/components}/Table/index.d.ts +0 -0
  215. /package/{components → src/components}/Table/types.d.ts +0 -0
  216. /package/{components → src/components}/Tabs/Tab.d.ts +0 -0
  217. /package/{components → src/components}/Tabs/Tab.definition.d.ts +0 -0
  218. /package/{components → src/components}/Tabs/Tabs.d.ts +0 -0
  219. /package/{components → src/components}/Tabs/_tabUtils.d.ts +0 -0
  220. /package/{components → src/components}/Tabs/index.d.ts +0 -0
  221. /package/{components → src/components}/Timeline/Timeline.d.ts +0 -0
  222. /package/{components → src/components}/Timeline/Timeline.definition.d.ts +0 -0
  223. /package/{components → src/components}/Timeline/TimelineItem.d.ts +0 -0
  224. /package/{components → src/components}/Timeline/index.d.ts +0 -0
  225. /package/{components → src/components}/Tooltip/Tooltip.d.ts +0 -0
  226. /package/{components → src/components}/Tooltip/index.d.ts +0 -0
  227. /package/{components → src/components}/_shared/formField.sx.d.ts +0 -0
  228. /package/{components → src/components}/_shared/mergeSx.d.ts +0 -0
  229. /package/{components → src/components}/_shared/resolvePreset.d.ts +0 -0
  230. /package/{hooks → src/hooks}/ClipBoard/ClipBoard.d.ts +0 -0
  231. /package/{hooks → src/hooks}/ClipBoard/ClipboardUnifiedDemo.d.ts +0 -0
  232. /package/{hooks → src/hooks}/ClipBoard/index.d.ts +0 -0
  233. /package/{mui.d.ts → src/mui.d.ts} +0 -0
  234. /package/{theme → src/theme}/tokens.d.ts +0 -0
  235. /package/{utils → src/utils}/index.d.ts +0 -0
  236. /package/{utils → src/utils}/scrollToTop.d.ts +0 -0
@@ -0,0 +1,55 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useTheme, Box, Typography } from "@mui/material";
3
+ import { r as resolvePreset } from "./resolvePreset-K6_BfWHD.js";
4
+ function DataRow({
5
+ label,
6
+ children,
7
+ last,
8
+ labelWidth = 200,
9
+ preset,
10
+ sx,
11
+ className,
12
+ "data-testid": dataTestId
13
+ }) {
14
+ const theme = useTheme();
15
+ const presetSx = resolvePreset("DataRow", preset, theme);
16
+ const rootSx = [
17
+ {
18
+ display: "flex",
19
+ flexDirection: { xs: "column", sm: "row" },
20
+ alignItems: { xs: "flex-start", sm: "center" },
21
+ gap: { xs: 0.5, sm: 2 },
22
+ mb: last ? 0 : 2.5
23
+ },
24
+ ...presetSx ? [presetSx] : [],
25
+ ...Array.isArray(sx) ? sx : sx ? [sx] : []
26
+ ];
27
+ return /* @__PURE__ */ jsxs(Box, { sx: rootSx, className, "data-testid": dataTestId, children: [
28
+ /* @__PURE__ */ jsx(
29
+ Typography,
30
+ {
31
+ variant: "body2",
32
+ component: "label",
33
+ className: "fri-DataRow-label",
34
+ sx: { width: { sm: labelWidth }, flexShrink: 0, color: "text.secondary" },
35
+ children: label
36
+ }
37
+ ),
38
+ typeof children === "string" ? /* @__PURE__ */ jsx(Typography, { variant: "body1", component: "span", className: "fri-DataRow-value", children }) : (
39
+ // El slot de valor crece: así un Input en modo edición ocupa el ancho
40
+ // restante y un Chip conserva su tamaño (es inline-flex).
41
+ /* @__PURE__ */ jsx(
42
+ Box,
43
+ {
44
+ className: "fri-DataRow-value",
45
+ sx: { flex: 1, minWidth: 0, width: { xs: "100%", sm: "auto" } },
46
+ children
47
+ }
48
+ )
49
+ )
50
+ ] });
51
+ }
52
+ export {
53
+ DataRow as D
54
+ };
55
+ //# sourceMappingURL=DataRow-B7fJ5taA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataRow-B7fJ5taA.js","sources":["../src/components/DataRow/DataRow.tsx"],"sourcesContent":["import { type ReactNode } from 'react';\nimport { Box, Typography, useTheme } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\n\nimport { resolvePreset } from '../_shared/resolvePreset';\n\nexport interface DataRowProps {\n /** Etiqueta del dato (columna izquierda). */\n label: ReactNode;\n /** Valor: texto, o cualquier nodo (chip, link, Input en modo edición). */\n children: ReactNode;\n /** Última fila de un bloque: sin margen inferior. */\n last?: boolean;\n /**\n * Ancho de la columna del label a partir de `sm`. Default `200`.\n * Fijo a propósito: alinea verticalmente todos los valores de un bloque.\n */\n labelWidth?: number | string;\n /** Preset registrado en `theme.styles.DataRow`. */\n preset?: string;\n sx?: SxProps<Theme>;\n className?: string;\n 'data-testid'?: string;\n}\n\n/**\n * Fila label/valor — el patrón de dato para vistas de detalle.\n *\n * Geometría: label de ancho fijo + valor al lado; en móvil apila. El ancho fijo\n * (en vez de un `Grid` 4/8) evita que en una card full-width queden cientos de\n * px muertos entre label y valor.\n *\n * Tipografía: el paquete pone `body2`/`body1`. Para mapear a variantes propias\n * del consumidor, registrar un preset en el theme apuntando a las clases\n * internas:\n *\n * ```ts\n * styles: {\n * DataRow: {\n * default: {\n * '& .fri-DataRow-label': { typography: 'dataLabel' },\n * '& .fri-DataRow-value': { typography: 'dataValue' },\n * },\n * },\n * }\n * ```\n */\nexport function DataRow({\n label,\n children,\n last,\n labelWidth = 200,\n preset,\n sx,\n className,\n 'data-testid': dataTestId,\n}: DataRowProps) {\n const theme = useTheme();\n const presetSx = resolvePreset('DataRow', preset, theme);\n\n const rootSx: SxProps<Theme> = [\n {\n display: 'flex',\n flexDirection: { xs: 'column', sm: 'row' },\n alignItems: { xs: 'flex-start', sm: 'center' },\n gap: { xs: 0.5, sm: 2 },\n mb: last ? 0 : 2.5,\n },\n ...(presetSx ? [presetSx] : []),\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ] as SxProps<Theme>;\n\n return (\n <Box sx={rootSx} className={className} data-testid={dataTestId}>\n <Typography\n variant=\"body2\"\n component=\"label\"\n className=\"fri-DataRow-label\"\n sx={{ width: { sm: labelWidth }, flexShrink: 0, color: 'text.secondary' }}\n >\n {label}\n </Typography>\n {typeof children === 'string' ? (\n <Typography variant=\"body1\" component=\"span\" className=\"fri-DataRow-value\">\n {children}\n </Typography>\n ) : (\n // El slot de valor crece: así un Input en modo edición ocupa el ancho\n // restante y un Chip conserva su tamaño (es inline-flex).\n <Box\n className=\"fri-DataRow-value\"\n sx={{ flex: 1, minWidth: 0, width: { xs: '100%', sm: 'auto' } }}\n >\n {children}\n </Box>\n )}\n </Box>\n );\n}\n\nexport default DataRow;\n"],"names":[],"mappings":";;;AA+CO,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,GAAiB;AACf,QAAM,QAAQ,SAAA;AACd,QAAM,WAAW,cAAc,WAAW,QAAQ,KAAK;AAEvD,QAAM,SAAyB;AAAA,IAC7B;AAAA,MACE,SAAS;AAAA,MACT,eAAe,EAAE,IAAI,UAAU,IAAI,MAAA;AAAA,MACnC,YAAY,EAAE,IAAI,cAAc,IAAI,SAAA;AAAA,MACpC,KAAK,EAAE,IAAI,KAAK,IAAI,EAAA;AAAA,MACpB,IAAI,OAAO,IAAI;AAAA,IAAA;AAAA,IAEjB,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAA;AAAA,IAC5B,GAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,KAAK,CAAC,EAAE,IAAI,CAAA;AAAA,EAAC;AAG5C,8BACG,KAAA,EAAI,IAAI,QAAQ,WAAsB,eAAa,YAClD,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,WAAU;AAAA,QACV,WAAU;AAAA,QACV,IAAI,EAAE,OAAO,EAAE,IAAI,cAAc,YAAY,GAAG,OAAO,iBAAA;AAAA,QAEtD,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEF,OAAO,aAAa,WACnB,oBAAC,YAAA,EAAW,SAAQ,SAAQ,WAAU,QAAO,WAAU,qBACpD,SAAA,CACH;AAAA;AAAA;AAAA,MAIA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,EAAE,IAAI,QAAQ,IAAI,OAAA,EAAO;AAAA,UAE3D;AAAA,QAAA;AAAA,MAAA;AAAA;AAAA,EACH,GAEJ;AAEJ;"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ const jsxRuntime = require("react/jsx-runtime");
3
+ const material = require("@mui/material");
4
+ const resolvePreset = require("./resolvePreset-CxTI6_Ln.cjs");
5
+ function DataRow({
6
+ label,
7
+ children,
8
+ last,
9
+ labelWidth = 200,
10
+ preset,
11
+ sx,
12
+ className,
13
+ "data-testid": dataTestId
14
+ }) {
15
+ const theme = material.useTheme();
16
+ const presetSx = resolvePreset.resolvePreset("DataRow", preset, theme);
17
+ const rootSx = [
18
+ {
19
+ display: "flex",
20
+ flexDirection: { xs: "column", sm: "row" },
21
+ alignItems: { xs: "flex-start", sm: "center" },
22
+ gap: { xs: 0.5, sm: 2 },
23
+ mb: last ? 0 : 2.5
24
+ },
25
+ ...presetSx ? [presetSx] : [],
26
+ ...Array.isArray(sx) ? sx : sx ? [sx] : []
27
+ ];
28
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: rootSx, className, "data-testid": dataTestId, children: [
29
+ /* @__PURE__ */ jsxRuntime.jsx(
30
+ material.Typography,
31
+ {
32
+ variant: "body2",
33
+ component: "label",
34
+ className: "fri-DataRow-label",
35
+ sx: { width: { sm: labelWidth }, flexShrink: 0, color: "text.secondary" },
36
+ children: label
37
+ }
38
+ ),
39
+ typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body1", component: "span", className: "fri-DataRow-value", children }) : (
40
+ // El slot de valor crece: así un Input en modo edición ocupa el ancho
41
+ // restante y un Chip conserva su tamaño (es inline-flex).
42
+ /* @__PURE__ */ jsxRuntime.jsx(
43
+ material.Box,
44
+ {
45
+ className: "fri-DataRow-value",
46
+ sx: { flex: 1, minWidth: 0, width: { xs: "100%", sm: "auto" } },
47
+ children
48
+ }
49
+ )
50
+ )
51
+ ] });
52
+ }
53
+ exports.DataRow = DataRow;
54
+ //# sourceMappingURL=DataRow-CfCaSdaJ.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DataRow-CfCaSdaJ.cjs","sources":["../src/components/DataRow/DataRow.tsx"],"sourcesContent":["import { type ReactNode } from 'react';\nimport { Box, Typography, useTheme } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\n\nimport { resolvePreset } from '../_shared/resolvePreset';\n\nexport interface DataRowProps {\n /** Etiqueta del dato (columna izquierda). */\n label: ReactNode;\n /** Valor: texto, o cualquier nodo (chip, link, Input en modo edición). */\n children: ReactNode;\n /** Última fila de un bloque: sin margen inferior. */\n last?: boolean;\n /**\n * Ancho de la columna del label a partir de `sm`. Default `200`.\n * Fijo a propósito: alinea verticalmente todos los valores de un bloque.\n */\n labelWidth?: number | string;\n /** Preset registrado en `theme.styles.DataRow`. */\n preset?: string;\n sx?: SxProps<Theme>;\n className?: string;\n 'data-testid'?: string;\n}\n\n/**\n * Fila label/valor — el patrón de dato para vistas de detalle.\n *\n * Geometría: label de ancho fijo + valor al lado; en móvil apila. El ancho fijo\n * (en vez de un `Grid` 4/8) evita que en una card full-width queden cientos de\n * px muertos entre label y valor.\n *\n * Tipografía: el paquete pone `body2`/`body1`. Para mapear a variantes propias\n * del consumidor, registrar un preset en el theme apuntando a las clases\n * internas:\n *\n * ```ts\n * styles: {\n * DataRow: {\n * default: {\n * '& .fri-DataRow-label': { typography: 'dataLabel' },\n * '& .fri-DataRow-value': { typography: 'dataValue' },\n * },\n * },\n * }\n * ```\n */\nexport function DataRow({\n label,\n children,\n last,\n labelWidth = 200,\n preset,\n sx,\n className,\n 'data-testid': dataTestId,\n}: DataRowProps) {\n const theme = useTheme();\n const presetSx = resolvePreset('DataRow', preset, theme);\n\n const rootSx: SxProps<Theme> = [\n {\n display: 'flex',\n flexDirection: { xs: 'column', sm: 'row' },\n alignItems: { xs: 'flex-start', sm: 'center' },\n gap: { xs: 0.5, sm: 2 },\n mb: last ? 0 : 2.5,\n },\n ...(presetSx ? [presetSx] : []),\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ] as SxProps<Theme>;\n\n return (\n <Box sx={rootSx} className={className} data-testid={dataTestId}>\n <Typography\n variant=\"body2\"\n component=\"label\"\n className=\"fri-DataRow-label\"\n sx={{ width: { sm: labelWidth }, flexShrink: 0, color: 'text.secondary' }}\n >\n {label}\n </Typography>\n {typeof children === 'string' ? (\n <Typography variant=\"body1\" component=\"span\" className=\"fri-DataRow-value\">\n {children}\n </Typography>\n ) : (\n // El slot de valor crece: así un Input en modo edición ocupa el ancho\n // restante y un Chip conserva su tamaño (es inline-flex).\n <Box\n className=\"fri-DataRow-value\"\n sx={{ flex: 1, minWidth: 0, width: { xs: '100%', sm: 'auto' } }}\n >\n {children}\n </Box>\n )}\n </Box>\n );\n}\n\nexport default DataRow;\n"],"names":["useTheme","resolvePreset","Box","jsx","Typography"],"mappings":";;;;AA+CO,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,GAAiB;AACf,QAAM,QAAQA,SAAAA,SAAA;AACd,QAAM,WAAWC,cAAAA,cAAc,WAAW,QAAQ,KAAK;AAEvD,QAAM,SAAyB;AAAA,IAC7B;AAAA,MACE,SAAS;AAAA,MACT,eAAe,EAAE,IAAI,UAAU,IAAI,MAAA;AAAA,MACnC,YAAY,EAAE,IAAI,cAAc,IAAI,SAAA;AAAA,MACpC,KAAK,EAAE,IAAI,KAAK,IAAI,EAAA;AAAA,MACpB,IAAI,OAAO,IAAI;AAAA,IAAA;AAAA,IAEjB,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAA;AAAA,IAC5B,GAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,KAAK,CAAC,EAAE,IAAI,CAAA;AAAA,EAAC;AAG5C,yCACGC,SAAAA,KAAA,EAAI,IAAI,QAAQ,WAAsB,eAAa,YAClD,UAAA;AAAA,IAAAC,2BAAAA;AAAAA,MAACC,SAAAA;AAAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,WAAU;AAAA,QACV,WAAU;AAAA,QACV,IAAI,EAAE,OAAO,EAAE,IAAI,cAAc,YAAY,GAAG,OAAO,iBAAA;AAAA,QAEtD,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEF,OAAO,aAAa,WACnBD,+BAACC,SAAAA,YAAA,EAAW,SAAQ,SAAQ,WAAU,QAAO,WAAU,qBACpD,SAAA,CACH;AAAA;AAAA;AAAA,MAIAD,2BAAAA;AAAAA,QAACD,SAAAA;AAAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,EAAE,IAAI,QAAQ,IAAI,OAAA,EAAO;AAAA,UAE3D;AAAA,QAAA;AAAA,MAAA;AAAA;AAAA,EACH,GAEJ;AAEJ;;"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ const jsxRuntime = require("react/jsx-runtime");
3
+ const material = require("@mui/material");
4
+ const resolvePreset = require("./resolvePreset-CxTI6_Ln.cjs");
5
+ function EmptyState({
6
+ title,
7
+ message,
8
+ icon,
9
+ action,
10
+ preset,
11
+ sx,
12
+ className,
13
+ "data-testid": dataTestId
14
+ }) {
15
+ const theme = material.useTheme();
16
+ const presetSx = resolvePreset.resolvePreset("EmptyState", preset, theme);
17
+ const rootSx = [
18
+ {
19
+ display: "flex",
20
+ flexDirection: "column",
21
+ alignItems: "center",
22
+ justifyContent: "center",
23
+ py: 8,
24
+ px: 3,
25
+ textAlign: "center",
26
+ color: "text.secondary"
27
+ },
28
+ ...presetSx ? [presetSx] : [],
29
+ ...Array.isArray(sx) ? sx : sx ? [sx] : []
30
+ ];
31
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: rootSx, className, "data-testid": dataTestId, children: [
32
+ icon,
33
+ /* @__PURE__ */ jsxRuntime.jsx(
34
+ material.Typography,
35
+ {
36
+ variant: "subtitle1",
37
+ className: "fri-EmptyState-title",
38
+ sx: { fontWeight: 600, color: "text.primary", mt: icon ? 2 : 0 },
39
+ children: title
40
+ }
41
+ ),
42
+ message && /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "body2", className: "fri-EmptyState-message", sx: { mt: 0.5 }, children: message }),
43
+ action && /* @__PURE__ */ jsxRuntime.jsx(material.Box, { sx: { mt: 3 }, children: action })
44
+ ] });
45
+ }
46
+ exports.EmptyState = EmptyState;
47
+ //# sourceMappingURL=EmptyState-DJj9KOEy.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState-DJj9KOEy.cjs","sources":["../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["import { type ReactNode } from 'react';\nimport { Box, Typography, useTheme } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\n\nimport { resolvePreset } from '../_shared/resolvePreset';\n\nexport interface EmptyStateProps {\n /** Qué falta, en positivo: \"Sin dispositivos registrados\". */\n title: string;\n /** Línea secundaria opcional: qué puede hacer el usuario. */\n message?: string;\n /** Icono o ilustración arriba del título. */\n icon?: ReactNode;\n /** Acción opcional (botón) debajo del mensaje. */\n action?: ReactNode;\n /** Preset registrado en `theme.styles.EmptyState`. */\n preset?: string;\n sx?: SxProps<Theme>;\n className?: string;\n 'data-testid'?: string;\n}\n\n/**\n * Estado vacío centrado, para usar dentro de una card, un tab o una tabla sin\n * resultados. Color y tipografía salen del theme del consumidor: no hay\n * hex ni tamaños hardcodeados.\n */\nexport function EmptyState({\n title,\n message,\n icon,\n action,\n preset,\n sx,\n className,\n 'data-testid': dataTestId,\n}: EmptyStateProps) {\n const theme = useTheme();\n const presetSx = resolvePreset('EmptyState', preset, theme);\n\n const rootSx: SxProps<Theme> = [\n {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n py: 8,\n px: 3,\n textAlign: 'center',\n color: 'text.secondary',\n },\n ...(presetSx ? [presetSx] : []),\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ] as SxProps<Theme>;\n\n return (\n <Box sx={rootSx} className={className} data-testid={dataTestId}>\n {icon}\n <Typography\n variant=\"subtitle1\"\n className=\"fri-EmptyState-title\"\n sx={{ fontWeight: 600, color: 'text.primary', mt: icon ? 2 : 0 }}\n >\n {title}\n </Typography>\n {message && (\n <Typography variant=\"body2\" className=\"fri-EmptyState-message\" sx={{ mt: 0.5 }}>\n {message}\n </Typography>\n )}\n {action && <Box sx={{ mt: 3 }}>{action}</Box>}\n </Box>\n );\n}\n\nexport default EmptyState;\n"],"names":["useTheme","resolvePreset","Box","jsx","Typography"],"mappings":";;;;AA2BO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,GAAoB;AAClB,QAAM,QAAQA,SAAAA,SAAA;AACd,QAAM,WAAWC,cAAAA,cAAc,cAAc,QAAQ,KAAK;AAE1D,QAAM,SAAyB;AAAA,IAC7B;AAAA,MACE,SAAS;AAAA,MACT,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,WAAW;AAAA,MACX,OAAO;AAAA,IAAA;AAAA,IAET,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAA;AAAA,IAC5B,GAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,KAAK,CAAC,EAAE,IAAI,CAAA;AAAA,EAAC;AAG5C,yCACGC,SAAAA,KAAA,EAAI,IAAI,QAAQ,WAAsB,eAAa,YACjD,UAAA;AAAA,IAAA;AAAA,IACDC,2BAAAA;AAAAA,MAACC,SAAAA;AAAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,WAAU;AAAA,QACV,IAAI,EAAE,YAAY,KAAK,OAAO,gBAAgB,IAAI,OAAO,IAAI,EAAA;AAAA,QAE5D,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEF,WACCD,2BAAAA,IAACC,SAAAA,YAAA,EAAW,SAAQ,SAAQ,WAAU,0BAAyB,IAAI,EAAE,IAAI,IAAA,GACtE,UAAA,QAAA,CACH;AAAA,IAED,yCAAWF,SAAAA,KAAA,EAAI,IAAI,EAAE,IAAI,EAAA,GAAM,UAAA,OAAA,CAAO;AAAA,EAAA,GACzC;AAEJ;;"}
@@ -0,0 +1,48 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useTheme, Box, Typography } from "@mui/material";
3
+ import { r as resolvePreset } from "./resolvePreset-K6_BfWHD.js";
4
+ function EmptyState({
5
+ title,
6
+ message,
7
+ icon,
8
+ action,
9
+ preset,
10
+ sx,
11
+ className,
12
+ "data-testid": dataTestId
13
+ }) {
14
+ const theme = useTheme();
15
+ const presetSx = resolvePreset("EmptyState", preset, theme);
16
+ const rootSx = [
17
+ {
18
+ display: "flex",
19
+ flexDirection: "column",
20
+ alignItems: "center",
21
+ justifyContent: "center",
22
+ py: 8,
23
+ px: 3,
24
+ textAlign: "center",
25
+ color: "text.secondary"
26
+ },
27
+ ...presetSx ? [presetSx] : [],
28
+ ...Array.isArray(sx) ? sx : sx ? [sx] : []
29
+ ];
30
+ return /* @__PURE__ */ jsxs(Box, { sx: rootSx, className, "data-testid": dataTestId, children: [
31
+ icon,
32
+ /* @__PURE__ */ jsx(
33
+ Typography,
34
+ {
35
+ variant: "subtitle1",
36
+ className: "fri-EmptyState-title",
37
+ sx: { fontWeight: 600, color: "text.primary", mt: icon ? 2 : 0 },
38
+ children: title
39
+ }
40
+ ),
41
+ message && /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "fri-EmptyState-message", sx: { mt: 0.5 }, children: message }),
42
+ action && /* @__PURE__ */ jsx(Box, { sx: { mt: 3 }, children: action })
43
+ ] });
44
+ }
45
+ export {
46
+ EmptyState as E
47
+ };
48
+ //# sourceMappingURL=EmptyState-kEoDkg1B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyState-kEoDkg1B.js","sources":["../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["import { type ReactNode } from 'react';\nimport { Box, Typography, useTheme } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\n\nimport { resolvePreset } from '../_shared/resolvePreset';\n\nexport interface EmptyStateProps {\n /** Qué falta, en positivo: \"Sin dispositivos registrados\". */\n title: string;\n /** Línea secundaria opcional: qué puede hacer el usuario. */\n message?: string;\n /** Icono o ilustración arriba del título. */\n icon?: ReactNode;\n /** Acción opcional (botón) debajo del mensaje. */\n action?: ReactNode;\n /** Preset registrado en `theme.styles.EmptyState`. */\n preset?: string;\n sx?: SxProps<Theme>;\n className?: string;\n 'data-testid'?: string;\n}\n\n/**\n * Estado vacío centrado, para usar dentro de una card, un tab o una tabla sin\n * resultados. Color y tipografía salen del theme del consumidor: no hay\n * hex ni tamaños hardcodeados.\n */\nexport function EmptyState({\n title,\n message,\n icon,\n action,\n preset,\n sx,\n className,\n 'data-testid': dataTestId,\n}: EmptyStateProps) {\n const theme = useTheme();\n const presetSx = resolvePreset('EmptyState', preset, theme);\n\n const rootSx: SxProps<Theme> = [\n {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n py: 8,\n px: 3,\n textAlign: 'center',\n color: 'text.secondary',\n },\n ...(presetSx ? [presetSx] : []),\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ] as SxProps<Theme>;\n\n return (\n <Box sx={rootSx} className={className} data-testid={dataTestId}>\n {icon}\n <Typography\n variant=\"subtitle1\"\n className=\"fri-EmptyState-title\"\n sx={{ fontWeight: 600, color: 'text.primary', mt: icon ? 2 : 0 }}\n >\n {title}\n </Typography>\n {message && (\n <Typography variant=\"body2\" className=\"fri-EmptyState-message\" sx={{ mt: 0.5 }}>\n {message}\n </Typography>\n )}\n {action && <Box sx={{ mt: 3 }}>{action}</Box>}\n </Box>\n );\n}\n\nexport default EmptyState;\n"],"names":[],"mappings":";;;AA2BO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,GAAoB;AAClB,QAAM,QAAQ,SAAA;AACd,QAAM,WAAW,cAAc,cAAc,QAAQ,KAAK;AAE1D,QAAM,SAAyB;AAAA,IAC7B;AAAA,MACE,SAAS;AAAA,MACT,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,WAAW;AAAA,MACX,OAAO;AAAA,IAAA;AAAA,IAET,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAA;AAAA,IAC5B,GAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,KAAK,CAAC,EAAE,IAAI,CAAA;AAAA,EAAC;AAG5C,8BACG,KAAA,EAAI,IAAI,QAAQ,WAAsB,eAAa,YACjD,UAAA;AAAA,IAAA;AAAA,IACD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,WAAU;AAAA,QACV,IAAI,EAAE,YAAY,KAAK,OAAO,gBAAgB,IAAI,OAAO,IAAI,EAAA;AAAA,QAE5D,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEF,WACC,oBAAC,YAAA,EAAW,SAAQ,SAAQ,WAAU,0BAAyB,IAAI,EAAE,IAAI,IAAA,GACtE,UAAA,QAAA,CACH;AAAA,IAED,8BAAW,KAAA,EAAI,IAAI,EAAE,IAAI,EAAA,GAAM,UAAA,OAAA,CAAO;AAAA,EAAA,GACzC;AAEJ;"}
@@ -333,7 +333,17 @@ const Modal = forwardRef(
333
333
  "aria-describedby": descId,
334
334
  closeAfterTransition: true,
335
335
  sx,
336
- children: /* @__PURE__ */ jsx(Paper, { className, sx: mergedPaperSx, "data-testid": dataTestId, children: renderChildren() })
336
+ children: /* @__PURE__ */ jsx(
337
+ Paper,
338
+ {
339
+ role: "dialog",
340
+ "aria-modal": "true",
341
+ className,
342
+ sx: mergedPaperSx,
343
+ "data-testid": dataTestId,
344
+ children: renderChildren()
345
+ }
346
+ )
337
347
  }
338
348
  );
339
349
  }
@@ -349,4 +359,4 @@ export {
349
359
  ModalBody as b,
350
360
  ModalFooter as c
351
361
  };
352
- //# sourceMappingURL=Modal-C_QY7ZzY.js.map
362
+ //# sourceMappingURL=Modal-BqW0Nk3l.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Modal-C_QY7ZzY.js","sources":["../src/components/Modal/ModalFooter.tsx","../src/components/Modal/ModalHeader.tsx","../src/components/Modal/ModalBody.tsx","../src/components/Modal/Modal.tsx"],"sourcesContent":["import React from 'react';\nimport { Box, Stack } from '@mui/material';\nimport type { ButtonProps as MuiButtonProps } from '@mui/material/Button';\n\nimport { Button } from '../Button';\n\n// Interfaz para acciones personalizadas (se mantiene aquí)\nexport interface ModalAction {\n text: string;\n onClick?: () => void;\n disabled?: boolean;\n variant?: MuiButtonProps['variant'];\n color?: MuiButtonProps['color'];\n /**\n * Props adicionales que se forwardean al `<Button>` interno. Útil para casos\n * avanzados como conectar el botón con un `<form id=\"...\">` externo usando\n * `buttonProps={{ type: 'submit', form: 'my-form-id' }}`.\n */\n buttonProps?: Partial<MuiButtonProps> & { form?: string };\n}\n\nexport interface ModalFooterProps {\n children?: React.ReactNode;\n showCloseButton?: boolean;\n closeButtonText?: string;\n closeButtonDisabled?: boolean;\n onClose: () => void;\n actions?: ModalAction[];\n}\n\nexport const ModalFooter: React.FC<ModalFooterProps> = ({\n children,\n showCloseButton = true,\n closeButtonText = 'Cerrar',\n closeButtonDisabled = false,\n onClose,\n actions = [],\n}) => {\n return (\n <Box\n sx={{\n padding: 2,\n borderTop: (theme) => `1px solid ${theme.palette.divider}`,\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 1,\n }}\n >\n {children}\n <Stack direction=\"row\" spacing={1}>\n {showCloseButton && (\n <Button\n onClick={onClose}\n disabled={closeButtonDisabled}\n variant=\"outlined\"\n color=\"secondary\"\n >\n {closeButtonText}\n </Button>\n )}\n {actions.map((action) => {\n const { buttonProps, text, onClick, disabled, variant, color } = action;\n return (\n <Button\n key={text}\n onClick={onClick}\n disabled={disabled}\n variant={variant || 'contained'}\n color={color || 'primary'}\n {...(buttonProps as any)}\n >\n {text}\n </Button>\n );\n })}\n </Stack>\n </Box>\n );\n};\n\nModalFooter.displayName = 'ModalFooter';\n\nexport default ModalFooter;\n","import React from 'react';\nimport { Box, Typography } from '@mui/material';\n\nexport interface ModalHeaderProps {\n children: React.ReactNode;\n /**\n * ID del elemento — usado para `aria-labelledby` del Modal. Se setea\n * automáticamente cuando el header se renderiza dentro de `<Modal>`.\n */\n id?: string;\n}\n\nexport const ModalHeader: React.FC<ModalHeaderProps> = ({ children, id }) => {\n return (\n <Box\n sx={{\n padding: 2,\n borderBottom: (theme) => `1px solid ${theme.palette.divider}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n <Typography id={id} variant=\"h6\" component=\"h2\">\n {children}\n </Typography>\n </Box>\n );\n};\n\nModalHeader.displayName = 'ModalHeader';\n\nexport default ModalHeader;\n","import React from 'react';\nimport { Box } from '@mui/material';\n\nexport interface ModalBodyProps {\n children: React.ReactNode;\n /**\n * ID del elemento — usado para `aria-describedby` del Modal. Se setea\n * automáticamente cuando el body se renderiza dentro de `<Modal>`.\n */\n id?: string;\n}\n\nexport const ModalBody: React.FC<ModalBodyProps> = ({ children, id }) => {\n return (\n <Box id={id} sx={{ padding: 2, overflowY: 'auto', flexGrow: 1 }}>\n {children}\n </Box>\n );\n};\n\nModalBody.displayName = 'ModalBody';\n\nexport default ModalBody;\n","import {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n useId,\n useImperativeHandle,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport {\n Modal as MuiModal,\n Paper,\n useMediaQuery,\n useTheme,\n Box,\n Stack,\n Typography,\n} from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';\nimport WarningAmberIcon from '@mui/icons-material/WarningAmber';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';\nimport CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';\n\nimport type { DialogProps } from '@mui/material/Dialog';\nimport { ModalFooter, type ModalAction, type ModalFooterProps } from './ModalFooter';\nimport { ModalHeader } from './ModalHeader';\nimport { ModalBody } from './ModalBody';\nimport { mergeSx } from '../_shared/mergeSx';\n\n// Detección robusta de sub-componentes — funciona con wrappers / HMR que\n// rompen la igualdad de referencia (`child.type === ModalHeader`).\nconst isModalSlot = (\n child: ReactElement,\n Component: unknown,\n displayName: string,\n): boolean => {\n if (child.type === Component) return true;\n const type = child.type as { displayName?: string };\n return type?.displayName === displayName;\n};\n\n// Define la interfaz para los métodos que el padre puede llamar a través de la ref\nexport interface ModalRef {\n open: () => void;\n close: () => void;\n}\n\nexport type ModalMode = 'default' | 'confirm';\nexport type ModalSeverity = 'info' | 'warning' | 'error' | 'success';\n\nexport interface ModalProps {\n /**\n * Modo del modal.\n * - `default` (default): modal genérico con slots `Header`/`Body`/`Footer` y\n * `actions` custom.\n * - `confirm`: reemplaza al `ConfirmModal` legacy. Renderiza un layout\n * focalizado con icono por severidad, mensaje y botones \"Cancelar\" /\n * \"Confirmar\".\n */\n mode?: ModalMode;\n\n // ── Props comunes ────────────────────────────────────────────────────\n /** Controlado externamente. Omitir si se usa vía ref. */\n open?: boolean;\n /** Callback al cerrar. También se dispara al confirmar/cancelar. */\n onClose?: () => void;\n title?: string;\n children?: ReactNode;\n showCloseButton?: boolean;\n closeButtonText?: string;\n closeButtonDisabled?: boolean;\n actions?: ModalAction[];\n maxWidth?: DialogProps['maxWidth'];\n /**\n * Si `true`, el modal NO se cierra al hacer click en el backdrop ni con Escape\n * (equivale a `backdrop=\"static\"`). Cerrar solo vía botón/acción.\n */\n staticBackdrop?: boolean;\n /** Test id aplicado al Paper interno (contenedor visual). */\n 'data-testid'?: string;\n /** Oculta el header (incluso si hay `title` o se pasa un `<Modal.Header>`). */\n hiddenHeader?: boolean;\n /** Oculta el body (incluso si se pasa un `<Modal.Body>`). */\n hiddenBody?: boolean;\n /** Oculta el footer (incluso si se pasa un `<Modal.Footer>` o `actions`). */\n hiddenFooter?: boolean;\n /** sx del Modal root (MuiModal). */\n sx?: SxProps<Theme>;\n /** sx del Paper interno (contenedor visual). Se mergea sobre el default. */\n paperSx?: SxProps<Theme>;\n /** className del Paper interno. */\n className?: string;\n\n // ── Props del modo confirm ───────────────────────────────────────────\n /**\n * Callback de confirmación. Soporta promesa — si devuelve `Promise`, el\n * botón muestra estado `disabled` mientras resuelve.\n *\n * Si la promesa **rechaza**, el modal queda abierto para que el consumer\n * pueda mostrar el error en su UI. El modal se cierra solo en éxito.\n */\n onConfirm?: () => void | Promise<void>;\n /** Texto del botón primario en modo `confirm`. Default: \"Confirmar\". */\n confirmText?: string;\n /** Deshabilita el botón de confirmar. */\n confirmDisabled?: boolean;\n /**\n * Severidad visual en modo `confirm`. Controla el icono y el color del\n * botón de confirmación.\n * - `info` (default): primary\n * - `warning`: warning (amarillo)\n * - `error`: error (rojo) — típico para \"Eliminar\"\n * - `success`: success (verde) — típico para \"Aprobar\"\n */\n severity?: ModalSeverity;\n /**\n * Mensaje del confirm. Puede ser string o cualquier ReactNode. Si se omite,\n * se usa `children`.\n */\n confirmMessage?: ReactNode;\n}\n\nconst modalStyle = {\n position: 'absolute' as const,\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: '90%',\n maxHeight: '90vh',\n display: 'flex',\n flexDirection: 'column' as const,\n outline: 'none',\n};\n\nconst severityConfig: Record<\n ModalSeverity,\n { color: ModalAction['color']; icon: ReactNode; paletteKey: 'primary' | 'warning' | 'error' | 'success' }\n> = {\n info: {\n color: 'primary',\n icon: <InfoOutlinedIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'primary',\n },\n warning: {\n color: 'warning',\n icon: <WarningAmberIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'warning',\n },\n error: {\n color: 'error',\n icon: <ErrorOutlineIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'error',\n },\n success: {\n color: 'success',\n icon: <CheckCircleOutlineIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'success',\n },\n};\n\nexport const Modal = forwardRef<ModalRef, ModalProps>(\n (\n {\n mode = 'default',\n open: controlledOpen,\n onClose: controlledOnClose,\n title,\n children,\n showCloseButton = true,\n closeButtonText = 'Cerrar',\n closeButtonDisabled = false,\n actions = [],\n maxWidth = 'sm',\n hiddenHeader = false,\n hiddenBody = false,\n hiddenFooter = false,\n staticBackdrop = false,\n 'data-testid': dataTestId,\n sx,\n paperSx,\n className,\n\n // Props del modo confirm\n onConfirm,\n confirmText = 'Confirmar',\n confirmDisabled = false,\n severity = 'info',\n confirmMessage,\n },\n ref,\n ) => {\n const [internalOpen, setInternalOpen] = useState(false);\n const [confirmLoading, setConfirmLoading] = useState(false);\n\n // IDs estables para a11y: `aria-labelledby` y `aria-describedby`.\n const titleId = useId();\n const descId = useId();\n\n const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;\n\n useImperativeHandle(ref, () => ({\n open: () => setInternalOpen(true),\n close: () => {\n setInternalOpen(false);\n controlledOnClose?.();\n },\n }));\n\n const handleCloseInternal = (\n _event?: object,\n reason?: 'backdropClick' | 'escapeKeyDown',\n ) => {\n // Backdrop estático: ignora cierres por click fuera o Escape.\n if (\n staticBackdrop &&\n (reason === 'backdropClick' || reason === 'escapeKeyDown')\n ) {\n return;\n }\n setInternalOpen(false);\n controlledOnClose?.();\n };\n\n const handleConfirm = async () => {\n if (!onConfirm) {\n handleCloseInternal();\n return;\n }\n const result = onConfirm();\n if (!(result instanceof Promise)) {\n handleCloseInternal();\n return;\n }\n setConfirmLoading(true);\n try {\n await result;\n handleCloseInternal();\n } catch (err) {\n // No cerrar el modal en caso de error — el consumer es responsable\n // de mostrar un estado de error en su UI. Logueamos para trazabilidad\n // en dev.\n // eslint-disable-next-line no-console\n console.error('Modal onConfirm failed:', err);\n } finally {\n setConfirmLoading(false);\n }\n };\n\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('sm'));\n\n const getWidth = () => {\n if (isMobile) return '95%';\n switch (maxWidth) {\n case 'xs':\n return 300;\n case 'sm':\n return 500;\n case 'md':\n return 700;\n case 'lg':\n return 900;\n case 'xl':\n return 1100;\n case false:\n return 'auto';\n default:\n // Soporta string custom: `maxWidth=\"600px\"` se pasa tal cual.\n return typeof maxWidth === 'string' ? maxWidth : 500;\n }\n };\n\n // Base sx del Paper + width responsive; el consumer puede pisarlos via `paperSx`.\n const paperBaseSx: SxProps<Theme> = { ...modalStyle, width: getWidth() };\n const mergedPaperSx = mergeSx(paperBaseSx, paperSx);\n\n // ── Render modo CONFIRM ─────────────────────────────────────────────\n if (mode === 'confirm') {\n const config = severityConfig[severity];\n const message = confirmMessage ?? children;\n\n return (\n <MuiModal\n open={isOpen}\n onClose={handleCloseInternal}\n aria-labelledby={title ? titleId : undefined}\n aria-describedby={message ? descId : undefined}\n closeAfterTransition\n sx={sx}\n >\n <Paper className={className} sx={mergedPaperSx} data-testid={dataTestId}>\n <Stack spacing={2.5} sx={{ p: 3, alignItems: 'center', textAlign: 'center' }}>\n <Box\n sx={{\n width: 72,\n height: 72,\n borderRadius: '50%',\n backgroundColor: (t) => t.palette[config.paletteKey].light,\n color: (t) => t.palette[config.paletteKey].dark,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n opacity: 0.9,\n }}\n >\n {config.icon}\n </Box>\n {title && (\n <Typography id={titleId} variant=\"h6\" component=\"h2\" sx={{ fontWeight: 700 }}>\n {title}\n </Typography>\n )}\n {message && (\n <Typography id={descId} variant=\"body2\" color=\"text.secondary\">\n {message}\n </Typography>\n )}\n </Stack>\n <ModalFooter\n showCloseButton={showCloseButton}\n closeButtonText={closeButtonText}\n closeButtonDisabled={closeButtonDisabled || confirmLoading}\n onClose={handleCloseInternal}\n actions={[\n {\n text: confirmText,\n onClick: handleConfirm,\n disabled: confirmDisabled || confirmLoading,\n variant: 'contained',\n color: config.color,\n },\n ]}\n />\n </Paper>\n </MuiModal>\n );\n }\n\n // ── Render modo DEFAULT (compuesto) ─────────────────────────────────\n const renderChildren = () => {\n let header: ReactNode | null = null;\n let body: ReactNode | null = null;\n let footer: ReactNode | null = null;\n\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n\n if (isModalSlot(child, ModalHeader, 'ModalHeader')) {\n const headerChild = child as ReactElement<{ id?: string }>;\n header = cloneElement(headerChild, { id: titleId, ...headerChild.props });\n } else if (isModalSlot(child, ModalBody, 'ModalBody')) {\n const bodyChild = child as ReactElement<{ id?: string }>;\n body = cloneElement(bodyChild, { id: descId, ...bodyChild.props });\n } else if (isModalSlot(child, ModalFooter, 'ModalFooter')) {\n const footerChild = child as ReactElement<ModalFooterProps>;\n // Props del child ganan sobre los del Modal padre: si el consumer\n // declara `<Modal.Footer showCloseButton={false}>`, ese valor se\n // respeta. Solo los que vengan `undefined` caen al default del padre.\n const childProps = footerChild.props;\n footer = cloneElement(footerChild, {\n showCloseButton: childProps.showCloseButton ?? showCloseButton,\n closeButtonText: childProps.closeButtonText ?? closeButtonText,\n closeButtonDisabled: childProps.closeButtonDisabled ?? closeButtonDisabled,\n onClose: childProps.onClose ?? handleCloseInternal,\n actions: childProps.actions ?? actions,\n });\n }\n });\n\n if (!footer && !hiddenFooter) {\n footer = (\n <ModalFooter\n showCloseButton={showCloseButton}\n closeButtonText={closeButtonText}\n closeButtonDisabled={closeButtonDisabled}\n onClose={handleCloseInternal}\n actions={actions}\n />\n );\n }\n\n return (\n <>\n {!hiddenHeader && (header || (title && <ModalHeader id={titleId}>{title}</ModalHeader>))}\n {!hiddenBody && body}\n {footer}\n </>\n );\n };\n\n return (\n <MuiModal\n open={isOpen}\n onClose={handleCloseInternal}\n aria-labelledby={titleId}\n aria-describedby={descId}\n closeAfterTransition\n sx={sx}\n >\n <Paper className={className} sx={mergedPaperSx} data-testid={dataTestId}>\n {renderChildren()}\n </Paper>\n </MuiModal>\n );\n },\n);\n\nModal.displayName = 'Modal';\n\n// Define los sub-componentes como propiedades estáticas con tipos explícitos\ntype ModalComponent = ReturnType<typeof forwardRef<ModalRef, ModalProps>> & {\n Header: typeof ModalHeader;\n Body: typeof ModalBody;\n Footer: typeof ModalFooter;\n};\n\nconst ModalWithStatics = Modal as ModalComponent;\n\nModalWithStatics.Header = ModalHeader;\nModalWithStatics.Body = ModalBody;\nModalWithStatics.Footer = ModalFooter;\n\nexport default ModalWithStatics;\n"],"names":["MuiModal"],"mappings":"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"}
1
+ {"version":3,"file":"Modal-BqW0Nk3l.js","sources":["../src/components/Modal/ModalFooter.tsx","../src/components/Modal/ModalHeader.tsx","../src/components/Modal/ModalBody.tsx","../src/components/Modal/Modal.tsx"],"sourcesContent":["import React from 'react';\nimport { Box, Stack } from '@mui/material';\nimport type { ButtonProps as MuiButtonProps } from '@mui/material/Button';\n\nimport { Button } from '../Button';\n\n// Interfaz para acciones personalizadas (se mantiene aquí)\nexport interface ModalAction {\n text: string;\n onClick?: () => void;\n disabled?: boolean;\n variant?: MuiButtonProps['variant'];\n color?: MuiButtonProps['color'];\n /**\n * Props adicionales que se forwardean al `<Button>` interno. Útil para casos\n * avanzados como conectar el botón con un `<form id=\"...\">` externo usando\n * `buttonProps={{ type: 'submit', form: 'my-form-id' }}`.\n */\n buttonProps?: Partial<MuiButtonProps> & { form?: string };\n}\n\nexport interface ModalFooterProps {\n children?: React.ReactNode;\n showCloseButton?: boolean;\n closeButtonText?: string;\n closeButtonDisabled?: boolean;\n onClose: () => void;\n actions?: ModalAction[];\n}\n\nexport const ModalFooter: React.FC<ModalFooterProps> = ({\n children,\n showCloseButton = true,\n closeButtonText = 'Cerrar',\n closeButtonDisabled = false,\n onClose,\n actions = [],\n}) => {\n return (\n <Box\n sx={{\n padding: 2,\n borderTop: (theme) => `1px solid ${theme.palette.divider}`,\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 1,\n }}\n >\n {children}\n <Stack direction=\"row\" spacing={1}>\n {showCloseButton && (\n <Button\n onClick={onClose}\n disabled={closeButtonDisabled}\n variant=\"outlined\"\n color=\"secondary\"\n >\n {closeButtonText}\n </Button>\n )}\n {actions.map((action) => {\n const { buttonProps, text, onClick, disabled, variant, color } = action;\n return (\n <Button\n key={text}\n onClick={onClick}\n disabled={disabled}\n variant={variant || 'contained'}\n color={color || 'primary'}\n {...(buttonProps as any)}\n >\n {text}\n </Button>\n );\n })}\n </Stack>\n </Box>\n );\n};\n\nModalFooter.displayName = 'ModalFooter';\n\nexport default ModalFooter;\n","import React from 'react';\nimport { Box, Typography } from '@mui/material';\n\nexport interface ModalHeaderProps {\n children: React.ReactNode;\n /**\n * ID del elemento — usado para `aria-labelledby` del Modal. Se setea\n * automáticamente cuando el header se renderiza dentro de `<Modal>`.\n */\n id?: string;\n}\n\nexport const ModalHeader: React.FC<ModalHeaderProps> = ({ children, id }) => {\n return (\n <Box\n sx={{\n padding: 2,\n borderBottom: (theme) => `1px solid ${theme.palette.divider}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n <Typography id={id} variant=\"h6\" component=\"h2\">\n {children}\n </Typography>\n </Box>\n );\n};\n\nModalHeader.displayName = 'ModalHeader';\n\nexport default ModalHeader;\n","import React from 'react';\nimport { Box } from '@mui/material';\n\nexport interface ModalBodyProps {\n children: React.ReactNode;\n /**\n * ID del elemento — usado para `aria-describedby` del Modal. Se setea\n * automáticamente cuando el body se renderiza dentro de `<Modal>`.\n */\n id?: string;\n}\n\nexport const ModalBody: React.FC<ModalBodyProps> = ({ children, id }) => {\n return (\n <Box id={id} sx={{ padding: 2, overflowY: 'auto', flexGrow: 1 }}>\n {children}\n </Box>\n );\n};\n\nModalBody.displayName = 'ModalBody';\n\nexport default ModalBody;\n","import {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n useId,\n useImperativeHandle,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport {\n Modal as MuiModal,\n Paper,\n useMediaQuery,\n useTheme,\n Box,\n Stack,\n Typography,\n} from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';\nimport WarningAmberIcon from '@mui/icons-material/WarningAmber';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';\nimport CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';\n\nimport type { DialogProps } from '@mui/material/Dialog';\nimport { ModalFooter, type ModalAction, type ModalFooterProps } from './ModalFooter';\nimport { ModalHeader } from './ModalHeader';\nimport { ModalBody } from './ModalBody';\nimport { mergeSx } from '../_shared/mergeSx';\n\n// Detección robusta de sub-componentes — funciona con wrappers / HMR que\n// rompen la igualdad de referencia (`child.type === ModalHeader`).\nconst isModalSlot = (\n child: ReactElement,\n Component: unknown,\n displayName: string,\n): boolean => {\n if (child.type === Component) return true;\n const type = child.type as { displayName?: string };\n return type?.displayName === displayName;\n};\n\n// Define la interfaz para los métodos que el padre puede llamar a través de la ref\nexport interface ModalRef {\n open: () => void;\n close: () => void;\n}\n\nexport type ModalMode = 'default' | 'confirm';\nexport type ModalSeverity = 'info' | 'warning' | 'error' | 'success';\n\nexport interface ModalProps {\n /**\n * Modo del modal.\n * - `default` (default): modal genérico con slots `Header`/`Body`/`Footer` y\n * `actions` custom.\n * - `confirm`: reemplaza al `ConfirmModal` legacy. Renderiza un layout\n * focalizado con icono por severidad, mensaje y botones \"Cancelar\" /\n * \"Confirmar\".\n */\n mode?: ModalMode;\n\n // ── Props comunes ────────────────────────────────────────────────────\n /** Controlado externamente. Omitir si se usa vía ref. */\n open?: boolean;\n /** Callback al cerrar. También se dispara al confirmar/cancelar. */\n onClose?: () => void;\n title?: string;\n children?: ReactNode;\n showCloseButton?: boolean;\n closeButtonText?: string;\n closeButtonDisabled?: boolean;\n actions?: ModalAction[];\n maxWidth?: DialogProps['maxWidth'];\n /**\n * Si `true`, el modal NO se cierra al hacer click en el backdrop ni con Escape\n * (equivale a `backdrop=\"static\"`). Cerrar solo vía botón/acción.\n */\n staticBackdrop?: boolean;\n /** Test id aplicado al Paper interno (contenedor visual). */\n 'data-testid'?: string;\n /** Oculta el header (incluso si hay `title` o se pasa un `<Modal.Header>`). */\n hiddenHeader?: boolean;\n /** Oculta el body (incluso si se pasa un `<Modal.Body>`). */\n hiddenBody?: boolean;\n /** Oculta el footer (incluso si se pasa un `<Modal.Footer>` o `actions`). */\n hiddenFooter?: boolean;\n /** sx del Modal root (MuiModal). */\n sx?: SxProps<Theme>;\n /** sx del Paper interno (contenedor visual). Se mergea sobre el default. */\n paperSx?: SxProps<Theme>;\n /** className del Paper interno. */\n className?: string;\n\n // ── Props del modo confirm ───────────────────────────────────────────\n /**\n * Callback de confirmación. Soporta promesa — si devuelve `Promise`, el\n * botón muestra estado `disabled` mientras resuelve.\n *\n * Si la promesa **rechaza**, el modal queda abierto para que el consumer\n * pueda mostrar el error en su UI. El modal se cierra solo en éxito.\n */\n onConfirm?: () => void | Promise<void>;\n /** Texto del botón primario en modo `confirm`. Default: \"Confirmar\". */\n confirmText?: string;\n /** Deshabilita el botón de confirmar. */\n confirmDisabled?: boolean;\n /**\n * Severidad visual en modo `confirm`. Controla el icono y el color del\n * botón de confirmación.\n * - `info` (default): primary\n * - `warning`: warning (amarillo)\n * - `error`: error (rojo) — típico para \"Eliminar\"\n * - `success`: success (verde) — típico para \"Aprobar\"\n */\n severity?: ModalSeverity;\n /**\n * Mensaje del confirm. Puede ser string o cualquier ReactNode. Si se omite,\n * se usa `children`.\n */\n confirmMessage?: ReactNode;\n}\n\nconst modalStyle = {\n position: 'absolute' as const,\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: '90%',\n maxHeight: '90vh',\n display: 'flex',\n flexDirection: 'column' as const,\n outline: 'none',\n};\n\nconst severityConfig: Record<\n ModalSeverity,\n { color: ModalAction['color']; icon: ReactNode; paletteKey: 'primary' | 'warning' | 'error' | 'success' }\n> = {\n info: {\n color: 'primary',\n icon: <InfoOutlinedIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'primary',\n },\n warning: {\n color: 'warning',\n icon: <WarningAmberIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'warning',\n },\n error: {\n color: 'error',\n icon: <ErrorOutlineIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'error',\n },\n success: {\n color: 'success',\n icon: <CheckCircleOutlineIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'success',\n },\n};\n\nexport const Modal = forwardRef<ModalRef, ModalProps>(\n (\n {\n mode = 'default',\n open: controlledOpen,\n onClose: controlledOnClose,\n title,\n children,\n showCloseButton = true,\n closeButtonText = 'Cerrar',\n closeButtonDisabled = false,\n actions = [],\n maxWidth = 'sm',\n hiddenHeader = false,\n hiddenBody = false,\n hiddenFooter = false,\n staticBackdrop = false,\n 'data-testid': dataTestId,\n sx,\n paperSx,\n className,\n\n // Props del modo confirm\n onConfirm,\n confirmText = 'Confirmar',\n confirmDisabled = false,\n severity = 'info',\n confirmMessage,\n },\n ref,\n ) => {\n const [internalOpen, setInternalOpen] = useState(false);\n const [confirmLoading, setConfirmLoading] = useState(false);\n\n // IDs estables para a11y: `aria-labelledby` y `aria-describedby`.\n const titleId = useId();\n const descId = useId();\n\n const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;\n\n useImperativeHandle(ref, () => ({\n open: () => setInternalOpen(true),\n close: () => {\n setInternalOpen(false);\n controlledOnClose?.();\n },\n }));\n\n const handleCloseInternal = (\n _event?: object,\n reason?: 'backdropClick' | 'escapeKeyDown',\n ) => {\n // Backdrop estático: ignora cierres por click fuera o Escape.\n if (\n staticBackdrop &&\n (reason === 'backdropClick' || reason === 'escapeKeyDown')\n ) {\n return;\n }\n setInternalOpen(false);\n controlledOnClose?.();\n };\n\n const handleConfirm = async () => {\n if (!onConfirm) {\n handleCloseInternal();\n return;\n }\n const result = onConfirm();\n if (!(result instanceof Promise)) {\n handleCloseInternal();\n return;\n }\n setConfirmLoading(true);\n try {\n await result;\n handleCloseInternal();\n } catch (err) {\n // No cerrar el modal en caso de error — el consumer es responsable\n // de mostrar un estado de error en su UI. Logueamos para trazabilidad\n // en dev.\n // eslint-disable-next-line no-console\n console.error('Modal onConfirm failed:', err);\n } finally {\n setConfirmLoading(false);\n }\n };\n\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('sm'));\n\n const getWidth = () => {\n if (isMobile) return '95%';\n switch (maxWidth) {\n case 'xs':\n return 300;\n case 'sm':\n return 500;\n case 'md':\n return 700;\n case 'lg':\n return 900;\n case 'xl':\n return 1100;\n case false:\n return 'auto';\n default:\n // Soporta string custom: `maxWidth=\"600px\"` se pasa tal cual.\n return typeof maxWidth === 'string' ? maxWidth : 500;\n }\n };\n\n // Base sx del Paper + width responsive; el consumer puede pisarlos via `paperSx`.\n const paperBaseSx: SxProps<Theme> = { ...modalStyle, width: getWidth() };\n const mergedPaperSx = mergeSx(paperBaseSx, paperSx);\n\n // ── Render modo CONFIRM ─────────────────────────────────────────────\n if (mode === 'confirm') {\n const config = severityConfig[severity];\n const message = confirmMessage ?? children;\n\n return (\n <MuiModal\n open={isOpen}\n onClose={handleCloseInternal}\n aria-labelledby={title ? titleId : undefined}\n aria-describedby={message ? descId : undefined}\n closeAfterTransition\n sx={sx}\n >\n <Paper className={className} sx={mergedPaperSx} data-testid={dataTestId}>\n <Stack spacing={2.5} sx={{ p: 3, alignItems: 'center', textAlign: 'center' }}>\n <Box\n sx={{\n width: 72,\n height: 72,\n borderRadius: '50%',\n backgroundColor: (t) => t.palette[config.paletteKey].light,\n color: (t) => t.palette[config.paletteKey].dark,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n opacity: 0.9,\n }}\n >\n {config.icon}\n </Box>\n {title && (\n <Typography id={titleId} variant=\"h6\" component=\"h2\" sx={{ fontWeight: 700 }}>\n {title}\n </Typography>\n )}\n {message && (\n <Typography id={descId} variant=\"body2\" color=\"text.secondary\">\n {message}\n </Typography>\n )}\n </Stack>\n <ModalFooter\n showCloseButton={showCloseButton}\n closeButtonText={closeButtonText}\n closeButtonDisabled={closeButtonDisabled || confirmLoading}\n onClose={handleCloseInternal}\n actions={[\n {\n text: confirmText,\n onClick: handleConfirm,\n disabled: confirmDisabled || confirmLoading,\n variant: 'contained',\n color: config.color,\n },\n ]}\n />\n </Paper>\n </MuiModal>\n );\n }\n\n // ── Render modo DEFAULT (compuesto) ─────────────────────────────────\n const renderChildren = () => {\n let header: ReactNode | null = null;\n let body: ReactNode | null = null;\n let footer: ReactNode | null = null;\n\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n\n if (isModalSlot(child, ModalHeader, 'ModalHeader')) {\n const headerChild = child as ReactElement<{ id?: string }>;\n header = cloneElement(headerChild, { id: titleId, ...headerChild.props });\n } else if (isModalSlot(child, ModalBody, 'ModalBody')) {\n const bodyChild = child as ReactElement<{ id?: string }>;\n body = cloneElement(bodyChild, { id: descId, ...bodyChild.props });\n } else if (isModalSlot(child, ModalFooter, 'ModalFooter')) {\n const footerChild = child as ReactElement<ModalFooterProps>;\n // Props del child ganan sobre los del Modal padre: si el consumer\n // declara `<Modal.Footer showCloseButton={false}>`, ese valor se\n // respeta. Solo los que vengan `undefined` caen al default del padre.\n const childProps = footerChild.props;\n footer = cloneElement(footerChild, {\n showCloseButton: childProps.showCloseButton ?? showCloseButton,\n closeButtonText: childProps.closeButtonText ?? closeButtonText,\n closeButtonDisabled: childProps.closeButtonDisabled ?? closeButtonDisabled,\n onClose: childProps.onClose ?? handleCloseInternal,\n actions: childProps.actions ?? actions,\n });\n }\n });\n\n if (!footer && !hiddenFooter) {\n footer = (\n <ModalFooter\n showCloseButton={showCloseButton}\n closeButtonText={closeButtonText}\n closeButtonDisabled={closeButtonDisabled}\n onClose={handleCloseInternal}\n actions={actions}\n />\n );\n }\n\n return (\n <>\n {!hiddenHeader && (header || (title && <ModalHeader id={titleId}>{title}</ModalHeader>))}\n {!hiddenBody && body}\n {footer}\n </>\n );\n };\n\n return (\n <MuiModal\n open={isOpen}\n onClose={handleCloseInternal}\n aria-labelledby={titleId}\n aria-describedby={descId}\n closeAfterTransition\n sx={sx}\n >\n {/*\n `role=\"dialog\"` + `aria-modal` van en el Paper, no en MuiModal: el root\n de MuiModal es un `presentation` y sin esto el lector de pantalla anuncia\n el contenido como texto suelto, sin decir que hay un diálogo abierto ni\n acotar la navegación a su interior.\n */}\n <Paper\n role=\"dialog\"\n aria-modal=\"true\"\n className={className}\n sx={mergedPaperSx}\n data-testid={dataTestId}\n >\n {renderChildren()}\n </Paper>\n </MuiModal>\n );\n },\n);\n\nModal.displayName = 'Modal';\n\n// Define los sub-componentes como propiedades estáticas con tipos explícitos\ntype ModalComponent = ReturnType<typeof forwardRef<ModalRef, ModalProps>> & {\n Header: typeof ModalHeader;\n Body: typeof ModalBody;\n Footer: typeof ModalFooter;\n};\n\nconst ModalWithStatics = Modal as ModalComponent;\n\nModalWithStatics.Header = ModalHeader;\nModalWithStatics.Body = ModalBody;\nModalWithStatics.Footer = ModalFooter;\n\nexport default ModalWithStatics;\n"],"names":["MuiModal"],"mappings":"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"}
@@ -334,7 +334,17 @@ const Modal = React.forwardRef(
334
334
  "aria-describedby": descId,
335
335
  closeAfterTransition: true,
336
336
  sx,
337
- children: /* @__PURE__ */ jsxRuntime.jsx(material.Paper, { className, sx: mergedPaperSx, "data-testid": dataTestId, children: renderChildren() })
337
+ children: /* @__PURE__ */ jsxRuntime.jsx(
338
+ material.Paper,
339
+ {
340
+ role: "dialog",
341
+ "aria-modal": "true",
342
+ className,
343
+ sx: mergedPaperSx,
344
+ "data-testid": dataTestId,
345
+ children: renderChildren()
346
+ }
347
+ )
338
348
  }
339
349
  );
340
350
  }
@@ -348,4 +358,4 @@ exports.ModalBody = ModalBody;
348
358
  exports.ModalFooter = ModalFooter;
349
359
  exports.ModalHeader = ModalHeader;
350
360
  exports.ModalWithStatics = ModalWithStatics;
351
- //# sourceMappingURL=Modal-D_6ZdSzw.cjs.map
361
+ //# sourceMappingURL=Modal-Cfyr-RsW.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Modal-D_6ZdSzw.cjs","sources":["../src/components/Modal/ModalFooter.tsx","../src/components/Modal/ModalHeader.tsx","../src/components/Modal/ModalBody.tsx","../src/components/Modal/Modal.tsx"],"sourcesContent":["import React from 'react';\nimport { Box, Stack } from '@mui/material';\nimport type { ButtonProps as MuiButtonProps } from '@mui/material/Button';\n\nimport { Button } from '../Button';\n\n// Interfaz para acciones personalizadas (se mantiene aquí)\nexport interface ModalAction {\n text: string;\n onClick?: () => void;\n disabled?: boolean;\n variant?: MuiButtonProps['variant'];\n color?: MuiButtonProps['color'];\n /**\n * Props adicionales que se forwardean al `<Button>` interno. Útil para casos\n * avanzados como conectar el botón con un `<form id=\"...\">` externo usando\n * `buttonProps={{ type: 'submit', form: 'my-form-id' }}`.\n */\n buttonProps?: Partial<MuiButtonProps> & { form?: string };\n}\n\nexport interface ModalFooterProps {\n children?: React.ReactNode;\n showCloseButton?: boolean;\n closeButtonText?: string;\n closeButtonDisabled?: boolean;\n onClose: () => void;\n actions?: ModalAction[];\n}\n\nexport const ModalFooter: React.FC<ModalFooterProps> = ({\n children,\n showCloseButton = true,\n closeButtonText = 'Cerrar',\n closeButtonDisabled = false,\n onClose,\n actions = [],\n}) => {\n return (\n <Box\n sx={{\n padding: 2,\n borderTop: (theme) => `1px solid ${theme.palette.divider}`,\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 1,\n }}\n >\n {children}\n <Stack direction=\"row\" spacing={1}>\n {showCloseButton && (\n <Button\n onClick={onClose}\n disabled={closeButtonDisabled}\n variant=\"outlined\"\n color=\"secondary\"\n >\n {closeButtonText}\n </Button>\n )}\n {actions.map((action) => {\n const { buttonProps, text, onClick, disabled, variant, color } = action;\n return (\n <Button\n key={text}\n onClick={onClick}\n disabled={disabled}\n variant={variant || 'contained'}\n color={color || 'primary'}\n {...(buttonProps as any)}\n >\n {text}\n </Button>\n );\n })}\n </Stack>\n </Box>\n );\n};\n\nModalFooter.displayName = 'ModalFooter';\n\nexport default ModalFooter;\n","import React from 'react';\nimport { Box, Typography } from '@mui/material';\n\nexport interface ModalHeaderProps {\n children: React.ReactNode;\n /**\n * ID del elemento — usado para `aria-labelledby` del Modal. Se setea\n * automáticamente cuando el header se renderiza dentro de `<Modal>`.\n */\n id?: string;\n}\n\nexport const ModalHeader: React.FC<ModalHeaderProps> = ({ children, id }) => {\n return (\n <Box\n sx={{\n padding: 2,\n borderBottom: (theme) => `1px solid ${theme.palette.divider}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n <Typography id={id} variant=\"h6\" component=\"h2\">\n {children}\n </Typography>\n </Box>\n );\n};\n\nModalHeader.displayName = 'ModalHeader';\n\nexport default ModalHeader;\n","import React from 'react';\nimport { Box } from '@mui/material';\n\nexport interface ModalBodyProps {\n children: React.ReactNode;\n /**\n * ID del elemento — usado para `aria-describedby` del Modal. Se setea\n * automáticamente cuando el body se renderiza dentro de `<Modal>`.\n */\n id?: string;\n}\n\nexport const ModalBody: React.FC<ModalBodyProps> = ({ children, id }) => {\n return (\n <Box id={id} sx={{ padding: 2, overflowY: 'auto', flexGrow: 1 }}>\n {children}\n </Box>\n );\n};\n\nModalBody.displayName = 'ModalBody';\n\nexport default ModalBody;\n","import {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n useId,\n useImperativeHandle,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport {\n Modal as MuiModal,\n Paper,\n useMediaQuery,\n useTheme,\n Box,\n Stack,\n Typography,\n} from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';\nimport WarningAmberIcon from '@mui/icons-material/WarningAmber';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';\nimport CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';\n\nimport type { DialogProps } from '@mui/material/Dialog';\nimport { ModalFooter, type ModalAction, type ModalFooterProps } from './ModalFooter';\nimport { ModalHeader } from './ModalHeader';\nimport { ModalBody } from './ModalBody';\nimport { mergeSx } from '../_shared/mergeSx';\n\n// Detección robusta de sub-componentes — funciona con wrappers / HMR que\n// rompen la igualdad de referencia (`child.type === ModalHeader`).\nconst isModalSlot = (\n child: ReactElement,\n Component: unknown,\n displayName: string,\n): boolean => {\n if (child.type === Component) return true;\n const type = child.type as { displayName?: string };\n return type?.displayName === displayName;\n};\n\n// Define la interfaz para los métodos que el padre puede llamar a través de la ref\nexport interface ModalRef {\n open: () => void;\n close: () => void;\n}\n\nexport type ModalMode = 'default' | 'confirm';\nexport type ModalSeverity = 'info' | 'warning' | 'error' | 'success';\n\nexport interface ModalProps {\n /**\n * Modo del modal.\n * - `default` (default): modal genérico con slots `Header`/`Body`/`Footer` y\n * `actions` custom.\n * - `confirm`: reemplaza al `ConfirmModal` legacy. Renderiza un layout\n * focalizado con icono por severidad, mensaje y botones \"Cancelar\" /\n * \"Confirmar\".\n */\n mode?: ModalMode;\n\n // ── Props comunes ────────────────────────────────────────────────────\n /** Controlado externamente. Omitir si se usa vía ref. */\n open?: boolean;\n /** Callback al cerrar. También se dispara al confirmar/cancelar. */\n onClose?: () => void;\n title?: string;\n children?: ReactNode;\n showCloseButton?: boolean;\n closeButtonText?: string;\n closeButtonDisabled?: boolean;\n actions?: ModalAction[];\n maxWidth?: DialogProps['maxWidth'];\n /**\n * Si `true`, el modal NO se cierra al hacer click en el backdrop ni con Escape\n * (equivale a `backdrop=\"static\"`). Cerrar solo vía botón/acción.\n */\n staticBackdrop?: boolean;\n /** Test id aplicado al Paper interno (contenedor visual). */\n 'data-testid'?: string;\n /** Oculta el header (incluso si hay `title` o se pasa un `<Modal.Header>`). */\n hiddenHeader?: boolean;\n /** Oculta el body (incluso si se pasa un `<Modal.Body>`). */\n hiddenBody?: boolean;\n /** Oculta el footer (incluso si se pasa un `<Modal.Footer>` o `actions`). */\n hiddenFooter?: boolean;\n /** sx del Modal root (MuiModal). */\n sx?: SxProps<Theme>;\n /** sx del Paper interno (contenedor visual). Se mergea sobre el default. */\n paperSx?: SxProps<Theme>;\n /** className del Paper interno. */\n className?: string;\n\n // ── Props del modo confirm ───────────────────────────────────────────\n /**\n * Callback de confirmación. Soporta promesa — si devuelve `Promise`, el\n * botón muestra estado `disabled` mientras resuelve.\n *\n * Si la promesa **rechaza**, el modal queda abierto para que el consumer\n * pueda mostrar el error en su UI. El modal se cierra solo en éxito.\n */\n onConfirm?: () => void | Promise<void>;\n /** Texto del botón primario en modo `confirm`. Default: \"Confirmar\". */\n confirmText?: string;\n /** Deshabilita el botón de confirmar. */\n confirmDisabled?: boolean;\n /**\n * Severidad visual en modo `confirm`. Controla el icono y el color del\n * botón de confirmación.\n * - `info` (default): primary\n * - `warning`: warning (amarillo)\n * - `error`: error (rojo) — típico para \"Eliminar\"\n * - `success`: success (verde) — típico para \"Aprobar\"\n */\n severity?: ModalSeverity;\n /**\n * Mensaje del confirm. Puede ser string o cualquier ReactNode. Si se omite,\n * se usa `children`.\n */\n confirmMessage?: ReactNode;\n}\n\nconst modalStyle = {\n position: 'absolute' as const,\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: '90%',\n maxHeight: '90vh',\n display: 'flex',\n flexDirection: 'column' as const,\n outline: 'none',\n};\n\nconst severityConfig: Record<\n ModalSeverity,\n { color: ModalAction['color']; icon: ReactNode; paletteKey: 'primary' | 'warning' | 'error' | 'success' }\n> = {\n info: {\n color: 'primary',\n icon: <InfoOutlinedIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'primary',\n },\n warning: {\n color: 'warning',\n icon: <WarningAmberIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'warning',\n },\n error: {\n color: 'error',\n icon: <ErrorOutlineIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'error',\n },\n success: {\n color: 'success',\n icon: <CheckCircleOutlineIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'success',\n },\n};\n\nexport const Modal = forwardRef<ModalRef, ModalProps>(\n (\n {\n mode = 'default',\n open: controlledOpen,\n onClose: controlledOnClose,\n title,\n children,\n showCloseButton = true,\n closeButtonText = 'Cerrar',\n closeButtonDisabled = false,\n actions = [],\n maxWidth = 'sm',\n hiddenHeader = false,\n hiddenBody = false,\n hiddenFooter = false,\n staticBackdrop = false,\n 'data-testid': dataTestId,\n sx,\n paperSx,\n className,\n\n // Props del modo confirm\n onConfirm,\n confirmText = 'Confirmar',\n confirmDisabled = false,\n severity = 'info',\n confirmMessage,\n },\n ref,\n ) => {\n const [internalOpen, setInternalOpen] = useState(false);\n const [confirmLoading, setConfirmLoading] = useState(false);\n\n // IDs estables para a11y: `aria-labelledby` y `aria-describedby`.\n const titleId = useId();\n const descId = useId();\n\n const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;\n\n useImperativeHandle(ref, () => ({\n open: () => setInternalOpen(true),\n close: () => {\n setInternalOpen(false);\n controlledOnClose?.();\n },\n }));\n\n const handleCloseInternal = (\n _event?: object,\n reason?: 'backdropClick' | 'escapeKeyDown',\n ) => {\n // Backdrop estático: ignora cierres por click fuera o Escape.\n if (\n staticBackdrop &&\n (reason === 'backdropClick' || reason === 'escapeKeyDown')\n ) {\n return;\n }\n setInternalOpen(false);\n controlledOnClose?.();\n };\n\n const handleConfirm = async () => {\n if (!onConfirm) {\n handleCloseInternal();\n return;\n }\n const result = onConfirm();\n if (!(result instanceof Promise)) {\n handleCloseInternal();\n return;\n }\n setConfirmLoading(true);\n try {\n await result;\n handleCloseInternal();\n } catch (err) {\n // No cerrar el modal en caso de error — el consumer es responsable\n // de mostrar un estado de error en su UI. Logueamos para trazabilidad\n // en dev.\n // eslint-disable-next-line no-console\n console.error('Modal onConfirm failed:', err);\n } finally {\n setConfirmLoading(false);\n }\n };\n\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('sm'));\n\n const getWidth = () => {\n if (isMobile) return '95%';\n switch (maxWidth) {\n case 'xs':\n return 300;\n case 'sm':\n return 500;\n case 'md':\n return 700;\n case 'lg':\n return 900;\n case 'xl':\n return 1100;\n case false:\n return 'auto';\n default:\n // Soporta string custom: `maxWidth=\"600px\"` se pasa tal cual.\n return typeof maxWidth === 'string' ? maxWidth : 500;\n }\n };\n\n // Base sx del Paper + width responsive; el consumer puede pisarlos via `paperSx`.\n const paperBaseSx: SxProps<Theme> = { ...modalStyle, width: getWidth() };\n const mergedPaperSx = mergeSx(paperBaseSx, paperSx);\n\n // ── Render modo CONFIRM ─────────────────────────────────────────────\n if (mode === 'confirm') {\n const config = severityConfig[severity];\n const message = confirmMessage ?? children;\n\n return (\n <MuiModal\n open={isOpen}\n onClose={handleCloseInternal}\n aria-labelledby={title ? titleId : undefined}\n aria-describedby={message ? descId : undefined}\n closeAfterTransition\n sx={sx}\n >\n <Paper className={className} sx={mergedPaperSx} data-testid={dataTestId}>\n <Stack spacing={2.5} sx={{ p: 3, alignItems: 'center', textAlign: 'center' }}>\n <Box\n sx={{\n width: 72,\n height: 72,\n borderRadius: '50%',\n backgroundColor: (t) => t.palette[config.paletteKey].light,\n color: (t) => t.palette[config.paletteKey].dark,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n opacity: 0.9,\n }}\n >\n {config.icon}\n </Box>\n {title && (\n <Typography id={titleId} variant=\"h6\" component=\"h2\" sx={{ fontWeight: 700 }}>\n {title}\n </Typography>\n )}\n {message && (\n <Typography id={descId} variant=\"body2\" color=\"text.secondary\">\n {message}\n </Typography>\n )}\n </Stack>\n <ModalFooter\n showCloseButton={showCloseButton}\n closeButtonText={closeButtonText}\n closeButtonDisabled={closeButtonDisabled || confirmLoading}\n onClose={handleCloseInternal}\n actions={[\n {\n text: confirmText,\n onClick: handleConfirm,\n disabled: confirmDisabled || confirmLoading,\n variant: 'contained',\n color: config.color,\n },\n ]}\n />\n </Paper>\n </MuiModal>\n );\n }\n\n // ── Render modo DEFAULT (compuesto) ─────────────────────────────────\n const renderChildren = () => {\n let header: ReactNode | null = null;\n let body: ReactNode | null = null;\n let footer: ReactNode | null = null;\n\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n\n if (isModalSlot(child, ModalHeader, 'ModalHeader')) {\n const headerChild = child as ReactElement<{ id?: string }>;\n header = cloneElement(headerChild, { id: titleId, ...headerChild.props });\n } else if (isModalSlot(child, ModalBody, 'ModalBody')) {\n const bodyChild = child as ReactElement<{ id?: string }>;\n body = cloneElement(bodyChild, { id: descId, ...bodyChild.props });\n } else if (isModalSlot(child, ModalFooter, 'ModalFooter')) {\n const footerChild = child as ReactElement<ModalFooterProps>;\n // Props del child ganan sobre los del Modal padre: si el consumer\n // declara `<Modal.Footer showCloseButton={false}>`, ese valor se\n // respeta. Solo los que vengan `undefined` caen al default del padre.\n const childProps = footerChild.props;\n footer = cloneElement(footerChild, {\n showCloseButton: childProps.showCloseButton ?? showCloseButton,\n closeButtonText: childProps.closeButtonText ?? closeButtonText,\n closeButtonDisabled: childProps.closeButtonDisabled ?? closeButtonDisabled,\n onClose: childProps.onClose ?? handleCloseInternal,\n actions: childProps.actions ?? actions,\n });\n }\n });\n\n if (!footer && !hiddenFooter) {\n footer = (\n <ModalFooter\n showCloseButton={showCloseButton}\n closeButtonText={closeButtonText}\n closeButtonDisabled={closeButtonDisabled}\n onClose={handleCloseInternal}\n actions={actions}\n />\n );\n }\n\n return (\n <>\n {!hiddenHeader && (header || (title && <ModalHeader id={titleId}>{title}</ModalHeader>))}\n {!hiddenBody && body}\n {footer}\n </>\n );\n };\n\n return (\n <MuiModal\n open={isOpen}\n onClose={handleCloseInternal}\n aria-labelledby={titleId}\n aria-describedby={descId}\n closeAfterTransition\n sx={sx}\n >\n <Paper className={className} sx={mergedPaperSx} data-testid={dataTestId}>\n {renderChildren()}\n </Paper>\n </MuiModal>\n );\n },\n);\n\nModal.displayName = 'Modal';\n\n// Define los sub-componentes como propiedades estáticas con tipos explícitos\ntype ModalComponent = ReturnType<typeof forwardRef<ModalRef, ModalProps>> & {\n Header: typeof ModalHeader;\n Body: typeof ModalBody;\n Footer: typeof ModalFooter;\n};\n\nconst ModalWithStatics = Modal as ModalComponent;\n\nModalWithStatics.Header = ModalHeader;\nModalWithStatics.Body = ModalBody;\nModalWithStatics.Footer = ModalFooter;\n\nexport default ModalWithStatics;\n"],"names":["jsxs","Box","Stack","jsx","Button","Typography","forwardRef","useState","useId","useImperativeHandle","useTheme","useMediaQuery","mergeSx","MuiModal","Paper","Children","isValidElement","cloneElement","Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"Modal-Cfyr-RsW.cjs","sources":["../src/components/Modal/ModalFooter.tsx","../src/components/Modal/ModalHeader.tsx","../src/components/Modal/ModalBody.tsx","../src/components/Modal/Modal.tsx"],"sourcesContent":["import React from 'react';\nimport { Box, Stack } from '@mui/material';\nimport type { ButtonProps as MuiButtonProps } from '@mui/material/Button';\n\nimport { Button } from '../Button';\n\n// Interfaz para acciones personalizadas (se mantiene aquí)\nexport interface ModalAction {\n text: string;\n onClick?: () => void;\n disabled?: boolean;\n variant?: MuiButtonProps['variant'];\n color?: MuiButtonProps['color'];\n /**\n * Props adicionales que se forwardean al `<Button>` interno. Útil para casos\n * avanzados como conectar el botón con un `<form id=\"...\">` externo usando\n * `buttonProps={{ type: 'submit', form: 'my-form-id' }}`.\n */\n buttonProps?: Partial<MuiButtonProps> & { form?: string };\n}\n\nexport interface ModalFooterProps {\n children?: React.ReactNode;\n showCloseButton?: boolean;\n closeButtonText?: string;\n closeButtonDisabled?: boolean;\n onClose: () => void;\n actions?: ModalAction[];\n}\n\nexport const ModalFooter: React.FC<ModalFooterProps> = ({\n children,\n showCloseButton = true,\n closeButtonText = 'Cerrar',\n closeButtonDisabled = false,\n onClose,\n actions = [],\n}) => {\n return (\n <Box\n sx={{\n padding: 2,\n borderTop: (theme) => `1px solid ${theme.palette.divider}`,\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 1,\n }}\n >\n {children}\n <Stack direction=\"row\" spacing={1}>\n {showCloseButton && (\n <Button\n onClick={onClose}\n disabled={closeButtonDisabled}\n variant=\"outlined\"\n color=\"secondary\"\n >\n {closeButtonText}\n </Button>\n )}\n {actions.map((action) => {\n const { buttonProps, text, onClick, disabled, variant, color } = action;\n return (\n <Button\n key={text}\n onClick={onClick}\n disabled={disabled}\n variant={variant || 'contained'}\n color={color || 'primary'}\n {...(buttonProps as any)}\n >\n {text}\n </Button>\n );\n })}\n </Stack>\n </Box>\n );\n};\n\nModalFooter.displayName = 'ModalFooter';\n\nexport default ModalFooter;\n","import React from 'react';\nimport { Box, Typography } from '@mui/material';\n\nexport interface ModalHeaderProps {\n children: React.ReactNode;\n /**\n * ID del elemento — usado para `aria-labelledby` del Modal. Se setea\n * automáticamente cuando el header se renderiza dentro de `<Modal>`.\n */\n id?: string;\n}\n\nexport const ModalHeader: React.FC<ModalHeaderProps> = ({ children, id }) => {\n return (\n <Box\n sx={{\n padding: 2,\n borderBottom: (theme) => `1px solid ${theme.palette.divider}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n <Typography id={id} variant=\"h6\" component=\"h2\">\n {children}\n </Typography>\n </Box>\n );\n};\n\nModalHeader.displayName = 'ModalHeader';\n\nexport default ModalHeader;\n","import React from 'react';\nimport { Box } from '@mui/material';\n\nexport interface ModalBodyProps {\n children: React.ReactNode;\n /**\n * ID del elemento — usado para `aria-describedby` del Modal. Se setea\n * automáticamente cuando el body se renderiza dentro de `<Modal>`.\n */\n id?: string;\n}\n\nexport const ModalBody: React.FC<ModalBodyProps> = ({ children, id }) => {\n return (\n <Box id={id} sx={{ padding: 2, overflowY: 'auto', flexGrow: 1 }}>\n {children}\n </Box>\n );\n};\n\nModalBody.displayName = 'ModalBody';\n\nexport default ModalBody;\n","import {\n Children,\n cloneElement,\n forwardRef,\n isValidElement,\n useId,\n useImperativeHandle,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport {\n Modal as MuiModal,\n Paper,\n useMediaQuery,\n useTheme,\n Box,\n Stack,\n Typography,\n} from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';\nimport WarningAmberIcon from '@mui/icons-material/WarningAmber';\nimport ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';\nimport CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';\n\nimport type { DialogProps } from '@mui/material/Dialog';\nimport { ModalFooter, type ModalAction, type ModalFooterProps } from './ModalFooter';\nimport { ModalHeader } from './ModalHeader';\nimport { ModalBody } from './ModalBody';\nimport { mergeSx } from '../_shared/mergeSx';\n\n// Detección robusta de sub-componentes — funciona con wrappers / HMR que\n// rompen la igualdad de referencia (`child.type === ModalHeader`).\nconst isModalSlot = (\n child: ReactElement,\n Component: unknown,\n displayName: string,\n): boolean => {\n if (child.type === Component) return true;\n const type = child.type as { displayName?: string };\n return type?.displayName === displayName;\n};\n\n// Define la interfaz para los métodos que el padre puede llamar a través de la ref\nexport interface ModalRef {\n open: () => void;\n close: () => void;\n}\n\nexport type ModalMode = 'default' | 'confirm';\nexport type ModalSeverity = 'info' | 'warning' | 'error' | 'success';\n\nexport interface ModalProps {\n /**\n * Modo del modal.\n * - `default` (default): modal genérico con slots `Header`/`Body`/`Footer` y\n * `actions` custom.\n * - `confirm`: reemplaza al `ConfirmModal` legacy. Renderiza un layout\n * focalizado con icono por severidad, mensaje y botones \"Cancelar\" /\n * \"Confirmar\".\n */\n mode?: ModalMode;\n\n // ── Props comunes ────────────────────────────────────────────────────\n /** Controlado externamente. Omitir si se usa vía ref. */\n open?: boolean;\n /** Callback al cerrar. También se dispara al confirmar/cancelar. */\n onClose?: () => void;\n title?: string;\n children?: ReactNode;\n showCloseButton?: boolean;\n closeButtonText?: string;\n closeButtonDisabled?: boolean;\n actions?: ModalAction[];\n maxWidth?: DialogProps['maxWidth'];\n /**\n * Si `true`, el modal NO se cierra al hacer click en el backdrop ni con Escape\n * (equivale a `backdrop=\"static\"`). Cerrar solo vía botón/acción.\n */\n staticBackdrop?: boolean;\n /** Test id aplicado al Paper interno (contenedor visual). */\n 'data-testid'?: string;\n /** Oculta el header (incluso si hay `title` o se pasa un `<Modal.Header>`). */\n hiddenHeader?: boolean;\n /** Oculta el body (incluso si se pasa un `<Modal.Body>`). */\n hiddenBody?: boolean;\n /** Oculta el footer (incluso si se pasa un `<Modal.Footer>` o `actions`). */\n hiddenFooter?: boolean;\n /** sx del Modal root (MuiModal). */\n sx?: SxProps<Theme>;\n /** sx del Paper interno (contenedor visual). Se mergea sobre el default. */\n paperSx?: SxProps<Theme>;\n /** className del Paper interno. */\n className?: string;\n\n // ── Props del modo confirm ───────────────────────────────────────────\n /**\n * Callback de confirmación. Soporta promesa — si devuelve `Promise`, el\n * botón muestra estado `disabled` mientras resuelve.\n *\n * Si la promesa **rechaza**, el modal queda abierto para que el consumer\n * pueda mostrar el error en su UI. El modal se cierra solo en éxito.\n */\n onConfirm?: () => void | Promise<void>;\n /** Texto del botón primario en modo `confirm`. Default: \"Confirmar\". */\n confirmText?: string;\n /** Deshabilita el botón de confirmar. */\n confirmDisabled?: boolean;\n /**\n * Severidad visual en modo `confirm`. Controla el icono y el color del\n * botón de confirmación.\n * - `info` (default): primary\n * - `warning`: warning (amarillo)\n * - `error`: error (rojo) — típico para \"Eliminar\"\n * - `success`: success (verde) — típico para \"Aprobar\"\n */\n severity?: ModalSeverity;\n /**\n * Mensaje del confirm. Puede ser string o cualquier ReactNode. Si se omite,\n * se usa `children`.\n */\n confirmMessage?: ReactNode;\n}\n\nconst modalStyle = {\n position: 'absolute' as const,\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n width: '90%',\n maxHeight: '90vh',\n display: 'flex',\n flexDirection: 'column' as const,\n outline: 'none',\n};\n\nconst severityConfig: Record<\n ModalSeverity,\n { color: ModalAction['color']; icon: ReactNode; paletteKey: 'primary' | 'warning' | 'error' | 'success' }\n> = {\n info: {\n color: 'primary',\n icon: <InfoOutlinedIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'primary',\n },\n warning: {\n color: 'warning',\n icon: <WarningAmberIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'warning',\n },\n error: {\n color: 'error',\n icon: <ErrorOutlineIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'error',\n },\n success: {\n color: 'success',\n icon: <CheckCircleOutlineIcon sx={{ fontSize: 48 }} />,\n paletteKey: 'success',\n },\n};\n\nexport const Modal = forwardRef<ModalRef, ModalProps>(\n (\n {\n mode = 'default',\n open: controlledOpen,\n onClose: controlledOnClose,\n title,\n children,\n showCloseButton = true,\n closeButtonText = 'Cerrar',\n closeButtonDisabled = false,\n actions = [],\n maxWidth = 'sm',\n hiddenHeader = false,\n hiddenBody = false,\n hiddenFooter = false,\n staticBackdrop = false,\n 'data-testid': dataTestId,\n sx,\n paperSx,\n className,\n\n // Props del modo confirm\n onConfirm,\n confirmText = 'Confirmar',\n confirmDisabled = false,\n severity = 'info',\n confirmMessage,\n },\n ref,\n ) => {\n const [internalOpen, setInternalOpen] = useState(false);\n const [confirmLoading, setConfirmLoading] = useState(false);\n\n // IDs estables para a11y: `aria-labelledby` y `aria-describedby`.\n const titleId = useId();\n const descId = useId();\n\n const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;\n\n useImperativeHandle(ref, () => ({\n open: () => setInternalOpen(true),\n close: () => {\n setInternalOpen(false);\n controlledOnClose?.();\n },\n }));\n\n const handleCloseInternal = (\n _event?: object,\n reason?: 'backdropClick' | 'escapeKeyDown',\n ) => {\n // Backdrop estático: ignora cierres por click fuera o Escape.\n if (\n staticBackdrop &&\n (reason === 'backdropClick' || reason === 'escapeKeyDown')\n ) {\n return;\n }\n setInternalOpen(false);\n controlledOnClose?.();\n };\n\n const handleConfirm = async () => {\n if (!onConfirm) {\n handleCloseInternal();\n return;\n }\n const result = onConfirm();\n if (!(result instanceof Promise)) {\n handleCloseInternal();\n return;\n }\n setConfirmLoading(true);\n try {\n await result;\n handleCloseInternal();\n } catch (err) {\n // No cerrar el modal en caso de error — el consumer es responsable\n // de mostrar un estado de error en su UI. Logueamos para trazabilidad\n // en dev.\n // eslint-disable-next-line no-console\n console.error('Modal onConfirm failed:', err);\n } finally {\n setConfirmLoading(false);\n }\n };\n\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('sm'));\n\n const getWidth = () => {\n if (isMobile) return '95%';\n switch (maxWidth) {\n case 'xs':\n return 300;\n case 'sm':\n return 500;\n case 'md':\n return 700;\n case 'lg':\n return 900;\n case 'xl':\n return 1100;\n case false:\n return 'auto';\n default:\n // Soporta string custom: `maxWidth=\"600px\"` se pasa tal cual.\n return typeof maxWidth === 'string' ? maxWidth : 500;\n }\n };\n\n // Base sx del Paper + width responsive; el consumer puede pisarlos via `paperSx`.\n const paperBaseSx: SxProps<Theme> = { ...modalStyle, width: getWidth() };\n const mergedPaperSx = mergeSx(paperBaseSx, paperSx);\n\n // ── Render modo CONFIRM ─────────────────────────────────────────────\n if (mode === 'confirm') {\n const config = severityConfig[severity];\n const message = confirmMessage ?? children;\n\n return (\n <MuiModal\n open={isOpen}\n onClose={handleCloseInternal}\n aria-labelledby={title ? titleId : undefined}\n aria-describedby={message ? descId : undefined}\n closeAfterTransition\n sx={sx}\n >\n <Paper className={className} sx={mergedPaperSx} data-testid={dataTestId}>\n <Stack spacing={2.5} sx={{ p: 3, alignItems: 'center', textAlign: 'center' }}>\n <Box\n sx={{\n width: 72,\n height: 72,\n borderRadius: '50%',\n backgroundColor: (t) => t.palette[config.paletteKey].light,\n color: (t) => t.palette[config.paletteKey].dark,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n opacity: 0.9,\n }}\n >\n {config.icon}\n </Box>\n {title && (\n <Typography id={titleId} variant=\"h6\" component=\"h2\" sx={{ fontWeight: 700 }}>\n {title}\n </Typography>\n )}\n {message && (\n <Typography id={descId} variant=\"body2\" color=\"text.secondary\">\n {message}\n </Typography>\n )}\n </Stack>\n <ModalFooter\n showCloseButton={showCloseButton}\n closeButtonText={closeButtonText}\n closeButtonDisabled={closeButtonDisabled || confirmLoading}\n onClose={handleCloseInternal}\n actions={[\n {\n text: confirmText,\n onClick: handleConfirm,\n disabled: confirmDisabled || confirmLoading,\n variant: 'contained',\n color: config.color,\n },\n ]}\n />\n </Paper>\n </MuiModal>\n );\n }\n\n // ── Render modo DEFAULT (compuesto) ─────────────────────────────────\n const renderChildren = () => {\n let header: ReactNode | null = null;\n let body: ReactNode | null = null;\n let footer: ReactNode | null = null;\n\n Children.forEach(children, (child) => {\n if (!isValidElement(child)) return;\n\n if (isModalSlot(child, ModalHeader, 'ModalHeader')) {\n const headerChild = child as ReactElement<{ id?: string }>;\n header = cloneElement(headerChild, { id: titleId, ...headerChild.props });\n } else if (isModalSlot(child, ModalBody, 'ModalBody')) {\n const bodyChild = child as ReactElement<{ id?: string }>;\n body = cloneElement(bodyChild, { id: descId, ...bodyChild.props });\n } else if (isModalSlot(child, ModalFooter, 'ModalFooter')) {\n const footerChild = child as ReactElement<ModalFooterProps>;\n // Props del child ganan sobre los del Modal padre: si el consumer\n // declara `<Modal.Footer showCloseButton={false}>`, ese valor se\n // respeta. Solo los que vengan `undefined` caen al default del padre.\n const childProps = footerChild.props;\n footer = cloneElement(footerChild, {\n showCloseButton: childProps.showCloseButton ?? showCloseButton,\n closeButtonText: childProps.closeButtonText ?? closeButtonText,\n closeButtonDisabled: childProps.closeButtonDisabled ?? closeButtonDisabled,\n onClose: childProps.onClose ?? handleCloseInternal,\n actions: childProps.actions ?? actions,\n });\n }\n });\n\n if (!footer && !hiddenFooter) {\n footer = (\n <ModalFooter\n showCloseButton={showCloseButton}\n closeButtonText={closeButtonText}\n closeButtonDisabled={closeButtonDisabled}\n onClose={handleCloseInternal}\n actions={actions}\n />\n );\n }\n\n return (\n <>\n {!hiddenHeader && (header || (title && <ModalHeader id={titleId}>{title}</ModalHeader>))}\n {!hiddenBody && body}\n {footer}\n </>\n );\n };\n\n return (\n <MuiModal\n open={isOpen}\n onClose={handleCloseInternal}\n aria-labelledby={titleId}\n aria-describedby={descId}\n closeAfterTransition\n sx={sx}\n >\n {/*\n `role=\"dialog\"` + `aria-modal` van en el Paper, no en MuiModal: el root\n de MuiModal es un `presentation` y sin esto el lector de pantalla anuncia\n el contenido como texto suelto, sin decir que hay un diálogo abierto ni\n acotar la navegación a su interior.\n */}\n <Paper\n role=\"dialog\"\n aria-modal=\"true\"\n className={className}\n sx={mergedPaperSx}\n data-testid={dataTestId}\n >\n {renderChildren()}\n </Paper>\n </MuiModal>\n );\n },\n);\n\nModal.displayName = 'Modal';\n\n// Define los sub-componentes como propiedades estáticas con tipos explícitos\ntype ModalComponent = ReturnType<typeof forwardRef<ModalRef, ModalProps>> & {\n Header: typeof ModalHeader;\n Body: typeof ModalBody;\n Footer: typeof ModalFooter;\n};\n\nconst ModalWithStatics = Modal as ModalComponent;\n\nModalWithStatics.Header = ModalHeader;\nModalWithStatics.Body = ModalBody;\nModalWithStatics.Footer = ModalFooter;\n\nexport default ModalWithStatics;\n"],"names":["jsxs","Box","Stack","jsx","Button","Typography","forwardRef","useState","useId","useImperativeHandle","useTheme","useMediaQuery","mergeSx","MuiModal","Paper","Children","isValidElement","cloneElement","Fragment"],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ const jsxRuntime = require("react/jsx-runtime");
3
+ const material = require("@mui/material");
4
+ const resolvePreset = require("./resolvePreset-CxTI6_Ln.cjs");
5
+ function PageHeader({
6
+ title,
7
+ breadcrumbs,
8
+ actions,
9
+ preset,
10
+ sx,
11
+ className,
12
+ "data-testid": dataTestId
13
+ }) {
14
+ const theme = material.useTheme();
15
+ const presetSx = resolvePreset.resolvePreset("PageHeader", preset, theme);
16
+ const rootSx = [
17
+ {
18
+ display: "flex",
19
+ flexWrap: "wrap",
20
+ alignItems: "center",
21
+ justifyContent: "space-between",
22
+ gap: 2,
23
+ mb: 3
24
+ },
25
+ ...presetSx ? [presetSx] : [],
26
+ ...Array.isArray(sx) ? sx : sx ? [sx] : []
27
+ ];
28
+ return /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { sx: rootSx, className, "data-testid": dataTestId, children: [
29
+ /* @__PURE__ */ jsxRuntime.jsx(material.Typography, { variant: "h4", component: "h1", className: "fri-PageHeader-title", sx: { color: "text.primary" }, children: title }),
30
+ (breadcrumbs || actions) && /* @__PURE__ */ jsxRuntime.jsxs(material.Box, { className: "fri-PageHeader-aside", sx: { display: "flex", alignItems: "center", gap: 2 }, children: [
31
+ breadcrumbs,
32
+ actions
33
+ ] })
34
+ ] });
35
+ }
36
+ exports.PageHeader = PageHeader;
37
+ //# sourceMappingURL=PageHeader-BQZOqjNr.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PageHeader-BQZOqjNr.cjs","sources":["../src/components/PageHeader/PageHeader.tsx"],"sourcesContent":["import { type ReactNode } from 'react';\nimport { Box, Typography, useTheme } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\n\nimport { resolvePreset } from '../_shared/resolvePreset';\n\nexport interface PageHeaderProps {\n /** Título de la página. Se renderiza como `<h1>`. */\n title: ReactNode;\n /**\n * Migas de pan ya armadas por el consumidor — normalmente un `<Breadcrumbs>`\n * con los `Link` de su router. Es un slot a propósito: el paquete no depende\n * de ninguna librería de routing.\n */\n breadcrumbs?: ReactNode;\n /** Acciones a la derecha (botones, menús). */\n actions?: ReactNode;\n /** Preset registrado en `theme.styles.PageHeader`. */\n preset?: string;\n sx?: SxProps<Theme>;\n className?: string;\n 'data-testid'?: string;\n}\n\n/**\n * Encabezado de página: título a la izquierda, migas + acciones a la derecha.\n * En pantallas angostas envuelve en vez de comprimir el título.\n */\nexport function PageHeader({\n title,\n breadcrumbs,\n actions,\n preset,\n sx,\n className,\n 'data-testid': dataTestId,\n}: PageHeaderProps) {\n const theme = useTheme();\n const presetSx = resolvePreset('PageHeader', preset, theme);\n\n const rootSx: SxProps<Theme> = [\n {\n display: 'flex',\n flexWrap: 'wrap',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 2,\n mb: 3,\n },\n ...(presetSx ? [presetSx] : []),\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ] as SxProps<Theme>;\n\n return (\n <Box sx={rootSx} className={className} data-testid={dataTestId}>\n <Typography variant=\"h4\" component=\"h1\" className=\"fri-PageHeader-title\" sx={{ color: 'text.primary' }}>\n {title}\n </Typography>\n {(breadcrumbs || actions) && (\n <Box className=\"fri-PageHeader-aside\" sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>\n {breadcrumbs}\n {actions}\n </Box>\n )}\n </Box>\n );\n}\n\nexport default PageHeader;\n"],"names":["useTheme","resolvePreset","Box","jsx","Typography","jsxs"],"mappings":";;;;AA4BO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,GAAoB;AAClB,QAAM,QAAQA,SAAAA,SAAA;AACd,QAAM,WAAWC,cAAAA,cAAc,cAAc,QAAQ,KAAK;AAE1D,QAAM,SAAyB;AAAA,IAC7B;AAAA,MACE,SAAS;AAAA,MACT,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,KAAK;AAAA,MACL,IAAI;AAAA,IAAA;AAAA,IAEN,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAA;AAAA,IAC5B,GAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,KAAK,CAAC,EAAE,IAAI,CAAA;AAAA,EAAC;AAG5C,yCACGC,SAAAA,KAAA,EAAI,IAAI,QAAQ,WAAsB,eAAa,YAClD,UAAA;AAAA,IAAAC,2BAAAA,IAACC,SAAAA,YAAA,EAAW,SAAQ,MAAK,WAAU,MAAK,WAAU,wBAAuB,IAAI,EAAE,OAAO,eAAA,GACnF,UAAA,OACH;AAAA,KACE,eAAe,YACfC,2BAAAA,KAACH,SAAAA,KAAA,EAAI,WAAU,wBAAuB,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,KACrF,UAAA;AAAA,MAAA;AAAA,MACA;AAAA,IAAA,EAAA,CACH;AAAA,EAAA,GAEJ;AAEJ;;"}