@soyfri/shared-library 3.2.0 → 3.3.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.
- package/DataRow-B7fJ5taA.js +55 -0
- package/DataRow-B7fJ5taA.js.map +1 -0
- package/DataRow-CfCaSdaJ.cjs +54 -0
- package/DataRow-CfCaSdaJ.cjs.map +1 -0
- package/{DrawerItem--OTb3X9v.cjs → DrawerItem-DlnG_NdY.cjs} +4 -2
- package/DrawerItem-DlnG_NdY.cjs.map +1 -0
- package/{DrawerItem-DKlMQ-xs.js → DrawerItem-at1lsEo9.js} +4 -2
- package/DrawerItem-at1lsEo9.js.map +1 -0
- package/EmptyState-DJj9KOEy.cjs +47 -0
- package/EmptyState-DJj9KOEy.cjs.map +1 -0
- package/EmptyState-kEoDkg1B.js +48 -0
- package/EmptyState-kEoDkg1B.js.map +1 -0
- package/PageHeader-BQZOqjNr.cjs +37 -0
- package/PageHeader-BQZOqjNr.cjs.map +1 -0
- package/PageHeader-DDYi6Nhy.js +38 -0
- package/PageHeader-DDYi6Nhy.js.map +1 -0
- package/components/DataRow/DataRow.cjs +6 -0
- package/components/DataRow/DataRow.cjs.map +1 -0
- package/components/DataRow/DataRow.d.ts +44 -0
- package/components/DataRow/DataRow.js +6 -0
- package/components/DataRow/DataRow.js.map +1 -0
- package/components/DataRow/index.d.ts +2 -0
- package/components/DataRow.d.ts +6 -0
- package/components/Drawer/Drawer.cjs +1 -1
- package/components/Drawer/Drawer.js +1 -1
- package/components/EmptyState/EmptyState.cjs +6 -0
- package/components/EmptyState/EmptyState.cjs.map +1 -0
- package/components/EmptyState/EmptyState.d.ts +24 -0
- package/components/EmptyState/EmptyState.js +6 -0
- package/components/EmptyState/EmptyState.js.map +1 -0
- package/components/EmptyState/index.d.ts +2 -0
- package/components/EmptyState.d.ts +6 -0
- package/components/PageHeader/PageHeader.cjs +6 -0
- package/components/PageHeader/PageHeader.cjs.map +1 -0
- package/components/PageHeader/PageHeader.d.ts +25 -0
- package/components/PageHeader/PageHeader.js +6 -0
- package/components/PageHeader/PageHeader.js.map +1 -0
- package/components/PageHeader/index.d.ts +2 -0
- package/components/PageHeader.d.ts +6 -0
- package/index.cjs +7 -1
- package/index.cjs.map +1 -1
- package/index.d.ts +6 -0
- package/index.js +12 -6
- package/index.js.map +1 -1
- package/package.json +16 -1
- package/theme/componentStyles.d.ts +1 -1
- package/DrawerItem--OTb3X9v.cjs.map +0 -1
- package/DrawerItem-DKlMQ-xs.js.map +0 -1
- package/styles.css +0 -375
|
@@ -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;;"}
|
|
@@ -77,7 +77,9 @@ function buildDrawerItemSx({
|
|
|
77
77
|
whiteSpace: "nowrap",
|
|
78
78
|
opacity: collapsed ? 0 : 1,
|
|
79
79
|
width: collapsed ? 0 : "auto",
|
|
80
|
-
|
|
80
|
+
// Solo `opacity`: `width: auto` no es interpolable, así que animarlo nunca
|
|
81
|
+
// hizo nada más que pedir un reflow. El fundido es lo que se ve.
|
|
82
|
+
transition: theme.transitions.create("opacity", {
|
|
81
83
|
duration: collapsed ? 100 : 200
|
|
82
84
|
})
|
|
83
85
|
}
|
|
@@ -267,4 +269,4 @@ function DrawerItem({
|
|
|
267
269
|
exports.Drawer = Drawer;
|
|
268
270
|
exports.DrawerItem = DrawerItem;
|
|
269
271
|
exports.useDrawerContext = useDrawerContext;
|
|
270
|
-
//# sourceMappingURL=DrawerItem
|
|
272
|
+
//# sourceMappingURL=DrawerItem-DlnG_NdY.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DrawerItem-DlnG_NdY.cjs","sources":["../src/components/Drawer/DrawerContext.ts","../src/components/Drawer/Drawer.sx.ts","../src/components/Drawer/Drawer.tsx","../src/components/Drawer/DrawerItem.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\n/**\n * Context interno del Drawer. Permite que los sub-componentes (DrawerItem,\n * DrawerSection, etc.) reaccionen al estado `collapsed` sin necesidad de\n * recibirlo por props explícitas.\n */\nexport interface DrawerContextValue {\n /** Si el drawer está en modo mini (solo iconos). */\n collapsed: boolean;\n /** Ancho actual del drawer (útil para sub-componentes que necesiten layout). */\n width: number;\n}\n\nexport const DrawerContext = createContext<DrawerContextValue | null>(null);\n\n/**\n * Hook para leer el estado del drawer desde cualquier sub-componente. Si se\n * llama fuera de un `<Drawer>`, devuelve valores por defecto (collapsed=false)\n * para que los items renderizados sueltos no exploten.\n */\nexport function useDrawerContext(): DrawerContextValue {\n const ctx = useContext(DrawerContext);\n if (ctx) return ctx;\n return { collapsed: false, width: 260 };\n}\n","import { alpha, type SxProps, type Theme } from '@mui/material/styles';\n\nexport interface BuildDrawerSxArgs {\n /** Ancho actual del drawer (expanded o collapsed). */\n width: number;\n /** Duración de la transición de ancho en ms. */\n transitionDuration?: number;\n}\n\n/**\n * sx aplicado al root del MuiDrawer. Controla el ancho animado y el paper\n * interno. Los estilos visuales del paper (background, border) se dejan en\n * manos del theme / preset.\n */\nexport function buildDrawerSx({\n width,\n transitionDuration = 200,\n}: BuildDrawerSxArgs): SxProps<Theme> {\n return {\n width,\n flexShrink: 0,\n whiteSpace: 'nowrap',\n boxSizing: 'border-box',\n transition: (theme) =>\n theme.transitions.create('width', {\n easing: theme.transitions.easing.sharp,\n duration: transitionDuration,\n }),\n '& .MuiDrawer-paper': {\n width,\n boxSizing: 'border-box',\n overflowX: 'hidden',\n transition: (theme) =>\n theme.transitions.create('width', {\n easing: theme.transitions.easing.sharp,\n duration: transitionDuration,\n }),\n },\n };\n}\n\nexport interface BuildDrawerItemSxArgs {\n collapsed: boolean;\n active?: boolean;\n danger?: boolean;\n}\n\n/**\n * sx para un item del drawer. Centra el icono cuando está colapsado y\n * tiñe el fondo cuando el item está activo.\n */\nexport function buildDrawerItemSx({\n collapsed,\n active,\n danger,\n}: BuildDrawerItemSxArgs): SxProps<Theme> {\n return (theme) => ({\n minHeight: 44,\n px: collapsed ? 1 : 2,\n py: 1,\n mx: 1,\n my: 0.25,\n borderRadius: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: collapsed ? 'center' : 'flex-start',\n gap: collapsed ? 0 : 1.5,\n cursor: 'pointer',\n color: danger\n ? theme.palette.error.main\n : active\n ? theme.palette.primary.main\n : theme.palette.text.primary,\n backgroundColor: active\n ? theme.palette.action.selected\n : 'transparent',\n transition: theme.transitions.create(\n ['background-color', 'color', 'padding'],\n { duration: 150 },\n ),\n '&:hover': {\n backgroundColor: danger\n ? alpha(theme.palette.error.main, 0.08)\n : theme.palette.action.hover,\n },\n '& .drawer-item__icon': {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n minWidth: 24,\n },\n '& .drawer-item__label': {\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n opacity: collapsed ? 0 : 1,\n width: collapsed ? 0 : 'auto',\n // Solo `opacity`: `width: auto` no es interpolable, así que animarlo nunca\n // hizo nada más que pedir un reflow. El fundido es lo que se ve.\n transition: theme.transitions.create('opacity', {\n duration: collapsed ? 100 : 200,\n }),\n },\n });\n}\n","import { useMemo, type ReactNode } from 'react';\nimport {\n Drawer as MuiDrawer,\n IconButton,\n Box,\n type DrawerProps as MuiDrawerProps,\n} from '@mui/material';\nimport {\n useTheme,\n type SxProps,\n type Theme,\n} from '@mui/material/styles';\nimport ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\nimport ChevronRightIcon from '@mui/icons-material/ChevronRight';\n\nimport { DrawerContext } from './DrawerContext';\nimport { buildDrawerSx } from './Drawer.sx';\nimport { resolvePreset } from '../_shared/resolvePreset';\n\n// ── Tipos públicos ──────────────────────────────────────────────────────\nexport type DrawerVariant = 'permanent' | 'persistent' | 'temporary';\nexport type DrawerAnchor = 'left' | 'right' | 'top' | 'bottom';\n\nexport interface DrawerProps {\n /** Contenido del drawer (típicamente `<DrawerItem>`s). */\n children?: ReactNode;\n /**\n * Variante del drawer:\n * - `permanent` (default): siempre visible en desktop, soporta collapsed (mini).\n * - `persistent`: se oculta/muestra, empuja el contenido principal.\n * - `temporary`: flotante con backdrop (típico móvil).\n */\n variant?: DrawerVariant;\n /** Lado del viewport. Default: `'left'`. */\n anchor?: DrawerAnchor;\n /**\n * Estado mini (solo iconos). Solo se aplica con `variant=\"permanent\"` o\n * `\"persistent\"`. Si no se provee, el drawer está siempre expandido.\n */\n collapsed?: boolean;\n /** Callback del botón de toggle (chevron). */\n onToggleCollapse?: () => void;\n /** Estado abierto/cerrado (aplica a `temporary` y `persistent`). */\n open?: boolean;\n /** Callback de cierre (backdrop o ESC en temporary). */\n onClose?: MuiDrawerProps['onClose'];\n /** Ancho en estado expandido. Default: 260. */\n expandedWidth?: number;\n /** Ancho en estado colapsado (solo iconos). Default: 72. */\n collapsedWidth?: number;\n /** Muestra el botón chevron para toggle collapsed. Default: true si `onToggleCollapse` está definido. */\n showCollapseButton?: boolean;\n /** Contenido del header (por encima de los items). Típicamente logo/brand. */\n header?: ReactNode;\n /**\n * Logo/brand que se muestra junto al botón de toggle.\n * - Expandido: logo a la izquierda, toggle a la derecha en la misma fila.\n * - Colapsado: logo arriba centrado, toggle debajo centrado (stack vertical).\n * Siempre visible (a diferencia de `header`, que se oculta al colapsar).\n */\n logo?: ReactNode;\n /** Contenido del footer (por debajo de los items). Típicamente user profile. */\n footer?: ReactNode;\n /**\n * Nombre del preset de estilo registrado en `theme.styles.Drawer`.\n * - `\"default\"` (o ausente) = estilo built-in del paquete.\n */\n preset?: string;\n /** sx aplicado al Drawer (root). Se mergea después del preset. */\n sx?: SxProps<Theme>;\n /** sx aplicado al Paper interno. */\n paperSx?: SxProps<Theme>;\n className?: string;\n}\n\nexport function Drawer({\n children,\n variant = 'permanent',\n anchor = 'left',\n collapsed = false,\n onToggleCollapse,\n open,\n onClose,\n expandedWidth = 260,\n collapsedWidth = 72,\n showCollapseButton,\n header,\n logo,\n footer,\n preset,\n sx,\n paperSx,\n className,\n}: DrawerProps) {\n const theme = useTheme();\n const presetSx = resolvePreset('Drawer', preset, theme);\n\n // El mini-variant solo tiene sentido en permanent / persistent.\n const supportsCollapsed = variant !== 'temporary';\n const effectiveWidth =\n supportsCollapsed && collapsed ? collapsedWidth : expandedWidth;\n\n const contextValue = useMemo(\n () => ({\n collapsed: supportsCollapsed && collapsed,\n width: effectiveWidth,\n }),\n [supportsCollapsed, collapsed, effectiveWidth],\n );\n\n const rootSx: SxProps<Theme> = [\n buildDrawerSx({ width: effectiveWidth }),\n ...(presetSx ? [presetSx] : []),\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ];\n\n const shouldShowToggle =\n showCollapseButton ?? (supportsCollapsed && !!onToggleCollapse);\n\n const openProp =\n variant === 'permanent'\n ? true\n : open !== undefined\n ? open\n : false;\n\n return (\n <DrawerContext.Provider value={contextValue}>\n <MuiDrawer\n variant={variant}\n anchor={anchor}\n open={openProp}\n onClose={onClose}\n className={className}\n sx={rootSx}\n slotProps={{\n paper: {\n sx: paperSx,\n },\n }}\n >\n {(logo || shouldShowToggle) && (\n <Box\n sx={{\n display: 'flex',\n flexDirection: contextValue.collapsed ? 'column' : 'row',\n alignItems: 'center',\n justifyContent: contextValue.collapsed\n ? 'center'\n : logo\n ? 'space-between'\n : 'flex-end',\n gap: contextValue.collapsed ? 0.5 : 0,\n px: contextValue.collapsed ? 1 : 2,\n py: 1,\n minHeight: 64,\n flexShrink: 0,\n }}\n >\n {logo && (\n <Box sx={{ display: 'flex', alignItems: 'center', minWidth: 0 }}>\n {logo}\n </Box>\n )}\n {shouldShowToggle && (\n <IconButton\n size=\"small\"\n onClick={onToggleCollapse}\n aria-label={collapsed ? 'Expandir menú' : 'Colapsar menú'}\n >\n {collapsed ? <ChevronRightIcon /> : <ChevronLeftIcon />}\n </IconButton>\n )}\n </Box>\n )}\n\n {header && !contextValue.collapsed && (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n px: 2,\n py: 1.5,\n minHeight: 56,\n flexShrink: 0,\n }}\n >\n <Box sx={{ flex: 1, minWidth: 0 }}>{header}</Box>\n </Box>\n )}\n\n <Box\n component=\"nav\"\n sx={{\n flex: 1,\n overflowY: 'auto',\n overflowX: 'hidden',\n py: 1,\n }}\n >\n {children}\n </Box>\n\n {footer && (\n <Box\n sx={{\n flexShrink: 0,\n borderTop: (t) => `1px solid ${t.palette.divider}`,\n p: contextValue.collapsed ? 1 : 1.5,\n display: 'flex',\n justifyContent: contextValue.collapsed\n ? 'center'\n : 'flex-start',\n }}\n >\n {footer}\n </Box>\n )}\n </MuiDrawer>\n </DrawerContext.Provider>\n );\n}\n\nexport default Drawer;\n","import React, { type ReactNode, type MouseEvent } from 'react';\nimport { Box, Tooltip, Typography } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\n\nimport { useDrawerContext } from './DrawerContext';\nimport { buildDrawerItemSx } from './Drawer.sx';\n\nexport interface DrawerItemProps {\n /** Icono del item. Se muestra siempre (expanded y collapsed). */\n icon?: ReactNode;\n /** Texto del item. Se oculta cuando el drawer está colapsado (muestra tooltip). */\n label: ReactNode;\n /**\n * Texto del tooltip en modo collapsed. Si no se provee y `label` es string,\n * se usa `label`. Necesario cuando `label` es un ReactNode complejo.\n */\n tooltipText?: string;\n /** Handler de click. */\n onClick?: (event: MouseEvent<HTMLDivElement>) => void;\n /** Marca el item como activo (destaca color y fondo). */\n active?: boolean;\n /** Marca el item como \"destructivo\" (p.ej. cerrar sesión): color error. */\n danger?: boolean;\n /** Deshabilita click + bajo opacidad. */\n disabled?: boolean;\n /** Contenido adicional a la derecha del label (badge, count, chevron). */\n endAdornment?: ReactNode;\n /** sx override del consumer, se mergea al final. */\n sx?: SxProps<Theme>;\n className?: string;\n}\n\n/**\n * Item de un Drawer de shared-library. Lee el estado `collapsed` del\n * DrawerContext para adaptar layout y mostrar tooltip en modo mini.\n *\n * Uso típico:\n * ```tsx\n * <Drawer collapsed={collapsed} onToggleCollapse={toggle}>\n * <DrawerItem icon={<HomeIcon />} label=\"Inicio\" active />\n * <DrawerItem icon={<UserIcon />} label=\"Perfil\" />\n * </Drawer>\n * ```\n */\nexport function DrawerItem({\n icon,\n label,\n tooltipText,\n onClick,\n active = false,\n danger = false,\n disabled = false,\n endAdornment,\n sx,\n className,\n}: DrawerItemProps) {\n const { collapsed } = useDrawerContext();\n\n const baseSx = buildDrawerItemSx({ collapsed, active, danger });\n\n const mergedSx: SxProps<Theme> = [\n baseSx,\n disabled && { pointerEvents: 'none', opacity: 0.5 },\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ].filter(Boolean) as SxProps<Theme>;\n\n const content = (\n <Box\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-disabled={disabled}\n onClick={disabled ? undefined : onClick}\n onKeyDown={(event) => {\n if (disabled) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n onClick?.(event as unknown as MouseEvent<HTMLDivElement>);\n }\n }}\n className={className}\n sx={mergedSx}\n >\n {icon && (\n <Box className=\"drawer-item__icon\" component=\"span\">\n {icon}\n </Box>\n )}\n <Typography\n component=\"span\"\n variant=\"body2\"\n className=\"drawer-item__label\"\n sx={{ fontWeight: active ? 600 : 400 }}\n >\n {label}\n </Typography>\n {!collapsed && endAdornment && (\n <Box component=\"span\" sx={{ flexShrink: 0, ml: 'auto' }}>\n {endAdornment}\n </Box>\n )}\n </Box>\n );\n\n // Cuando está colapsado, envolvemos en tooltip para revelar el label al hover.\n // Prioriza `tooltipText` explícito; si no, cae al `label` si es string.\n const resolvedTooltip =\n tooltipText ?? (typeof label === 'string' ? label : undefined);\n\n if (collapsed && resolvedTooltip) {\n return (\n <Tooltip title={resolvedTooltip} placement=\"right\" arrow>\n {content}\n </Tooltip>\n );\n }\n\n return content;\n}\n\nexport default DrawerItem;\n"],"names":["createContext","useContext","alpha","useTheme","resolvePreset","useMemo","jsx","jsxs","MuiDrawer","Box","IconButton","Typography","Tooltip"],"mappings":"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"}
|
|
@@ -76,7 +76,9 @@ function buildDrawerItemSx({
|
|
|
76
76
|
whiteSpace: "nowrap",
|
|
77
77
|
opacity: collapsed ? 0 : 1,
|
|
78
78
|
width: collapsed ? 0 : "auto",
|
|
79
|
-
|
|
79
|
+
// Solo `opacity`: `width: auto` no es interpolable, así que animarlo nunca
|
|
80
|
+
// hizo nada más que pedir un reflow. El fundido es lo que se ve.
|
|
81
|
+
transition: theme.transitions.create("opacity", {
|
|
80
82
|
duration: collapsed ? 100 : 200
|
|
81
83
|
})
|
|
82
84
|
}
|
|
@@ -268,4 +270,4 @@ export {
|
|
|
268
270
|
DrawerItem as a,
|
|
269
271
|
useDrawerContext as u
|
|
270
272
|
};
|
|
271
|
-
//# sourceMappingURL=DrawerItem-
|
|
273
|
+
//# sourceMappingURL=DrawerItem-at1lsEo9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DrawerItem-at1lsEo9.js","sources":["../src/components/Drawer/DrawerContext.ts","../src/components/Drawer/Drawer.sx.ts","../src/components/Drawer/Drawer.tsx","../src/components/Drawer/DrawerItem.tsx"],"sourcesContent":["import { createContext, useContext } from 'react';\n\n/**\n * Context interno del Drawer. Permite que los sub-componentes (DrawerItem,\n * DrawerSection, etc.) reaccionen al estado `collapsed` sin necesidad de\n * recibirlo por props explícitas.\n */\nexport interface DrawerContextValue {\n /** Si el drawer está en modo mini (solo iconos). */\n collapsed: boolean;\n /** Ancho actual del drawer (útil para sub-componentes que necesiten layout). */\n width: number;\n}\n\nexport const DrawerContext = createContext<DrawerContextValue | null>(null);\n\n/**\n * Hook para leer el estado del drawer desde cualquier sub-componente. Si se\n * llama fuera de un `<Drawer>`, devuelve valores por defecto (collapsed=false)\n * para que los items renderizados sueltos no exploten.\n */\nexport function useDrawerContext(): DrawerContextValue {\n const ctx = useContext(DrawerContext);\n if (ctx) return ctx;\n return { collapsed: false, width: 260 };\n}\n","import { alpha, type SxProps, type Theme } from '@mui/material/styles';\n\nexport interface BuildDrawerSxArgs {\n /** Ancho actual del drawer (expanded o collapsed). */\n width: number;\n /** Duración de la transición de ancho en ms. */\n transitionDuration?: number;\n}\n\n/**\n * sx aplicado al root del MuiDrawer. Controla el ancho animado y el paper\n * interno. Los estilos visuales del paper (background, border) se dejan en\n * manos del theme / preset.\n */\nexport function buildDrawerSx({\n width,\n transitionDuration = 200,\n}: BuildDrawerSxArgs): SxProps<Theme> {\n return {\n width,\n flexShrink: 0,\n whiteSpace: 'nowrap',\n boxSizing: 'border-box',\n transition: (theme) =>\n theme.transitions.create('width', {\n easing: theme.transitions.easing.sharp,\n duration: transitionDuration,\n }),\n '& .MuiDrawer-paper': {\n width,\n boxSizing: 'border-box',\n overflowX: 'hidden',\n transition: (theme) =>\n theme.transitions.create('width', {\n easing: theme.transitions.easing.sharp,\n duration: transitionDuration,\n }),\n },\n };\n}\n\nexport interface BuildDrawerItemSxArgs {\n collapsed: boolean;\n active?: boolean;\n danger?: boolean;\n}\n\n/**\n * sx para un item del drawer. Centra el icono cuando está colapsado y\n * tiñe el fondo cuando el item está activo.\n */\nexport function buildDrawerItemSx({\n collapsed,\n active,\n danger,\n}: BuildDrawerItemSxArgs): SxProps<Theme> {\n return (theme) => ({\n minHeight: 44,\n px: collapsed ? 1 : 2,\n py: 1,\n mx: 1,\n my: 0.25,\n borderRadius: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: collapsed ? 'center' : 'flex-start',\n gap: collapsed ? 0 : 1.5,\n cursor: 'pointer',\n color: danger\n ? theme.palette.error.main\n : active\n ? theme.palette.primary.main\n : theme.palette.text.primary,\n backgroundColor: active\n ? theme.palette.action.selected\n : 'transparent',\n transition: theme.transitions.create(\n ['background-color', 'color', 'padding'],\n { duration: 150 },\n ),\n '&:hover': {\n backgroundColor: danger\n ? alpha(theme.palette.error.main, 0.08)\n : theme.palette.action.hover,\n },\n '& .drawer-item__icon': {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n minWidth: 24,\n },\n '& .drawer-item__label': {\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n opacity: collapsed ? 0 : 1,\n width: collapsed ? 0 : 'auto',\n // Solo `opacity`: `width: auto` no es interpolable, así que animarlo nunca\n // hizo nada más que pedir un reflow. El fundido es lo que se ve.\n transition: theme.transitions.create('opacity', {\n duration: collapsed ? 100 : 200,\n }),\n },\n });\n}\n","import { useMemo, type ReactNode } from 'react';\nimport {\n Drawer as MuiDrawer,\n IconButton,\n Box,\n type DrawerProps as MuiDrawerProps,\n} from '@mui/material';\nimport {\n useTheme,\n type SxProps,\n type Theme,\n} from '@mui/material/styles';\nimport ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\nimport ChevronRightIcon from '@mui/icons-material/ChevronRight';\n\nimport { DrawerContext } from './DrawerContext';\nimport { buildDrawerSx } from './Drawer.sx';\nimport { resolvePreset } from '../_shared/resolvePreset';\n\n// ── Tipos públicos ──────────────────────────────────────────────────────\nexport type DrawerVariant = 'permanent' | 'persistent' | 'temporary';\nexport type DrawerAnchor = 'left' | 'right' | 'top' | 'bottom';\n\nexport interface DrawerProps {\n /** Contenido del drawer (típicamente `<DrawerItem>`s). */\n children?: ReactNode;\n /**\n * Variante del drawer:\n * - `permanent` (default): siempre visible en desktop, soporta collapsed (mini).\n * - `persistent`: se oculta/muestra, empuja el contenido principal.\n * - `temporary`: flotante con backdrop (típico móvil).\n */\n variant?: DrawerVariant;\n /** Lado del viewport. Default: `'left'`. */\n anchor?: DrawerAnchor;\n /**\n * Estado mini (solo iconos). Solo se aplica con `variant=\"permanent\"` o\n * `\"persistent\"`. Si no se provee, el drawer está siempre expandido.\n */\n collapsed?: boolean;\n /** Callback del botón de toggle (chevron). */\n onToggleCollapse?: () => void;\n /** Estado abierto/cerrado (aplica a `temporary` y `persistent`). */\n open?: boolean;\n /** Callback de cierre (backdrop o ESC en temporary). */\n onClose?: MuiDrawerProps['onClose'];\n /** Ancho en estado expandido. Default: 260. */\n expandedWidth?: number;\n /** Ancho en estado colapsado (solo iconos). Default: 72. */\n collapsedWidth?: number;\n /** Muestra el botón chevron para toggle collapsed. Default: true si `onToggleCollapse` está definido. */\n showCollapseButton?: boolean;\n /** Contenido del header (por encima de los items). Típicamente logo/brand. */\n header?: ReactNode;\n /**\n * Logo/brand que se muestra junto al botón de toggle.\n * - Expandido: logo a la izquierda, toggle a la derecha en la misma fila.\n * - Colapsado: logo arriba centrado, toggle debajo centrado (stack vertical).\n * Siempre visible (a diferencia de `header`, que se oculta al colapsar).\n */\n logo?: ReactNode;\n /** Contenido del footer (por debajo de los items). Típicamente user profile. */\n footer?: ReactNode;\n /**\n * Nombre del preset de estilo registrado en `theme.styles.Drawer`.\n * - `\"default\"` (o ausente) = estilo built-in del paquete.\n */\n preset?: string;\n /** sx aplicado al Drawer (root). Se mergea después del preset. */\n sx?: SxProps<Theme>;\n /** sx aplicado al Paper interno. */\n paperSx?: SxProps<Theme>;\n className?: string;\n}\n\nexport function Drawer({\n children,\n variant = 'permanent',\n anchor = 'left',\n collapsed = false,\n onToggleCollapse,\n open,\n onClose,\n expandedWidth = 260,\n collapsedWidth = 72,\n showCollapseButton,\n header,\n logo,\n footer,\n preset,\n sx,\n paperSx,\n className,\n}: DrawerProps) {\n const theme = useTheme();\n const presetSx = resolvePreset('Drawer', preset, theme);\n\n // El mini-variant solo tiene sentido en permanent / persistent.\n const supportsCollapsed = variant !== 'temporary';\n const effectiveWidth =\n supportsCollapsed && collapsed ? collapsedWidth : expandedWidth;\n\n const contextValue = useMemo(\n () => ({\n collapsed: supportsCollapsed && collapsed,\n width: effectiveWidth,\n }),\n [supportsCollapsed, collapsed, effectiveWidth],\n );\n\n const rootSx: SxProps<Theme> = [\n buildDrawerSx({ width: effectiveWidth }),\n ...(presetSx ? [presetSx] : []),\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ];\n\n const shouldShowToggle =\n showCollapseButton ?? (supportsCollapsed && !!onToggleCollapse);\n\n const openProp =\n variant === 'permanent'\n ? true\n : open !== undefined\n ? open\n : false;\n\n return (\n <DrawerContext.Provider value={contextValue}>\n <MuiDrawer\n variant={variant}\n anchor={anchor}\n open={openProp}\n onClose={onClose}\n className={className}\n sx={rootSx}\n slotProps={{\n paper: {\n sx: paperSx,\n },\n }}\n >\n {(logo || shouldShowToggle) && (\n <Box\n sx={{\n display: 'flex',\n flexDirection: contextValue.collapsed ? 'column' : 'row',\n alignItems: 'center',\n justifyContent: contextValue.collapsed\n ? 'center'\n : logo\n ? 'space-between'\n : 'flex-end',\n gap: contextValue.collapsed ? 0.5 : 0,\n px: contextValue.collapsed ? 1 : 2,\n py: 1,\n minHeight: 64,\n flexShrink: 0,\n }}\n >\n {logo && (\n <Box sx={{ display: 'flex', alignItems: 'center', minWidth: 0 }}>\n {logo}\n </Box>\n )}\n {shouldShowToggle && (\n <IconButton\n size=\"small\"\n onClick={onToggleCollapse}\n aria-label={collapsed ? 'Expandir menú' : 'Colapsar menú'}\n >\n {collapsed ? <ChevronRightIcon /> : <ChevronLeftIcon />}\n </IconButton>\n )}\n </Box>\n )}\n\n {header && !contextValue.collapsed && (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n px: 2,\n py: 1.5,\n minHeight: 56,\n flexShrink: 0,\n }}\n >\n <Box sx={{ flex: 1, minWidth: 0 }}>{header}</Box>\n </Box>\n )}\n\n <Box\n component=\"nav\"\n sx={{\n flex: 1,\n overflowY: 'auto',\n overflowX: 'hidden',\n py: 1,\n }}\n >\n {children}\n </Box>\n\n {footer && (\n <Box\n sx={{\n flexShrink: 0,\n borderTop: (t) => `1px solid ${t.palette.divider}`,\n p: contextValue.collapsed ? 1 : 1.5,\n display: 'flex',\n justifyContent: contextValue.collapsed\n ? 'center'\n : 'flex-start',\n }}\n >\n {footer}\n </Box>\n )}\n </MuiDrawer>\n </DrawerContext.Provider>\n );\n}\n\nexport default Drawer;\n","import React, { type ReactNode, type MouseEvent } from 'react';\nimport { Box, Tooltip, Typography } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material/styles';\n\nimport { useDrawerContext } from './DrawerContext';\nimport { buildDrawerItemSx } from './Drawer.sx';\n\nexport interface DrawerItemProps {\n /** Icono del item. Se muestra siempre (expanded y collapsed). */\n icon?: ReactNode;\n /** Texto del item. Se oculta cuando el drawer está colapsado (muestra tooltip). */\n label: ReactNode;\n /**\n * Texto del tooltip en modo collapsed. Si no se provee y `label` es string,\n * se usa `label`. Necesario cuando `label` es un ReactNode complejo.\n */\n tooltipText?: string;\n /** Handler de click. */\n onClick?: (event: MouseEvent<HTMLDivElement>) => void;\n /** Marca el item como activo (destaca color y fondo). */\n active?: boolean;\n /** Marca el item como \"destructivo\" (p.ej. cerrar sesión): color error. */\n danger?: boolean;\n /** Deshabilita click + bajo opacidad. */\n disabled?: boolean;\n /** Contenido adicional a la derecha del label (badge, count, chevron). */\n endAdornment?: ReactNode;\n /** sx override del consumer, se mergea al final. */\n sx?: SxProps<Theme>;\n className?: string;\n}\n\n/**\n * Item de un Drawer de shared-library. Lee el estado `collapsed` del\n * DrawerContext para adaptar layout y mostrar tooltip en modo mini.\n *\n * Uso típico:\n * ```tsx\n * <Drawer collapsed={collapsed} onToggleCollapse={toggle}>\n * <DrawerItem icon={<HomeIcon />} label=\"Inicio\" active />\n * <DrawerItem icon={<UserIcon />} label=\"Perfil\" />\n * </Drawer>\n * ```\n */\nexport function DrawerItem({\n icon,\n label,\n tooltipText,\n onClick,\n active = false,\n danger = false,\n disabled = false,\n endAdornment,\n sx,\n className,\n}: DrawerItemProps) {\n const { collapsed } = useDrawerContext();\n\n const baseSx = buildDrawerItemSx({ collapsed, active, danger });\n\n const mergedSx: SxProps<Theme> = [\n baseSx,\n disabled && { pointerEvents: 'none', opacity: 0.5 },\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ].filter(Boolean) as SxProps<Theme>;\n\n const content = (\n <Box\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-disabled={disabled}\n onClick={disabled ? undefined : onClick}\n onKeyDown={(event) => {\n if (disabled) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n onClick?.(event as unknown as MouseEvent<HTMLDivElement>);\n }\n }}\n className={className}\n sx={mergedSx}\n >\n {icon && (\n <Box className=\"drawer-item__icon\" component=\"span\">\n {icon}\n </Box>\n )}\n <Typography\n component=\"span\"\n variant=\"body2\"\n className=\"drawer-item__label\"\n sx={{ fontWeight: active ? 600 : 400 }}\n >\n {label}\n </Typography>\n {!collapsed && endAdornment && (\n <Box component=\"span\" sx={{ flexShrink: 0, ml: 'auto' }}>\n {endAdornment}\n </Box>\n )}\n </Box>\n );\n\n // Cuando está colapsado, envolvemos en tooltip para revelar el label al hover.\n // Prioriza `tooltipText` explícito; si no, cae al `label` si es string.\n const resolvedTooltip =\n tooltipText ?? (typeof label === 'string' ? label : undefined);\n\n if (collapsed && resolvedTooltip) {\n return (\n <Tooltip title={resolvedTooltip} placement=\"right\" arrow>\n {content}\n </Tooltip>\n );\n }\n\n return content;\n}\n\nexport default DrawerItem;\n"],"names":["MuiDrawer"],"mappings":"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"}
|
|
@@ -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;"}
|
|
@@ -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;;"}
|
|
@@ -0,0 +1,38 @@
|
|
|
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 PageHeader({
|
|
5
|
+
title,
|
|
6
|
+
breadcrumbs,
|
|
7
|
+
actions,
|
|
8
|
+
preset,
|
|
9
|
+
sx,
|
|
10
|
+
className,
|
|
11
|
+
"data-testid": dataTestId
|
|
12
|
+
}) {
|
|
13
|
+
const theme = useTheme();
|
|
14
|
+
const presetSx = resolvePreset("PageHeader", preset, theme);
|
|
15
|
+
const rootSx = [
|
|
16
|
+
{
|
|
17
|
+
display: "flex",
|
|
18
|
+
flexWrap: "wrap",
|
|
19
|
+
alignItems: "center",
|
|
20
|
+
justifyContent: "space-between",
|
|
21
|
+
gap: 2,
|
|
22
|
+
mb: 3
|
|
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(Typography, { variant: "h4", component: "h1", className: "fri-PageHeader-title", sx: { color: "text.primary" }, children: title }),
|
|
29
|
+
(breadcrumbs || actions) && /* @__PURE__ */ jsxs(Box, { className: "fri-PageHeader-aside", sx: { display: "flex", alignItems: "center", gap: 2 }, children: [
|
|
30
|
+
breadcrumbs,
|
|
31
|
+
actions
|
|
32
|
+
] })
|
|
33
|
+
] });
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
PageHeader as P
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=PageHeader-DDYi6Nhy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageHeader-DDYi6Nhy.js","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":[],"mappings":";;;AA4BO,SAAS,WAAW;AAAA,EACzB;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,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,8BACG,KAAA,EAAI,IAAI,QAAQ,WAAsB,eAAa,YAClD,UAAA;AAAA,IAAA,oBAAC,YAAA,EAAW,SAAQ,MAAK,WAAU,MAAK,WAAU,wBAAuB,IAAI,EAAE,OAAO,eAAA,GACnF,UAAA,OACH;AAAA,KACE,eAAe,YACf,qBAAC,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;"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const DataRow = require("../../DataRow-CfCaSdaJ.cjs");
|
|
4
|
+
exports.DataRow = DataRow.DataRow;
|
|
5
|
+
exports.default = DataRow.DataRow;
|
|
6
|
+
//# sourceMappingURL=DataRow.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataRow.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { SxProps, Theme } from '@mui/material/styles';
|
|
3
|
+
export interface DataRowProps {
|
|
4
|
+
/** Etiqueta del dato (columna izquierda). */
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
/** Valor: texto, o cualquier nodo (chip, link, Input en modo edición). */
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
/** Última fila de un bloque: sin margen inferior. */
|
|
9
|
+
last?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Ancho de la columna del label a partir de `sm`. Default `200`.
|
|
12
|
+
* Fijo a propósito: alinea verticalmente todos los valores de un bloque.
|
|
13
|
+
*/
|
|
14
|
+
labelWidth?: number | string;
|
|
15
|
+
/** Preset registrado en `theme.styles.DataRow`. */
|
|
16
|
+
preset?: string;
|
|
17
|
+
sx?: SxProps<Theme>;
|
|
18
|
+
className?: string;
|
|
19
|
+
'data-testid'?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Fila label/valor — el patrón de dato para vistas de detalle.
|
|
23
|
+
*
|
|
24
|
+
* Geometría: label de ancho fijo + valor al lado; en móvil apila. El ancho fijo
|
|
25
|
+
* (en vez de un `Grid` 4/8) evita que en una card full-width queden cientos de
|
|
26
|
+
* px muertos entre label y valor.
|
|
27
|
+
*
|
|
28
|
+
* Tipografía: el paquete pone `body2`/`body1`. Para mapear a variantes propias
|
|
29
|
+
* del consumidor, registrar un preset en el theme apuntando a las clases
|
|
30
|
+
* internas:
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* styles: {
|
|
34
|
+
* DataRow: {
|
|
35
|
+
* default: {
|
|
36
|
+
* '& .fri-DataRow-label': { typography: 'dataLabel' },
|
|
37
|
+
* '& .fri-DataRow-value': { typography: 'dataValue' },
|
|
38
|
+
* },
|
|
39
|
+
* },
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function DataRow({ label, children, last, labelWidth, preset, sx, className, 'data-testid': dataTestId, }: DataRowProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export default DataRow;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataRow.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
-
const DrawerItem = require("../../DrawerItem
|
|
3
|
+
const DrawerItem = require("../../DrawerItem-DlnG_NdY.cjs");
|
|
4
4
|
exports.Drawer = DrawerItem.Drawer;
|
|
5
5
|
exports.DrawerItem = DrawerItem.DrawerItem;
|
|
6
6
|
exports.default = DrawerItem.Drawer;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const EmptyState = require("../../EmptyState-DJj9KOEy.cjs");
|
|
4
|
+
exports.EmptyState = EmptyState.EmptyState;
|
|
5
|
+
exports.default = EmptyState.EmptyState;
|
|
6
|
+
//# sourceMappingURL=EmptyState.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EmptyState.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { SxProps, Theme } from '@mui/material/styles';
|
|
3
|
+
export interface EmptyStateProps {
|
|
4
|
+
/** Qué falta, en positivo: "Sin dispositivos registrados". */
|
|
5
|
+
title: string;
|
|
6
|
+
/** Línea secundaria opcional: qué puede hacer el usuario. */
|
|
7
|
+
message?: string;
|
|
8
|
+
/** Icono o ilustración arriba del título. */
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
/** Acción opcional (botón) debajo del mensaje. */
|
|
11
|
+
action?: ReactNode;
|
|
12
|
+
/** Preset registrado en `theme.styles.EmptyState`. */
|
|
13
|
+
preset?: string;
|
|
14
|
+
sx?: SxProps<Theme>;
|
|
15
|
+
className?: string;
|
|
16
|
+
'data-testid'?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Estado vacío centrado, para usar dentro de una card, un tab o una tabla sin
|
|
20
|
+
* resultados. Color y tipografía salen del theme del consumidor: no hay
|
|
21
|
+
* hex ni tamaños hardcodeados.
|
|
22
|
+
*/
|
|
23
|
+
export declare function EmptyState({ title, message, icon, action, preset, sx, className, 'data-testid': dataTestId, }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export default EmptyState;
|