@stackcraftmx/calcita 0.27.0 → 0.28.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/README.md +10 -0
- package/dist/index.js +3 -1
- package/dist/inputs/FormSection.js +5 -2
- package/dist/inputs/FormSection.js.map +1 -1
- package/dist/theme/components/minimalComponents.js +4 -4
- package/dist/theme/components/minimalComponents.js.map +1 -1
- package/dist/theme/createToolkitTheme.js +15 -5
- package/dist/theme/createToolkitTheme.js.map +1 -1
- package/dist/theme/glassSurface.js +56 -8
- package/dist/theme/glassSurface.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/theme/createToolkitTheme.d.ts +22 -1
- package/dist/types/theme/glassSurface.d.ts +54 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -263,6 +263,16 @@ navegador: `isAndroidDevice({userAgent: headers.get('user-agent')})`. Sirve para
|
|
|
263
263
|
const theme = isAndroidDevice() ? createToolkitTheme({look: THEME_LOOK.minimal}) : createToolkitTheme({glass: true});
|
|
264
264
|
```
|
|
265
265
|
|
|
266
|
+
Los campos de captura (con vidrio, con el minimalista y dentro de `FormSection`) traen el gris de relleno de Apple. Para que
|
|
267
|
+
se vean como los de su sistema: `fields`, por modo, con el relleno (`fill`), el relleno con el cursor encima (`hoverFill`),
|
|
268
|
+
la orilla (`border`) y la orilla con el cursor encima (`hoverBorder`); y sus esquinas (`radius`). Lo que no se pase se queda
|
|
269
|
+
como lo trae el estilo (`FIELD_TONES`). Van en la paleta de cada modo (`palette.field`): cambian solos con el modo y también
|
|
270
|
+
se pueden escribir en `colorSchemes`.
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
createToolkitTheme({glass: true, fields: {radius: 8, light: {fill: '#FFFFFF', hoverFill: '#FFFFFF', border: '#C4CDD5'}}});
|
|
274
|
+
```
|
|
275
|
+
|
|
266
276
|
El minimalista separa las superficies por su tono con los grises de Apple. Para pintarlo con los colores de la marca:
|
|
267
277
|
`minimalTones`, por modo, con el fondo de la página (`default`), las tarjetas (`paper`), el relleno de campos, grupos y
|
|
268
278
|
botones sin color (`fill`) y lo que flota, como la barra del teléfono (`floating`). Lo que no se pase se queda con el gris
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import { MINIMAL_BACKGROUND, MINIMAL_TONES } from "./theme/components/minimalCom
|
|
|
25
25
|
import { STACKCRAFT, stackcraftDarkPalette, stackcraftLightPalette } from "./theme/stackcraftPalette.js";
|
|
26
26
|
import { toolkitComponents } from "./theme/toolkitComponents.js";
|
|
27
27
|
import { mergeComponents } from "./theme/mergeComponents.js";
|
|
28
|
-
import { GLASS_INSET_PIXELS, GLASS_MENU_RADIUS_PIXELS, GLASS_OPACITY, GLASS_PANEL_RADIUS_PIXELS, accentTextStylesOf, ambientBackgroundOf, canvasFieldStylesOf, fieldWellStylesOf, fixedBackgroundLayerOf, glassDropOf, glassStylesOf, glassSurfaceOf, isGlassTheme, materialBackgroundOf, materialStylesOf, materialSurfaceOf, scrollEdgeStylesOf } from "./theme/glassSurface.js";
|
|
28
|
+
import { FIELD_TONES, GLASS_INSET_PIXELS, GLASS_MENU_RADIUS_PIXELS, GLASS_OPACITY, GLASS_PANEL_RADIUS_PIXELS, accentTextStylesOf, ambientBackgroundOf, canvasFieldStylesOf, fieldPaletteOf, fieldWellStylesOf, fixedBackgroundLayerOf, glassDropOf, glassStylesOf, glassSurfaceOf, isGlassTheme, materialBackgroundOf, materialStylesOf, materialSurfaceOf, scrollEdgeStylesOf } from "./theme/glassSurface.js";
|
|
29
29
|
import { AppLayout, MENU_POSITION } from "./appShell/AppLayout.js";
|
|
30
30
|
import { AuthLayout } from "./appShell/AuthLayout.js";
|
|
31
31
|
import { default as default11 } from "./appShell/BarActions.js";
|
|
@@ -178,6 +178,7 @@ export {
|
|
|
178
178
|
default50 as DownloadMenu,
|
|
179
179
|
ERROR_PAGE_KIND,
|
|
180
180
|
default22 as ErrorPage,
|
|
181
|
+
FIELD_TONES,
|
|
181
182
|
FILE_ACCEPT_PRESETS,
|
|
182
183
|
FILE_REJECTION,
|
|
183
184
|
FONT_SIZE_LEVELS,
|
|
@@ -287,6 +288,7 @@ export {
|
|
|
287
288
|
downloadsMachine,
|
|
288
289
|
errorsObjectToMessage,
|
|
289
290
|
fieldErrorsOf,
|
|
291
|
+
fieldPaletteOf,
|
|
290
292
|
fieldWellStylesOf,
|
|
291
293
|
fileNameFromContentDisposition,
|
|
292
294
|
fixedBackgroundLayerOf,
|
|
@@ -5,7 +5,7 @@ import Box from "@mui/material/Box";
|
|
|
5
5
|
import Paper from "@mui/material/Paper";
|
|
6
6
|
import Typography from "@mui/material/Typography";
|
|
7
7
|
import { FormSectionContext } from "./formLayoutContext.js";
|
|
8
|
-
import { GLASS_PANEL_RADIUS_PIXELS, accentTextStylesOf,
|
|
8
|
+
import { GLASS_PANEL_RADIUS_PIXELS, fieldVariablesOf, accentTextStylesOf, fieldWellFromVariablesOf } from "../theme/glassSurface.js";
|
|
9
9
|
const FORM_ROW_CLASS = "calcita-form-row";
|
|
10
10
|
const ROW_MIN_HEIGHT_PIXELS = 52;
|
|
11
11
|
const ROW_PADDING_BLOCK_PIXELS = 8;
|
|
@@ -18,7 +18,8 @@ function rowControlSxOf(theme) {
|
|
|
18
18
|
const roots = [".MuiOutlinedInput-root", ".MuiFilledInput-root", ".MuiPickersOutlinedInput-root"];
|
|
19
19
|
const ringOf = (color, percent) => ({ outline: `${RING.pixels}px solid color-mix(in srgb, ${color} ${percent}%, transparent)`, outlineOffset: 0 });
|
|
20
20
|
return {
|
|
21
|
-
|
|
21
|
+
// los tonos van en variables del renglón (fieldVariablesOf, abajo en FormRow): aquí abajo una regla de oscuro no aplica
|
|
22
|
+
[strong(roots)]: { ...fieldWellFromVariablesOf(theme), outline: "none" },
|
|
22
23
|
[strong(roots.map((root) => `${root}.Mui-focused`))]: ringOf(palette.primary.main, RING.focusPercent),
|
|
23
24
|
[strong(roots.map((root) => `${root}.Mui-error`))]: ringOf(palette.error.main, RING.errorPercent),
|
|
24
25
|
[strong([".MuiOutlinedInput-notchedOutline", ".MuiPickersOutlinedInput-notchedOutline"])]: { display: "none" },
|
|
@@ -49,6 +50,8 @@ function FormRow({ label, htmlFor, labelId, children }) {
|
|
|
49
50
|
py: `${ROW_PADDING_BLOCK_PIXELS}px`,
|
|
50
51
|
"&:focus-within > label": accentTextStylesOf(theme),
|
|
51
52
|
"&:has(.Mui-error) > label": { color: palette.error.main },
|
|
53
|
+
// los tonos de los campos (los del proyecto con createToolkitTheme fields, o los de Apple) para sus campos
|
|
54
|
+
...fieldVariablesOf(theme),
|
|
52
55
|
...rowControlSxOf(theme)
|
|
53
56
|
};
|
|
54
57
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormSection.js","sources":["../../src/inputs/FormSection.jsx"],"sourcesContent":["// El formulario agrupado de Apple (el de Ajustes y el de la hoja «Nuevo evento» de Calendario): una tarjeta redonda con\n// renglones, el título de la sección arriba de la tarjeta y la explicación abajo. Dentro de una FormSection cada campo del\n// framework (TextInput, NumberInput, SelectInput, CatalogInput, ColorInput, DateInput y sus versiones de formik y de\n// react-hook-form) se pinta solo como renglón: la etiqueta a la izquierda y el campo a la derecha.\n//\n// <FormSection title=\"Datos del cliente\" footer=\"Le enviaremos la factura al correo.\">\n// <FormTextField name=\"name\" label=\"Nombre\" />\n// <FormTextField name=\"email\" label=\"Correo\" />\n// <FormRow label=\"Recibir avisos\"><Switch /></FormRow>\n// </FormSection>\n//\n// Las reglas, de la guía de Apple (HIG «Text fields», «Pickers», «Combo boxes» y sus imágenes):\n// - la etiqueta siempre a la vista, a la izquierda (la pista se va al escribir; la etiqueta no);\n// - el campo es un «pozo» parejo con esquinas de 12 px (fieldWellStylesOf): gris tenue en claro y más oscuro que la\n// tarjeta en oscuro, con la letra clara, como el campo de la imagen de Apple. Antes iba transparente y el relleno solo\n// salía con el cursor encima, en cuadro: no se entendía dónde escribir (lo reportaron);\n// - la fecha es el mismo campo que los demás, a todo lo ancho (en cápsula al final del renglón quedaba descuadrada), con\n// la letra del texto (no del color del tema: en oscuro el naranja ahí «se veía horrible», lo reportaron);\n// - al escribir, un aro tenue del color principal y la etiqueta del color del tema; con error, aro y etiqueta en rojo y\n// el mensaje debajo del campo;\n// - una línea fina entre renglones, que empieza donde empieza el texto.\n//\n// Los campos pueden ir directo o dentro de lo que el proyecto necesite (un Grid de dos columnas, un Stack, un componente\n// suyo): cada renglón dibuja su propia línea ARRIBA y la tarjeta sube su contenido un píxel y lo recorta, así la línea del\n// primero queda escondida. OJO: antes la línea se dibujaba entre dos hermanos seguidos y con un Grid en medio desaparecían\n// todas (lo señalaron en una revisión: obligaba a «la forma Calcita»).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId} from 'react';\nimport Box from '@mui/material/Box';\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\n\nimport {FormSectionContext} from '@/inputs/formLayoutContext.js';\nimport {GLASS_PANEL_RADIUS_PIXELS, accentTextStylesOf, fieldWellStylesOf} from '@/theme/glassSurface.js';\n\n/** La clase de cada renglón: la sección le dibuja su línea de arriba, esté donde esté adentro de la tarjeta. */\nexport const FORM_ROW_CLASS = 'calcita-form-row';\n\n// el renglón: alto mínimo para el dedo, su aire arriba y abajo, y lo ancho de la columna de las etiquetas\nconst ROW_MIN_HEIGHT_PIXELS = 52;\nconst ROW_PADDING_BLOCK_PIXELS = 8;\nconst LABEL_COLUMN = Object.freeze({share: '38%', maxPixels: 200});\n// lo que la etiqueta baja para quedar en la misma línea que el texto del campo (el campo mide 40 px y su letra 24 px)\nconst LABEL_TOP_PIXELS = 8;\n// el aro al escribir y con error (por ciento del color) y su grosor\nconst RING = Object.freeze({focusPercent: 45, errorPercent: 60, pixels: 2});\n\n/**\n * Los campos de MUI dentro de un renglón: el pozo de Apple (fieldWellStylesOf), sin el borde de MUI ni el vidrio del tema,\n * con su aro al escribir. Los selectores van con «html body &&&» para ganarle a los ajustes del tema dentro de una\n * tarjeta, que con el lente llevan una etiqueta y hasta cuatro clases (con menos, el relleno del tema salía al pasar el\n * cursor, en cuadro: los «hovers espantosos» que reportaron).\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction rowControlSxOf(theme) {\n const palette = (theme.vars ?? theme).palette;\n const strong = (selectors) => selectors.map((selector) => `html body &&& ${selector}`).join(', ');\n const roots = ['.MuiOutlinedInput-root', '.MuiFilledInput-root', '.MuiPickersOutlinedInput-root'];\n const ringOf = (color, percent) => ({outline: `${RING.pixels}px solid color-mix(in srgb, ${color} ${percent}%, transparent)`, outlineOffset: 0});\n return {\n [strong(roots)]: {...fieldWellStylesOf(theme), outline: 'none'},\n [strong(roots.map((root) => `${root}.Mui-focused`))]: ringOf(palette.primary.main, RING.focusPercent),\n [strong(roots.map((root) => `${root}.Mui-error`))]: ringOf(palette.error.main, RING.errorPercent),\n [strong(['.MuiOutlinedInput-notchedOutline', '.MuiPickersOutlinedInput-notchedOutline'])]: {display: 'none'},\n [strong(['.MuiFilledInput-root::before', '.MuiFilledInput-root::after'])]: {display: 'none'},\n // la fecha: el mismo campo que los demás, a todo lo ancho de su columna (en cápsula al final del renglón quedaba\n // descuadrada, con su ayuda a la izquierda debajo de nada; lo reportaron), con el ícono del calendario discreto\n [strong(['.MuiPickersOutlinedInput-root'])]: {color: palette.text.primary},\n [strong(['.MuiPickersOutlinedInput-root .MuiInputAdornment-root .MuiSvgIcon-root'])]: {fontSize: '1.125rem', color: palette.text.secondary},\n // la ayuda y el error, debajo del campo; el renglón no guarda lugar para una ayuda vacía\n '& .MuiFormHelperText-root': {marginInline: theme.spacing(0.5), marginTop: '4px', marginBottom: '2px'},\n '& .MuiFormHelperText-root:has(> .notranslate:only-child)': {display: 'none'},\n };\n}\n\n/**\n * Un renglón del formulario agrupado: la etiqueta a la izquierda y lo que sea a la derecha (un campo, un interruptor, un\n * texto). Los campos del framework lo usan solos dentro de una FormSection; FormRow suelto es para lo demás.\n *\n * @param {object} props\n * @param {import('react').ReactNode} props.label ya traducida\n * @param {string} [props.htmlFor] el id del campo que nombra la etiqueta\n * @param {string} [props.labelId] el id de la etiqueta (para un campo que la nombra con aria-labelledby)\n * @param {import('react').ReactNode} props.children\n */\nexport function FormRow({label, htmlFor, labelId, children}) {\n return (\n <Box className={FORM_ROW_CLASS}\n sx={(theme) => {\n const palette = (theme.vars ?? theme).palette;\n return {\n position: 'relative',\n display: 'flex',\n alignItems: 'flex-start',\n gap: 2,\n minHeight: ROW_MIN_HEIGHT_PIXELS,\n px: 2,\n py: `${ROW_PADDING_BLOCK_PIXELS}px`,\n '&:focus-within > label': accentTextStylesOf(theme),\n '&:has(.Mui-error) > label': {color: palette.error.main},\n ...rowControlSxOf(theme),\n };\n }}>\n <Typography component=\"label\" id={labelId} htmlFor={htmlFor} variant=\"body1\"\n sx={{flex: `0 0 ${LABEL_COLUMN.share}`, maxWidth: LABEL_COLUMN.maxPixels, pt: `${LABEL_TOP_PIXELS}px`, lineHeight: 1.5, color: 'text.primary'}}>\n {label}\n </Typography>\n <Box sx={{flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center', minHeight: 40}}>\n {children}\n </Box>\n </Box>\n );\n}\n\n/**\n * @param {object} props\n * @param {string} [props.title] ya traducido; va arriba de la tarjeta\n * @param {import('react').ReactNode} [props.footer] la explicación, abajo de la tarjeta\n * @param {import('react').ReactNode} props.children los campos, directo o dentro de un Grid, un Stack o un componente propio\n */\nexport default function FormSection({title, footer, children}) {\n const titleId = useId();\n return (\n <FormSectionContext value>\n <Box component=\"section\" aria-labelledby={title ? titleId : undefined}>\n {title && (\n <Typography id={titleId} variant=\"subtitle2\" component=\"h2\" color=\"text.secondary\" sx={{px: 2, mb: 0.75, fontWeight: 600}}>\n {title}\n </Typography>\n )}\n <Paper variant=\"outlined\"\n sx={(theme) => ({\n borderRadius: `${GLASS_PANEL_RADIUS_PIXELS}px`,\n overflow: 'hidden',\n // la línea de arriba de cada renglón, desde donde empieza el texto (la del primero la recorta la tarjeta)\n [`& .${FORM_ROW_CLASS}::before`]: {\n content: '\"\"', position: 'absolute', top: 0, right: 0, left: theme.spacing(2), height: '1px',\n backgroundColor: (theme.vars ?? theme).palette.divider,\n },\n })}>\n {/* un píxel arriba: la línea de los renglones de hasta arriba queda fuera de la tarjeta (overflow hidden) */}\n <Box sx={{mt: '-1px'}}>{children}</Box>\n </Paper>\n {footer && (\n <Typography variant=\"caption\" component=\"p\" color=\"text.secondary\" sx={{px: 2, mt: 0.75}}>{footer}</Typography>\n )}\n </Box>\n </FormSectionContext>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FormSection.js","sources":["../../src/inputs/FormSection.jsx"],"sourcesContent":["// El formulario agrupado de Apple (el de Ajustes y el de la hoja «Nuevo evento» de Calendario): una tarjeta redonda con\n// renglones, el título de la sección arriba de la tarjeta y la explicación abajo. Dentro de una FormSection cada campo del\n// framework (TextInput, NumberInput, SelectInput, CatalogInput, ColorInput, DateInput y sus versiones de formik y de\n// react-hook-form) se pinta solo como renglón: la etiqueta a la izquierda y el campo a la derecha.\n//\n// <FormSection title=\"Datos del cliente\" footer=\"Le enviaremos la factura al correo.\">\n// <FormTextField name=\"name\" label=\"Nombre\" />\n// <FormTextField name=\"email\" label=\"Correo\" />\n// <FormRow label=\"Recibir avisos\"><Switch /></FormRow>\n// </FormSection>\n//\n// Las reglas, de la guía de Apple (HIG «Text fields», «Pickers», «Combo boxes» y sus imágenes):\n// - la etiqueta siempre a la vista, a la izquierda (la pista se va al escribir; la etiqueta no);\n// - el campo es un «pozo» parejo con esquinas de 12 px (fieldWellStylesOf): gris tenue en claro y más claro que la\n// tarjeta en oscuro, con la letra clara, como el campo de la imagen de Apple. Antes iba transparente y el relleno solo\n// salía con el cursor encima, en cuadro: no se entendía dónde escribir (lo reportaron);\n// - la fecha es el mismo campo que los demás, a todo lo ancho (en cápsula al final del renglón quedaba descuadrada), con\n// la letra del texto (no del color del tema: en oscuro el naranja ahí «se veía horrible», lo reportaron);\n// - al escribir, un aro tenue del color principal y la etiqueta del color del tema; con error, aro y etiqueta en rojo y\n// el mensaje debajo del campo;\n// - una línea fina entre renglones, que empieza donde empieza el texto.\n//\n// Los campos pueden ir directo o dentro de lo que el proyecto necesite (un Grid de dos columnas, un Stack, un componente\n// suyo): cada renglón dibuja su propia línea ARRIBA y la tarjeta sube su contenido un píxel y lo recorta, así la línea del\n// primero queda escondida. OJO: antes la línea se dibujaba entre dos hermanos seguidos y con un Grid en medio desaparecían\n// todas (lo señalaron en una revisión: obligaba a «la forma Calcita»).\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useId} from 'react';\nimport Box from '@mui/material/Box';\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\n\nimport {FormSectionContext} from '@/inputs/formLayoutContext.js';\nimport {GLASS_PANEL_RADIUS_PIXELS, accentTextStylesOf, fieldVariablesOf, fieldWellFromVariablesOf} from '@/theme/glassSurface.js';\n\n/** La clase de cada renglón: la sección le dibuja su línea de arriba, esté donde esté adentro de la tarjeta. */\nexport const FORM_ROW_CLASS = 'calcita-form-row';\n\n// el renglón: alto mínimo para el dedo, su aire arriba y abajo, y lo ancho de la columna de las etiquetas\nconst ROW_MIN_HEIGHT_PIXELS = 52;\nconst ROW_PADDING_BLOCK_PIXELS = 8;\nconst LABEL_COLUMN = Object.freeze({share: '38%', maxPixels: 200});\n// lo que la etiqueta baja para quedar en la misma línea que el texto del campo (el campo mide 40 px y su letra 24 px)\nconst LABEL_TOP_PIXELS = 8;\n// el aro al escribir y con error (por ciento del color) y su grosor\nconst RING = Object.freeze({focusPercent: 45, errorPercent: 60, pixels: 2});\n\n/**\n * Los campos de MUI dentro de un renglón: el pozo de Apple (fieldWellStylesOf), sin el borde de MUI ni el vidrio del tema,\n * con su aro al escribir. Los selectores van con «html body &&&» para ganarle a los ajustes del tema dentro de una\n * tarjeta, que con el lente llevan una etiqueta y hasta cuatro clases (con menos, el relleno del tema salía al pasar el\n * cursor, en cuadro: los «hovers espantosos» que reportaron).\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction rowControlSxOf(theme) {\n const palette = (theme.vars ?? theme).palette;\n const strong = (selectors) => selectors.map((selector) => `html body &&& ${selector}`).join(', ');\n const roots = ['.MuiOutlinedInput-root', '.MuiFilledInput-root', '.MuiPickersOutlinedInput-root'];\n const ringOf = (color, percent) => ({outline: `${RING.pixels}px solid color-mix(in srgb, ${color} ${percent}%, transparent)`, outlineOffset: 0});\n return {\n // los tonos van en variables del renglón (fieldVariablesOf, abajo en FormRow): aquí abajo una regla de oscuro no aplica\n [strong(roots)]: {...fieldWellFromVariablesOf(theme), outline: 'none'},\n [strong(roots.map((root) => `${root}.Mui-focused`))]: ringOf(palette.primary.main, RING.focusPercent),\n [strong(roots.map((root) => `${root}.Mui-error`))]: ringOf(palette.error.main, RING.errorPercent),\n [strong(['.MuiOutlinedInput-notchedOutline', '.MuiPickersOutlinedInput-notchedOutline'])]: {display: 'none'},\n [strong(['.MuiFilledInput-root::before', '.MuiFilledInput-root::after'])]: {display: 'none'},\n // la fecha: el mismo campo que los demás, a todo lo ancho de su columna (en cápsula al final del renglón quedaba\n // descuadrada, con su ayuda a la izquierda debajo de nada; lo reportaron), con el ícono del calendario discreto\n [strong(['.MuiPickersOutlinedInput-root'])]: {color: palette.text.primary},\n [strong(['.MuiPickersOutlinedInput-root .MuiInputAdornment-root .MuiSvgIcon-root'])]: {fontSize: '1.125rem', color: palette.text.secondary},\n // la ayuda y el error, debajo del campo; el renglón no guarda lugar para una ayuda vacía\n '& .MuiFormHelperText-root': {marginInline: theme.spacing(0.5), marginTop: '4px', marginBottom: '2px'},\n '& .MuiFormHelperText-root:has(> .notranslate:only-child)': {display: 'none'},\n };\n}\n\n/**\n * Un renglón del formulario agrupado: la etiqueta a la izquierda y lo que sea a la derecha (un campo, un interruptor, un\n * texto). Los campos del framework lo usan solos dentro de una FormSection; FormRow suelto es para lo demás.\n *\n * @param {object} props\n * @param {import('react').ReactNode} props.label ya traducida\n * @param {string} [props.htmlFor] el id del campo que nombra la etiqueta\n * @param {string} [props.labelId] el id de la etiqueta (para un campo que la nombra con aria-labelledby)\n * @param {import('react').ReactNode} props.children\n */\nexport function FormRow({label, htmlFor, labelId, children}) {\n return (\n <Box className={FORM_ROW_CLASS}\n sx={(theme) => {\n const palette = (theme.vars ?? theme).palette;\n return {\n position: 'relative',\n display: 'flex',\n alignItems: 'flex-start',\n gap: 2,\n minHeight: ROW_MIN_HEIGHT_PIXELS,\n px: 2,\n py: `${ROW_PADDING_BLOCK_PIXELS}px`,\n '&:focus-within > label': accentTextStylesOf(theme),\n '&:has(.Mui-error) > label': {color: palette.error.main},\n // los tonos de los campos (los del proyecto con createToolkitTheme fields, o los de Apple) para sus campos\n ...fieldVariablesOf(theme),\n ...rowControlSxOf(theme),\n };\n }}>\n <Typography component=\"label\" id={labelId} htmlFor={htmlFor} variant=\"body1\"\n sx={{flex: `0 0 ${LABEL_COLUMN.share}`, maxWidth: LABEL_COLUMN.maxPixels, pt: `${LABEL_TOP_PIXELS}px`, lineHeight: 1.5, color: 'text.primary'}}>\n {label}\n </Typography>\n <Box sx={{flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', justifyContent: 'center', minHeight: 40}}>\n {children}\n </Box>\n </Box>\n );\n}\n\n/**\n * @param {object} props\n * @param {string} [props.title] ya traducido; va arriba de la tarjeta\n * @param {import('react').ReactNode} [props.footer] la explicación, abajo de la tarjeta\n * @param {import('react').ReactNode} props.children los campos, directo o dentro de un Grid, un Stack o un componente propio\n */\nexport default function FormSection({title, footer, children}) {\n const titleId = useId();\n return (\n <FormSectionContext value>\n <Box component=\"section\" aria-labelledby={title ? titleId : undefined}>\n {title && (\n <Typography id={titleId} variant=\"subtitle2\" component=\"h2\" color=\"text.secondary\" sx={{px: 2, mb: 0.75, fontWeight: 600}}>\n {title}\n </Typography>\n )}\n <Paper variant=\"outlined\"\n sx={(theme) => ({\n borderRadius: `${GLASS_PANEL_RADIUS_PIXELS}px`,\n overflow: 'hidden',\n // la línea de arriba de cada renglón, desde donde empieza el texto (la del primero la recorta la tarjeta)\n [`& .${FORM_ROW_CLASS}::before`]: {\n content: '\"\"', position: 'absolute', top: 0, right: 0, left: theme.spacing(2), height: '1px',\n backgroundColor: (theme.vars ?? theme).palette.divider,\n },\n })}>\n {/* un píxel arriba: la línea de los renglones de hasta arriba queda fuera de la tarjeta (overflow hidden) */}\n <Box sx={{mt: '-1px'}}>{children}</Box>\n </Paper>\n {footer && (\n <Typography variant=\"caption\" component=\"p\" color=\"text.secondary\" sx={{px: 2, mt: 0.75}}>{footer}</Typography>\n )}\n </Box>\n </FormSectionContext>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAqCO,MAAM,iBAAiB;AAG9B,MAAM,wBAAwB;AAC9B,MAAM,2BAA2B;AACjC,MAAM,eAAe,OAAO,OAAO,EAAC,OAAO,OAAO,WAAW,KAAI;AAEjE,MAAM,mBAAmB;AAEzB,MAAM,OAAO,OAAO,OAAO,EAAC,cAAc,IAAI,cAAc,IAAI,QAAQ,GAAE;AAW1E,SAAS,eAAe,OAAO;AAC3B,QAAM,WAAW,MAAM,QAAQ,OAAO;AACtC,QAAM,SAAS,CAAC,cAAc,UAAU,IAAI,CAAC,aAAa,iBAAiB,QAAQ,EAAE,EAAE,KAAK,IAAI;AAChG,QAAM,QAAQ,CAAC,0BAA0B,wBAAwB,+BAA+B;AAChG,QAAM,SAAS,CAAC,OAAO,aAAa,EAAC,SAAS,GAAG,KAAK,MAAM,+BAA+B,KAAK,IAAI,OAAO,mBAAmB,eAAe;AAC7I,SAAO;AAAA;AAAA,IAEH,CAAC,OAAO,KAAK,CAAC,GAAG,EAAC,GAAG,yBAAyB,KAAK,GAAG,SAAS,OAAA;AAAA,IAC/D,CAAC,OAAO,MAAM,IAAI,CAAC,SAAS,GAAG,IAAI,cAAc,CAAC,CAAC,GAAG,OAAO,QAAQ,QAAQ,MAAM,KAAK,YAAY;AAAA,IACpG,CAAC,OAAO,MAAM,IAAI,CAAC,SAAS,GAAG,IAAI,YAAY,CAAC,CAAC,GAAG,OAAO,QAAQ,MAAM,MAAM,KAAK,YAAY;AAAA,IAChG,CAAC,OAAO,CAAC,oCAAoC,yCAAyC,CAAC,CAAC,GAAG,EAAC,SAAS,OAAA;AAAA,IACrG,CAAC,OAAO,CAAC,gCAAgC,6BAA6B,CAAC,CAAC,GAAG,EAAC,SAAS,OAAA;AAAA;AAAA;AAAA,IAGrF,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAC,GAAG,EAAC,OAAO,QAAQ,KAAK,QAAA;AAAA,IAClE,CAAC,OAAO,CAAC,wEAAwE,CAAC,CAAC,GAAG,EAAC,UAAU,YAAY,OAAO,QAAQ,KAAK,UAAA;AAAA;AAAA,IAEjI,6BAA6B,EAAC,cAAc,MAAM,QAAQ,GAAG,GAAG,WAAW,OAAO,cAAc,MAAA;AAAA,IAChG,4DAA4D,EAAC,SAAS,OAAA;AAAA,EAAM;AAEpF;AAYO,SAAS,QAAQ,EAAC,OAAO,SAAS,SAAS,YAAW;AACzD,SACI;AAAA,IAAC;AAAA,IAAA;AAAA,MAAI,WAAW;AAAA,MACX,IAAI,CAAC,UAAU;AACX,cAAM,WAAW,MAAM,QAAQ,OAAO;AACtC,eAAO;AAAA,UACH,UAAU;AAAA,UACV,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,KAAK;AAAA,UACL,WAAW;AAAA,UACX,IAAI;AAAA,UACJ,IAAI,GAAG,wBAAwB;AAAA,UAC/B,0BAA0B,mBAAmB,KAAK;AAAA,UAClD,6BAA6B,EAAC,OAAO,QAAQ,MAAM,KAAA;AAAA;AAAA,UAEnD,GAAG,iBAAiB,KAAK;AAAA,UACzB,GAAG,eAAe,KAAK;AAAA,QAAA;AAAA,MAE/B;AAAA,MACD,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YAAW,WAAU;AAAA,YAAQ,IAAI;AAAA,YAAS;AAAA,YAAkB,SAAQ;AAAA,YACzD,IAAI,EAAC,MAAM,OAAO,aAAa,KAAK,IAAI,UAAU,aAAa,WAAW,IAAI,GAAG,gBAAgB,MAAM,YAAY,KAAK,OAAO,eAAA;AAAA,YACtI,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,4BAEJ,KAAA,EAAI,IAAI,EAAC,MAAM,GAAG,UAAU,GAAG,SAAS,QAAQ,eAAe,UAAU,gBAAgB,UAAU,WAAW,GAAA,GAC1G,SAAA,CACL;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGZ;AAQA,SAAwB,YAAY,EAAC,OAAO,QAAQ,YAAW;AAC3D,QAAM,UAAU,MAAA;AAChB,SACI,oBAAC,oBAAA,EAAmB,OAAK,MACrB,UAAA,qBAAC,KAAA,EAAI,WAAU,WAAU,mBAAiB,QAAQ,UAAU,QACvD,UAAA;AAAA,IAAA,6BACI,YAAA,EAAW,IAAI,SAAS,SAAQ,aAAY,WAAU,MAAK,OAAM,kBAAiB,IAAI,EAAC,IAAI,GAAG,IAAI,MAAM,YAAY,IAAA,GAChH,UAAA,OACL;AAAA,IAEJ;AAAA,MAAC;AAAA,MAAA;AAAA,QAAM,SAAQ;AAAA,QACR,IAAI,CAAC,WAAW;AAAA,UACZ,cAAc,GAAG,yBAAyB;AAAA,UAC1C,UAAU;AAAA;AAAA,UAEV,CAAC,MAAM,cAAc,UAAU,GAAG;AAAA,YAC9B,SAAS;AAAA,YAAM,UAAU;AAAA,YAAY,KAAK;AAAA,YAAG,OAAO;AAAA,YAAG,MAAM,MAAM,QAAQ,CAAC;AAAA,YAAG,QAAQ;AAAA,YACvF,kBAAkB,MAAM,QAAQ,OAAO,QAAQ;AAAA,UAAA;AAAA,QACnD;AAAA,QAGP,8BAAC,KAAA,EAAI,IAAI,EAAC,IAAI,OAAA,GAAU,SAAA,CAAS;AAAA,MAAA;AAAA,IAAA;AAAA,IAEpC,UACG,oBAAC,YAAA,EAAW,SAAQ,WAAU,WAAU,KAAI,OAAM,kBAAiB,IAAI,EAAC,IAAI,GAAG,IAAI,KAAA,GAAQ,UAAA,OAAA,CAAO;AAAA,EAAA,EAAA,CAE1G,EAAA,CACJ;AAER;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { paletteOf } from "./paletteOf.js";
|
|
2
2
|
import { textSizeOf } from "../appleTracking.js";
|
|
3
|
-
import { accentTextStylesOf } from "../glassSurface.js";
|
|
3
|
+
import { accentTextStylesOf, fieldWellStylesOf } from "../glassSurface.js";
|
|
4
4
|
import { lightDarkStylesOf } from "../lightDarkStyles.js";
|
|
5
5
|
const MINIMAL_TONES = Object.freeze({
|
|
6
6
|
light: Object.freeze({ default: "#F2F2F7", paper: "#FFFFFF", fill: "rgba(118, 118, 128, 0.12)", floating: "#E5E5EA" }),
|
|
@@ -77,9 +77,9 @@ function minimalComponents() {
|
|
|
77
77
|
MuiButtonGroup: { defaultProps: { disableElevation: true } },
|
|
78
78
|
MuiOutlinedInput: {
|
|
79
79
|
styleOverrides: {
|
|
80
|
+
// el campo: los tonos de los campos del tema (por omisión, el relleno del minimalista; ver createToolkitTheme)
|
|
80
81
|
root: ({ theme }) => ({
|
|
81
|
-
...
|
|
82
|
-
borderRadius: RADIUS_PIXELS.control,
|
|
82
|
+
...fieldWellStylesOf(theme, { radius: RADIUS_PIXELS.control }),
|
|
83
83
|
"&.Mui-focused": { outline: `2px solid ${tintOf(theme, "primary", TINT_PERCENT.ring)}` },
|
|
84
84
|
"&.Mui-error": { outline: `2px solid ${tintOf(theme, "error", TINT_PERCENT.ring)}` }
|
|
85
85
|
}),
|
|
@@ -88,7 +88,7 @@ function minimalComponents() {
|
|
|
88
88
|
},
|
|
89
89
|
MuiFilledInput: {
|
|
90
90
|
defaultProps: { disableUnderline: true },
|
|
91
|
-
styleOverrides: { root: ({ theme }) => (
|
|
91
|
+
styleOverrides: { root: ({ theme }) => fieldWellStylesOf(theme, { radius: RADIUS_PIXELS.control }) }
|
|
92
92
|
},
|
|
93
93
|
// la etiqueta con borde también es tonal: el tinte de su color (o el gris si no lleva color)
|
|
94
94
|
MuiChip: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"minimalComponents.js","sources":["../../../src/theme/components/minimalComponents.js"],"sourcesContent":["// El estilo minimalista (createToolkitTheme({look: 'minimal'})): plano y tonal, como pidió el autor («casi solo colores, sin\n// bordes, que el mismo color diga dónde están las superficies»; su referencia: BELOW y Samurai Jack, formas de bloques de\n// color sin contorno y una sola luz de acento).\n//\n// Las reglas:\n// - sin bordes ni sombras: las superficies se separan por su tono, por omisión con los grises de Apple (MINIMAL_TONES: el\n// fondo agrupado gris y las tarjetas un escalón arriba; los campos, el gris de relleno; lo que flota, un gris más). Cada\n// proyecto puede pasar los suyos (createToolkitTheme minimalTones) y el minimalista se pinta con su marca;\n// - un solo color de acento: el botón principal, lo elegido (un tinte suave de su color, sin marco) y las ligas; lo demás\n// neutro. El botón con borde y la etiqueta con borde pasan a «tonales»: el tinte de su color, sin la raya;\n// - sin vidrio ni degradados: superficies sólidas.\n// Va encima de los ajustes del framework (toolkitComponents) y el proyecto puede sumar los suyos encima.\n//\n// Funciones puras, sin React: function (regla de la casa).\nimport {paletteOf} from '@/theme/components/paletteOf.js';\nimport {textSizeOf} from '@/theme/appleTracking.js';\nimport {accentTextStylesOf} from '@/theme/glassSurface.js';\nimport {lightDarkStylesOf} from '@/theme/lightDarkStyles.js';\n\n/**\n * Los tonos del minimalista por omisión, los grises de Apple, en claro y en oscuro:\n * - default: el fondo de la página (el gris agrupado);\n * - paper: las tarjetas, un escalón arriba;\n * - fill: el relleno de campos, grupos y botones sin color (más claro que el fondo en oscuro);\n * - floating: lo que flota sobre el contenido (la barra de pestañas del teléfono, el aviso de versión nueva), un escalón\n * más oscuro que las tarjetas. Del color de las tarjetas «se perdía» sobre ellas (lo dijo el autor de la primera barra\n * de abajo del minimalista); así se distingue sin borde ni sombra, sobre tarjetas y sobre el fondo.\n */\nexport const MINIMAL_TONES = Object.freeze({\n light: Object.freeze({default: '#F2F2F7', paper: '#FFFFFF', fill: 'rgba(118, 118, 128, 0.12)', floating: '#E5E5EA'}),\n dark: Object.freeze({default: '#000000', paper: '#1C1C1E', fill: 'rgba(118, 118, 128, 0.24)', floating: '#2C2C2E'}),\n});\n\n/** Los fondos del minimalista por omisión (los de MINIMAL_TONES): el gris agrupado de Apple y la tarjeta un escalón arriba. */\nexport const MINIMAL_BACKGROUND = Object.freeze({\n light: {default: MINIMAL_TONES.light.default, paper: MINIMAL_TONES.light.paper},\n dark: {default: MINIMAL_TONES.dark.default, paper: MINIMAL_TONES.dark.paper},\n});\n\n/**\n * Los tonos del minimalista con los del proyecto encima: lo que el proyecto no trae se queda con el gris de Apple.\n *\n * @param {{light?: object, dark?: object}} [projectTones] cualquiera de default, paper, fill y floating por modo\n * @returns {{light: {default: string, paper: string, fill: string, floating: string}, dark: {default: string, paper: string, fill: string, floating: string}}}\n */\nexport function minimalTonesOf(projectTones = {}) {\n return {\n light: {...MINIMAL_TONES.light, ...projectTones.light},\n dark: {...MINIMAL_TONES.dark, ...projectTones.dark},\n };\n}\n\n/** Los tonos con que se armó el tema (createToolkitTheme los guarda); sin ellos, los de Apple. */\nfunction tonesOf(theme) {\n return theme.toolkit?.minimalTones ?? MINIMAL_TONES;\n}\n// el tinte de lo elegido y de los controles tonales (por ciento de su color) y al pasar el cursor\nconst TINT_PERCENT = Object.freeze({rest: 14, hover: 22, ring: 45});\n// las esquinas: tarjetas y controles (px)\nconst RADIUS_PIXELS = Object.freeze({card: 16, control: 10, group: 12, segment: 9});\n// los títulos chicos (overline), como se escriben (px)\nconst SMALL_TITLE_PIXELS = 13;\n\n/**\n * El tinte de un color del tema (lo elegido, un botón tonal).\n *\n * @param {object} theme\n * @param {string} [colorName]\n * @param {number} [percent]\n * @returns {string}\n */\nfunction tintOf(theme, colorName = 'primary', percent = TINT_PERCENT.rest) {\n const palette = paletteOf(theme);\n const color = (palette[colorName] ?? palette.primary).main;\n return `color-mix(in srgb, ${color} ${percent}%, transparent)`;\n}\n\n/**\n * El relleno gris de un campo o de un grupo, en claro y en oscuro.\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction tonalFillOf(theme) {\n const tones = tonesOf(theme);\n return lightDarkStylesOf(theme, {backgroundColor: tones.light.fill}, {backgroundColor: tones.dark.fill});\n}\n\n/**\n * Lo elegido: el tinte suave del acento y su letra legible, sin marco ni gota.\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction selectedTintOf(theme) {\n return {backgroundColor: tintOf(theme), ...accentTextStylesOf(theme)};\n}\n\n/**\n * La superficie de lo que flota en el minimalista, sólida, en claro y en oscuro (el tono floating; ver MINIMAL_TONES).\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function minimalFloatingStylesOf(theme) {\n const tones = tonesOf(theme);\n return lightDarkStylesOf(theme, {backgroundColor: tones.light.floating}, {backgroundColor: tones.dark.floating});\n}\n\n/**\n * @returns {object} el `components` del tema de MUI para el estilo minimalista\n */\nexport function minimalComponents() {\n return {\n MuiPaper: {\n defaultProps: {elevation: 0},\n styleOverrides: {\n root: {backgroundImage: 'none', boxShadow: 'none'},\n outlined: {border: 0},\n rounded: {borderRadius: RADIUS_PIXELS.card},\n },\n },\n MuiCard: {defaultProps: {elevation: 0}},\n // la barra del mismo tono que el fondo: sin raya ni sombra, solo su contenido\n MuiAppBar: {\n defaultProps: {elevation: 0, color: 'inherit'},\n styleOverrides: {\n root: ({theme}) => ({backgroundColor: paletteOf(theme).background.default, color: paletteOf(theme).text.primary, boxShadow: 'none', borderBottom: 0}),\n },\n },\n // el menú lateral también del tono del fondo, sin raya: lo separa el espacio, no una línea\n MuiDrawer: {\n styleOverrides: {\n paper: ({theme}) => ({backgroundColor: paletteOf(theme).background.default, borderRight: 0, backgroundImage: 'none'}),\n },\n },\n MuiButton: {\n defaultProps: {disableElevation: true},\n styleOverrides: {\n root: {borderRadius: RADIUS_PIXELS.control, boxShadow: 'none'},\n // el de borde es «tonal»: el tinte de su color, sin la raya\n outlined: ({ownerState, theme}) => ({\n border: 0,\n backgroundColor: tintOf(theme, ownerState.color),\n '&:hover': {border: 0, backgroundColor: tintOf(theme, ownerState.color, TINT_PERCENT.hover)},\n }),\n },\n },\n MuiButtonGroup: {defaultProps: {disableElevation: true}},\n MuiOutlinedInput: {\n styleOverrides: {\n root: ({theme}) => ({\n ...tonalFillOf(theme),\n borderRadius: RADIUS_PIXELS.control,\n '&.Mui-focused': {outline: `2px solid ${tintOf(theme, 'primary', TINT_PERCENT.ring)}`},\n '&.Mui-error': {outline: `2px solid ${tintOf(theme, 'error', TINT_PERCENT.ring)}`},\n }),\n notchedOutline: {border: 0},\n },\n },\n MuiFilledInput: {\n defaultProps: {disableUnderline: true},\n styleOverrides: {root: ({theme}) => ({...tonalFillOf(theme), borderRadius: RADIUS_PIXELS.control})},\n },\n // la etiqueta con borde también es tonal: el tinte de su color (o el gris si no lleva color)\n MuiChip: {\n styleOverrides: {\n outlined: ({ownerState, theme}) => ({\n border: 0,\n ...(ownerState.color && ownerState.color !== 'default' ? {backgroundColor: tintOf(theme, ownerState.color)} : tonalFillOf(theme)),\n }),\n },\n },\n MuiListItemButton: {\n styleOverrides: {\n root: ({theme}) => ({borderRadius: RADIUS_PIXELS.control, '&.Mui-selected, &.Mui-selected:hover': selectedTintOf(theme)}),\n },\n },\n MuiMenuItem: {\n styleOverrides: {\n root: ({theme}) => ({'&.Mui-selected, &.Mui-selected:hover': selectedTintOf(theme)}),\n },\n },\n // el grupo de botones (el control segmentado): una tira gris y lo elegido en blanco (claro) o un escalón arriba (oscuro)\n MuiToggleButtonGroup: {\n styleOverrides: {\n root: ({theme}) => ({...tonalFillOf(theme), border: 0, borderRadius: RADIUS_PIXELS.group, padding: 3, gap: 3}),\n grouped: {border: 0, borderRadius: `${RADIUS_PIXELS.segment}px !important`},\n },\n },\n MuiToggleButton: {\n styleOverrides: {\n root: ({theme}) => ({\n border: 0,\n ...lightDarkStylesOf(theme,\n {'&.Mui-selected, &.Mui-selected:hover': {backgroundColor: paletteOf(theme).background.paper, color: paletteOf(theme).text.primary}},\n {'&.Mui-selected, &.Mui-selected:hover': {backgroundColor: 'rgba(118, 118, 128, 0.36)'}}),\n }),\n },\n },\n MuiTab: {\n styleOverrides: {\n root: ({theme}) => ({'&.Mui-selected': accentTextStylesOf(theme)}),\n },\n },\n // las tablas sin rayas entre renglones: el encabezado se distingue por su tono\n MuiTableCell: {\n styleOverrides: {\n root: {borderBottom: 0},\n head: ({theme}) => ({...tonalFillOf(theme), fontWeight: 600}),\n },\n },\n MuiDataGrid: {\n styleOverrides: {\n root: {border: 0, '--DataGrid-rowBorderColor': 'transparent'},\n columnHeaders: ({theme}) => tonalFillOf(theme),\n },\n },\n MuiAlert: {styleOverrides: {root: {border: 0}}},\n // los títulos chicos como se escriben (Apple ya no los pone en mayúsculas), con el espaciado de su tamaño\n MuiTypography: {\n styleOverrides: {\n overline: {textTransform: 'none', fontWeight: 600, ...textSizeOf(SMALL_TITLE_PIXELS)},\n },\n },\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"minimalComponents.js","sources":["../../../src/theme/components/minimalComponents.js"],"sourcesContent":["// El estilo minimalista (createToolkitTheme({look: 'minimal'})): plano y tonal, como pidió el autor («casi solo colores, sin\n// bordes, que el mismo color diga dónde están las superficies»; su referencia: BELOW y Samurai Jack, formas de bloques de\n// color sin contorno y una sola luz de acento).\n//\n// Las reglas:\n// - sin bordes ni sombras: las superficies se separan por su tono, por omisión con los grises de Apple (MINIMAL_TONES: el\n// fondo agrupado gris y las tarjetas un escalón arriba; los campos, el gris de relleno; lo que flota, un gris más). Cada\n// proyecto puede pasar los suyos (createToolkitTheme minimalTones) y el minimalista se pinta con su marca;\n// - un solo color de acento: el botón principal, lo elegido (un tinte suave de su color, sin marco) y las ligas; lo demás\n// neutro. El botón con borde y la etiqueta con borde pasan a «tonales»: el tinte de su color, sin la raya;\n// - sin vidrio ni degradados: superficies sólidas.\n// Va encima de los ajustes del framework (toolkitComponents) y el proyecto puede sumar los suyos encima.\n//\n// Funciones puras, sin React: function (regla de la casa).\nimport {paletteOf} from '@/theme/components/paletteOf.js';\nimport {textSizeOf} from '@/theme/appleTracking.js';\nimport {accentTextStylesOf, fieldWellStylesOf} from '@/theme/glassSurface.js';\nimport {lightDarkStylesOf} from '@/theme/lightDarkStyles.js';\n\n/**\n * Los tonos del minimalista por omisión, los grises de Apple, en claro y en oscuro:\n * - default: el fondo de la página (el gris agrupado);\n * - paper: las tarjetas, un escalón arriba;\n * - fill: el relleno de campos, grupos y botones sin color (más claro que el fondo en oscuro);\n * - floating: lo que flota sobre el contenido (la barra de pestañas del teléfono, el aviso de versión nueva), un escalón\n * más oscuro que las tarjetas. Del color de las tarjetas «se perdía» sobre ellas (lo dijo el autor de la primera barra\n * de abajo del minimalista); así se distingue sin borde ni sombra, sobre tarjetas y sobre el fondo.\n */\nexport const MINIMAL_TONES = Object.freeze({\n light: Object.freeze({default: '#F2F2F7', paper: '#FFFFFF', fill: 'rgba(118, 118, 128, 0.12)', floating: '#E5E5EA'}),\n dark: Object.freeze({default: '#000000', paper: '#1C1C1E', fill: 'rgba(118, 118, 128, 0.24)', floating: '#2C2C2E'}),\n});\n\n/** Los fondos del minimalista por omisión (los de MINIMAL_TONES): el gris agrupado de Apple y la tarjeta un escalón arriba. */\nexport const MINIMAL_BACKGROUND = Object.freeze({\n light: {default: MINIMAL_TONES.light.default, paper: MINIMAL_TONES.light.paper},\n dark: {default: MINIMAL_TONES.dark.default, paper: MINIMAL_TONES.dark.paper},\n});\n\n/**\n * Los tonos del minimalista con los del proyecto encima: lo que el proyecto no trae se queda con el gris de Apple.\n *\n * @param {{light?: object, dark?: object}} [projectTones] cualquiera de default, paper, fill y floating por modo\n * @returns {{light: {default: string, paper: string, fill: string, floating: string}, dark: {default: string, paper: string, fill: string, floating: string}}}\n */\nexport function minimalTonesOf(projectTones = {}) {\n return {\n light: {...MINIMAL_TONES.light, ...projectTones.light},\n dark: {...MINIMAL_TONES.dark, ...projectTones.dark},\n };\n}\n\n/** Los tonos con que se armó el tema (createToolkitTheme los guarda); sin ellos, los de Apple. */\nfunction tonesOf(theme) {\n return theme.toolkit?.minimalTones ?? MINIMAL_TONES;\n}\n// el tinte de lo elegido y de los controles tonales (por ciento de su color) y al pasar el cursor\nconst TINT_PERCENT = Object.freeze({rest: 14, hover: 22, ring: 45});\n// las esquinas: tarjetas y controles (px)\nconst RADIUS_PIXELS = Object.freeze({card: 16, control: 10, group: 12, segment: 9});\n// los títulos chicos (overline), como se escriben (px)\nconst SMALL_TITLE_PIXELS = 13;\n\n/**\n * El tinte de un color del tema (lo elegido, un botón tonal).\n *\n * @param {object} theme\n * @param {string} [colorName]\n * @param {number} [percent]\n * @returns {string}\n */\nfunction tintOf(theme, colorName = 'primary', percent = TINT_PERCENT.rest) {\n const palette = paletteOf(theme);\n const color = (palette[colorName] ?? palette.primary).main;\n return `color-mix(in srgb, ${color} ${percent}%, transparent)`;\n}\n\n/**\n * El relleno gris de un campo o de un grupo, en claro y en oscuro.\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction tonalFillOf(theme) {\n const tones = tonesOf(theme);\n return lightDarkStylesOf(theme, {backgroundColor: tones.light.fill}, {backgroundColor: tones.dark.fill});\n}\n\n/**\n * Lo elegido: el tinte suave del acento y su letra legible, sin marco ni gota.\n *\n * @param {object} theme\n * @returns {object}\n */\nfunction selectedTintOf(theme) {\n return {backgroundColor: tintOf(theme), ...accentTextStylesOf(theme)};\n}\n\n/**\n * La superficie de lo que flota en el minimalista, sólida, en claro y en oscuro (el tono floating; ver MINIMAL_TONES).\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function minimalFloatingStylesOf(theme) {\n const tones = tonesOf(theme);\n return lightDarkStylesOf(theme, {backgroundColor: tones.light.floating}, {backgroundColor: tones.dark.floating});\n}\n\n/**\n * @returns {object} el `components` del tema de MUI para el estilo minimalista\n */\nexport function minimalComponents() {\n return {\n MuiPaper: {\n defaultProps: {elevation: 0},\n styleOverrides: {\n root: {backgroundImage: 'none', boxShadow: 'none'},\n outlined: {border: 0},\n rounded: {borderRadius: RADIUS_PIXELS.card},\n },\n },\n MuiCard: {defaultProps: {elevation: 0}},\n // la barra del mismo tono que el fondo: sin raya ni sombra, solo su contenido\n MuiAppBar: {\n defaultProps: {elevation: 0, color: 'inherit'},\n styleOverrides: {\n root: ({theme}) => ({backgroundColor: paletteOf(theme).background.default, color: paletteOf(theme).text.primary, boxShadow: 'none', borderBottom: 0}),\n },\n },\n // el menú lateral también del tono del fondo, sin raya: lo separa el espacio, no una línea\n MuiDrawer: {\n styleOverrides: {\n paper: ({theme}) => ({backgroundColor: paletteOf(theme).background.default, borderRight: 0, backgroundImage: 'none'}),\n },\n },\n MuiButton: {\n defaultProps: {disableElevation: true},\n styleOverrides: {\n root: {borderRadius: RADIUS_PIXELS.control, boxShadow: 'none'},\n // el de borde es «tonal»: el tinte de su color, sin la raya\n outlined: ({ownerState, theme}) => ({\n border: 0,\n backgroundColor: tintOf(theme, ownerState.color),\n '&:hover': {border: 0, backgroundColor: tintOf(theme, ownerState.color, TINT_PERCENT.hover)},\n }),\n },\n },\n MuiButtonGroup: {defaultProps: {disableElevation: true}},\n MuiOutlinedInput: {\n styleOverrides: {\n // el campo: los tonos de los campos del tema (por omisión, el relleno del minimalista; ver createToolkitTheme)\n root: ({theme}) => ({\n ...fieldWellStylesOf(theme, {radius: RADIUS_PIXELS.control}),\n '&.Mui-focused': {outline: `2px solid ${tintOf(theme, 'primary', TINT_PERCENT.ring)}`},\n '&.Mui-error': {outline: `2px solid ${tintOf(theme, 'error', TINT_PERCENT.ring)}`},\n }),\n notchedOutline: {border: 0},\n },\n },\n MuiFilledInput: {\n defaultProps: {disableUnderline: true},\n styleOverrides: {root: ({theme}) => fieldWellStylesOf(theme, {radius: RADIUS_PIXELS.control})},\n },\n // la etiqueta con borde también es tonal: el tinte de su color (o el gris si no lleva color)\n MuiChip: {\n styleOverrides: {\n outlined: ({ownerState, theme}) => ({\n border: 0,\n ...(ownerState.color && ownerState.color !== 'default' ? {backgroundColor: tintOf(theme, ownerState.color)} : tonalFillOf(theme)),\n }),\n },\n },\n MuiListItemButton: {\n styleOverrides: {\n root: ({theme}) => ({borderRadius: RADIUS_PIXELS.control, '&.Mui-selected, &.Mui-selected:hover': selectedTintOf(theme)}),\n },\n },\n MuiMenuItem: {\n styleOverrides: {\n root: ({theme}) => ({'&.Mui-selected, &.Mui-selected:hover': selectedTintOf(theme)}),\n },\n },\n // el grupo de botones (el control segmentado): una tira gris y lo elegido en blanco (claro) o un escalón arriba (oscuro)\n MuiToggleButtonGroup: {\n styleOverrides: {\n root: ({theme}) => ({...tonalFillOf(theme), border: 0, borderRadius: RADIUS_PIXELS.group, padding: 3, gap: 3}),\n grouped: {border: 0, borderRadius: `${RADIUS_PIXELS.segment}px !important`},\n },\n },\n MuiToggleButton: {\n styleOverrides: {\n root: ({theme}) => ({\n border: 0,\n ...lightDarkStylesOf(theme,\n {'&.Mui-selected, &.Mui-selected:hover': {backgroundColor: paletteOf(theme).background.paper, color: paletteOf(theme).text.primary}},\n {'&.Mui-selected, &.Mui-selected:hover': {backgroundColor: 'rgba(118, 118, 128, 0.36)'}}),\n }),\n },\n },\n MuiTab: {\n styleOverrides: {\n root: ({theme}) => ({'&.Mui-selected': accentTextStylesOf(theme)}),\n },\n },\n // las tablas sin rayas entre renglones: el encabezado se distingue por su tono\n MuiTableCell: {\n styleOverrides: {\n root: {borderBottom: 0},\n head: ({theme}) => ({...tonalFillOf(theme), fontWeight: 600}),\n },\n },\n MuiDataGrid: {\n styleOverrides: {\n root: {border: 0, '--DataGrid-rowBorderColor': 'transparent'},\n columnHeaders: ({theme}) => tonalFillOf(theme),\n },\n },\n MuiAlert: {styleOverrides: {root: {border: 0}}},\n // los títulos chicos como se escriben (Apple ya no los pone en mayúsculas), con el espaciado de su tamaño\n MuiTypography: {\n styleOverrides: {\n overline: {textTransform: 'none', fontWeight: 600, ...textSizeOf(SMALL_TITLE_PIXELS)},\n },\n },\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { createTheme, responsiveFontSizes } from "@mui/material/styles";
|
|
3
3
|
import { glassComponents } from "./components/glassComponents.js";
|
|
4
|
-
import { GLASS_OPACITY } from "./glassSurface.js";
|
|
4
|
+
import { GLASS_OPACITY, FIELD_TONES } from "./glassSurface.js";
|
|
5
5
|
import { mergeComponents } from "./mergeComponents.js";
|
|
6
6
|
import { stackcraftDarkPalette, stackcraftLightPalette } from "./stackcraftPalette.js";
|
|
7
7
|
import { trackingOf } from "./appleTracking.js";
|
|
@@ -39,6 +39,7 @@ function createToolkitTheme({
|
|
|
39
39
|
look = THEME_LOOK.standard,
|
|
40
40
|
bar = TOP_BAR.capsules,
|
|
41
41
|
minimalTones = {},
|
|
42
|
+
fields = {},
|
|
42
43
|
components = {},
|
|
43
44
|
overrides = {}
|
|
44
45
|
} = {}) {
|
|
@@ -49,10 +50,18 @@ function createToolkitTheme({
|
|
|
49
50
|
const glassSettings = isMinimal ? null : glassSettingsOf(glass);
|
|
50
51
|
const frameworkComponents = isMinimal ? mergeComponents(toolkitComponents(), minimalComponents()) : glassSettings ? mergeComponents(toolkitComponents(), glassComponents({ surfaces: glassSettings.surfaces })) : toolkitComponents();
|
|
51
52
|
const tones = isMinimal ? minimalTonesOf(minimalTones) : null;
|
|
52
|
-
const
|
|
53
|
+
const fieldTonesOf = (mode, scheme) => {
|
|
54
|
+
const lookTones = tones?.[mode] ? { ...FIELD_TONES[mode], fill: tones[mode].fill, hoverFill: tones[mode].fill } : FIELD_TONES[mode] ?? FIELD_TONES.light;
|
|
55
|
+
return { ...lookTones, ...fields[mode], ...scheme?.palette?.field };
|
|
56
|
+
};
|
|
57
|
+
const schemes = Object.fromEntries(Object.entries(colorSchemes).map(([mode, scheme]) => [mode, {
|
|
53
58
|
...scheme,
|
|
54
|
-
palette: {
|
|
55
|
-
|
|
59
|
+
palette: {
|
|
60
|
+
...scheme?.palette,
|
|
61
|
+
...isMinimal && { background: tones[mode] ? { default: tones[mode].default, paper: tones[mode].paper } : scheme?.palette?.background },
|
|
62
|
+
field: fieldTonesOf(mode, scheme)
|
|
63
|
+
}
|
|
64
|
+
}]));
|
|
56
65
|
const baseTheme = createTheme({
|
|
57
66
|
cssVariables: { colorSchemeSelector },
|
|
58
67
|
colorSchemes: schemes,
|
|
@@ -90,7 +99,8 @@ function createToolkitTheme({
|
|
|
90
99
|
// sin sombras en el minimalista: lo plano es la idea
|
|
91
100
|
...isMinimal && { shadows: Array(SHADOW_LEVELS).fill("none") },
|
|
92
101
|
// minimalTones: los tonos con que se pintan los rellenos y lo que flota (minimalComponents los lee del tema)
|
|
93
|
-
|
|
102
|
+
// fields: las esquinas de los campos (sus tonos van en la paleta: palette.field)
|
|
103
|
+
toolkit: { glass: glassSettings, look, bar, minimalTones: tones, fields: { radius: fields.radius } },
|
|
94
104
|
...overrides
|
|
95
105
|
});
|
|
96
106
|
return responsiveFontSizes(baseTheme);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createToolkitTheme.js","sources":["../../src/theme/createToolkitTheme.js"],"sourcesContent":["// El tema del framework: el estilo de Stackcraft (del tema de walk-ot) con claro y oscuro. Es opcional: ToolkitProvider\n// funciona con cualquier tema de MUI.\n//\n// const theme = createToolkitTheme(); // los colores de Stackcraft\n// const theme = createToolkitTheme({glass: true}); // con vidrio líquido en lo que flota\n// const theme = createToolkitTheme({glass: {opacity: 0.7}}); // con vidrio más transparente (por omisión 0.8)\n// const theme = createToolkitTheme({glass: {surfaces: true}}); // también las tarjetas del contenido (con advertencia)\n// const theme = createToolkitTheme({glass: true, bar: TOP_BAR.band}); // la barra de arriba en franja (por omisión, cápsulas)\n// const theme = createToolkitTheme({colorSchemes: {light: {palette: {primary: {main: '#0B5FFF'}}}, dark: {...}}});\n//\n// Lo que trae, con su porqué:\n// - variables CSS y los dos modos: ColorSchemeToggle cambia de modo sin volver a pintar, y las gráficas leen sus colores\n// del tema (theme.vars): con variables cambian solas al cambiar de modo, sin ellas se quedarían con las del arranque.\n// - colorSchemeSelector 'class': el modo lo elige la persona con el botón (con 'media' solo mandaría el sistema\n// operativo y el botón no haría nada). Con Next.js va con <InitColorSchemeScript attribute=\"class\" />.\n// - letra base de 16 px: con menos, el iPhone hace zoom al entrar a un campo. body1 16 px y body2 15 px en el teléfono;\n// responsiveFontSizes los ajusta por ancho de pantalla.\n// - transiciones de 220 ms, iguales al abrir y al cerrar: más ágiles que las de Material (300 ms) y sin el desfase de\n// 30 ms entre lo que solo conoce una transición (la barra) y lo que conoce dos (el menú lateral).\n// - esquinas de 8 px y los ajustes de componentes de toolkitComponents().\n// - glass: el vidrio líquido en lo que flota y en los controles (glassSurface.js explica dónde y por qué). Queda anotado\n// en theme.toolkit.glass para que los componentes del framework que flotan (el marco, los avisos) lo sepan sin otra prop.\n// - components: los ajustes propios del proyecto se SUMAN a los del framework (mergeComponents), no los borran.\n//\n// Funciones puras, sin React: function (regla de la casa).\nimport {createTheme, responsiveFontSizes} from '@mui/material/styles';\n\nimport {glassComponents} from '@/theme/components/glassComponents.js';\nimport {GLASS_OPACITY} from '@/theme/glassSurface.js';\nimport {mergeComponents} from '@/theme/mergeComponents.js';\nimport {stackcraftDarkPalette, stackcraftLightPalette} from '@/theme/stackcraftPalette.js';\nimport {trackingOf} from '@/theme/appleTracking.js';\nimport {toolkitComponents} from '@/theme/toolkitComponents.js';\nimport {minimalComponents, minimalTonesOf} from '@/theme/components/minimalComponents.js';\nimport {createLogger} from '@/observability/logger.js';\n\nconst log = createLogger('theme');\n// el aviso de las tarjetas de vidrio sale una vez por pestaña: el tema se vuelve a armar cada vez que cambia algo (un\n// configurador de tema lo arma en cada clic) y la consola se llenaba del mismo aviso\nlet hasWarnedAboutGlassSurfaces = false;\n\nconst SYSTEM_FONT_FAMILY = 'system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif';\nconst CORNER_RADIUS_PIXELS = 8;\n// cuántos niveles de sombra trae el tema de MUI (del 0 al 24)\nconst SHADOW_LEVELS = 25;\n\n/** El estilo del tema: el de Stackcraft (con vidrio o sin él) o el minimalista, plano y tonal. */\nexport const THEME_LOOK = Object.freeze({standard: 'standard', minimal: 'minimal'});\n\n/**\n * La barra de arriba, con vidrio y con el minimalista: por omisión como las ventanas de macOS Tahoe, sin franja (el nombre\n * y los botones en cápsulas por grupo; lo eligió el autor al verlas), o la franja de lado a lado. Con vidrio las cápsulas\n * son de vidrio y el contenido pasa por debajo desenfocado; con el minimalista son bloques del tono de las tarjetas sobre\n * el color del fondo (AppLayout). El estilo de Stackcraft sin vidrio se queda con su barra de siempre.\n */\nexport const TOP_BAR = Object.freeze({band: 'band', capsules: 'capsules'});\n\n/**\n * Lo que pidió el proyecto del vidrio, ya revisado: false (sin vidrio) o {opacity, surfaces}.\n *\n * @param {boolean|{opacity?: number, surfaces?: boolean}} glass\n * @returns {false|{opacity: number, surfaces: boolean}}\n */\nfunction glassSettingsOf(glass) {\n if (!glass) {\n return false;\n }\n const requested = glass === true ? {} : glass;\n const opacity = requested.opacity ?? GLASS_OPACITY;\n // un 80 en lugar de 0.8 daría un color inválido y la barra saldría sin fondo, sin ningún aviso\n if (typeof opacity !== 'number' || opacity < 0 || opacity > 1) {\n throw new RangeError(`createToolkitTheme: glass.opacity va de 0 a 1 (llegó ${opacity}).`);\n }\n const surfaces = Boolean(requested.surfaces);\n // se permite, pero con advertencia: la guía de Apple pide el contenido sin vidrio y cada tarjeta desenfoca lo de atrás\n if (surfaces && !hasWarnedAboutGlassSurfaces) {\n hasWarnedAboutGlassSurfaces = true;\n log.warn('glass.surfaces pone vidrio también en el contenido (tarjetas, avisos, tabla): pesa más en equipos modestos '\n + 'y la guía de Apple no lo recomienda («no use Liquid Glass en la capa del contenido»). Úselo en una portada o una '\n + 'demostración, no en pantallas de trabajo.');\n }\n return {opacity, surfaces};\n}\n\n/**\n * @param {object} [options]\n * @param {{light?: object|boolean, dark?: object|boolean}} [options.colorSchemes] los colores de cada modo; por omisión los de\n * Stackcraft; true: los de MUI tal cual\n * @param {'class'|'data'|'media'|string} [options.colorSchemeSelector] cómo se elige el modo; por omisión 'class'\n * @param {string} [options.fontFamily] por omisión la letra del sistema\n * @param {boolean|{opacity?: number, surfaces?: boolean}} [options.glass] vidrio líquido en lo que flota y en los\n * controles; por omisión no. Con {opacity} se elige qué tan opaco (0 a 1; por omisión GLASS_OPACITY, 0.6) y con\n * {surfaces: true} también las tarjetas del contenido (por omisión sólidas, como pide la guía; avisa en consola)\n * @param {'standard'|'minimal'} [options.look] el estilo (THEME_LOOK): el de Stackcraft (por omisión) o el minimalista,\n * plano y tonal (sin bordes ni sombras: las superficies se separan por su tono; sin vidrio aunque se pida)\n * @param {'capsules'|'band'} [options.bar] la barra de arriba con vidrio o con el minimalista (TOP_BAR): por omisión en\n * cápsulas; 'band' la franja de lado a lado\n * @param {{light?: {default?: string, paper?: string, fill?: string, floating?: string}, dark?: {default?: string, paper?: string, fill?: string, floating?: string}}} [options.minimalTones]\n * los tonos del minimalista con los colores de la marca, por modo: default (el fondo de la página), paper (las tarjetas,\n * un escalón arriba), fill (el relleno de campos, grupos y botones sin color) y floating (la barra de pestañas del\n * teléfono y lo que flota). Lo que no se pase se queda con los grises de Apple (MINIMAL_TONES). OJO: con el minimalista\n * el fondo de la página sale de aquí y no de la paleta (sin minimalTones, los grises de Apple aunque la paleta traiga\n * su background)\n * @param {object} [options.components] ajustes propios de componentes (se suman; en el mismo estilo ganan los del proyecto)\n * @param {object} [options.overrides] cualquier otra cosa de createTheme (breakpoints, spacing…)\n * @returns {object} el tema de MUI\n */\nexport function createToolkitTheme({\n colorSchemes = {light: {palette: stackcraftLightPalette}, dark: {palette: stackcraftDarkPalette}},\n colorSchemeSelector = 'class',\n fontFamily = SYSTEM_FONT_FAMILY,\n glass = false,\n look = THEME_LOOK.standard,\n bar = TOP_BAR.capsules,\n minimalTones = {},\n components = {},\n overrides = {},\n} = {}) {\n // un nombre mal escrito dejaría la franja sin avisar: mejor que truene al armar el tema\n if (!Object.values(TOP_BAR).includes(bar)) {\n throw new RangeError(`createToolkitTheme: bar es '${TOP_BAR.capsules}' o '${TOP_BAR.band}' (llegó ${bar}).`);\n }\n const isMinimal = look === THEME_LOOK.minimal;\n // el minimalista es sólido: sin vidrio aunque se pida\n const glassSettings = isMinimal ? null : glassSettingsOf(glass);\n const frameworkComponents = isMinimal\n ? mergeComponents(toolkitComponents(), minimalComponents())\n : (glassSettings ? mergeComponents(toolkitComponents(), glassComponents({surfaces: glassSettings.surfaces})) : toolkitComponents());\n // el minimalista separa las superficies por su tono: el fondo de la página y la tarjeta un escalón arriba (los grises de\n // Apple o los tonos de la marca que pasó el proyecto)\n const tones = isMinimal ? minimalTonesOf(minimalTones) : null;\n const schemes = isMinimal\n ? Object.fromEntries(Object.entries(colorSchemes).map(([mode, scheme]) => [mode, {\n ...scheme,\n palette: {...scheme.palette, background: tones[mode] ? {default: tones[mode].default, paper: tones[mode].paper} : scheme.palette?.background},\n }]))\n : colorSchemes;\n const baseTheme = createTheme({\n cssVariables: {colorSchemeSelector},\n colorSchemes: schemes,\n // el espaciado entre letras (tracking) de la tabla de SF Pro de Apple para cada tamaño (appleTracking.js). MUI\n // trae uno POSITIVO pensado para Roboto (+0.15 px en el texto, +0.4 px en botones y textos chicos) y con la letra del\n // sistema se veía la letra separada (lo reportaron: «kerning»); Apple, de 13 a 22 pt, lo cierra\n typography: {\n fontFamily,\n h1: {letterSpacing: trackingOf(96)},\n h2: {letterSpacing: trackingOf(60)},\n h3: {letterSpacing: trackingOf(48)},\n h4: {letterSpacing: trackingOf(34)},\n h5: {fontWeight: 600, letterSpacing: trackingOf(24)},\n h6: {fontWeight: 600, letterSpacing: trackingOf(20)},\n subtitle1: {letterSpacing: trackingOf(16)},\n subtitle2: {letterSpacing: trackingOf(14)},\n body1: {fontSize: '1rem', letterSpacing: trackingOf(16)},\n body2: {fontSize: '0.9375rem', letterSpacing: trackingOf(15)},\n button: {fontSize: '0.9375rem', textTransform: 'none', fontWeight: 500, letterSpacing: trackingOf(15)},\n caption: {letterSpacing: trackingOf(12)},\n },\n transitions: {\n duration: {\n shortest: 150,\n shorter: 180,\n short: 200,\n standard: 220,\n complex: 280,\n enteringScreen: 220,\n leavingScreen: 220,\n },\n },\n shape: {borderRadius: CORNER_RADIUS_PIXELS},\n components: mergeComponents(frameworkComponents, components),\n // sin sombras en el minimalista: lo plano es la idea\n ...(isMinimal && {shadows: Array(SHADOW_LEVELS).fill('none')}),\n // minimalTones: los tonos con que se pintan los rellenos y lo que flota (minimalComponents los lee del tema)\n toolkit: {glass: glassSettings, look, bar, minimalTones: tones},\n ...overrides,\n });\n return responsiveFontSizes(baseTheme);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createToolkitTheme.js","sources":["../../src/theme/createToolkitTheme.js"],"sourcesContent":["// El tema del framework: el estilo de Stackcraft (del tema de walk-ot) con claro y oscuro. Es opcional: ToolkitProvider\n// funciona con cualquier tema de MUI.\n//\n// const theme = createToolkitTheme(); // los colores de Stackcraft\n// const theme = createToolkitTheme({glass: true}); // con vidrio líquido en lo que flota\n// const theme = createToolkitTheme({glass: {opacity: 0.7}}); // con vidrio más transparente (por omisión 0.8)\n// const theme = createToolkitTheme({glass: {surfaces: true}}); // también las tarjetas del contenido (con advertencia)\n// const theme = createToolkitTheme({glass: true, bar: TOP_BAR.band}); // la barra de arriba en franja (por omisión, cápsulas)\n// const theme = createToolkitTheme({colorSchemes: {light: {palette: {primary: {main: '#0B5FFF'}}}, dark: {...}}});\n//\n// Lo que trae, con su porqué:\n// - variables CSS y los dos modos: ColorSchemeToggle cambia de modo sin volver a pintar, y las gráficas leen sus colores\n// del tema (theme.vars): con variables cambian solas al cambiar de modo, sin ellas se quedarían con las del arranque.\n// - colorSchemeSelector 'class': el modo lo elige la persona con el botón (con 'media' solo mandaría el sistema\n// operativo y el botón no haría nada). Con Next.js va con <InitColorSchemeScript attribute=\"class\" />.\n// - letra base de 16 px: con menos, el iPhone hace zoom al entrar a un campo. body1 16 px y body2 15 px en el teléfono;\n// responsiveFontSizes los ajusta por ancho de pantalla.\n// - transiciones de 220 ms, iguales al abrir y al cerrar: más ágiles que las de Material (300 ms) y sin el desfase de\n// 30 ms entre lo que solo conoce una transición (la barra) y lo que conoce dos (el menú lateral).\n// - esquinas de 8 px y los ajustes de componentes de toolkitComponents().\n// - glass: el vidrio líquido en lo que flota y en los controles (glassSurface.js explica dónde y por qué). Queda anotado\n// en theme.toolkit.glass para que los componentes del framework que flotan (el marco, los avisos) lo sepan sin otra prop.\n// - components: los ajustes propios del proyecto se SUMAN a los del framework (mergeComponents), no los borran.\n//\n// Funciones puras, sin React: function (regla de la casa).\nimport {createTheme, responsiveFontSizes} from '@mui/material/styles';\n\nimport {glassComponents} from '@/theme/components/glassComponents.js';\nimport {GLASS_OPACITY} from '@/theme/glassSurface.js';\nimport {mergeComponents} from '@/theme/mergeComponents.js';\nimport {stackcraftDarkPalette, stackcraftLightPalette} from '@/theme/stackcraftPalette.js';\nimport {trackingOf} from '@/theme/appleTracking.js';\nimport {toolkitComponents} from '@/theme/toolkitComponents.js';\nimport {minimalComponents, minimalTonesOf} from '@/theme/components/minimalComponents.js';\nimport {FIELD_TONES} from '@/theme/glassSurface.js';\nimport {createLogger} from '@/observability/logger.js';\n\nconst log = createLogger('theme');\n// el aviso de las tarjetas de vidrio sale una vez por pestaña: el tema se vuelve a armar cada vez que cambia algo (un\n// configurador de tema lo arma en cada clic) y la consola se llenaba del mismo aviso\nlet hasWarnedAboutGlassSurfaces = false;\n\nconst SYSTEM_FONT_FAMILY = 'system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif';\nconst CORNER_RADIUS_PIXELS = 8;\n// cuántos niveles de sombra trae el tema de MUI (del 0 al 24)\nconst SHADOW_LEVELS = 25;\n\n/** El estilo del tema: el de Stackcraft (con vidrio o sin él) o el minimalista, plano y tonal. */\nexport const THEME_LOOK = Object.freeze({standard: 'standard', minimal: 'minimal'});\n\n/**\n * La barra de arriba, con vidrio y con el minimalista: por omisión como las ventanas de macOS Tahoe, sin franja (el nombre\n * y los botones en cápsulas por grupo; lo eligió el autor al verlas), o la franja de lado a lado. Con vidrio las cápsulas\n * son de vidrio y el contenido pasa por debajo desenfocado; con el minimalista son bloques del tono de las tarjetas sobre\n * el color del fondo (AppLayout). El estilo de Stackcraft sin vidrio se queda con su barra de siempre.\n */\nexport const TOP_BAR = Object.freeze({band: 'band', capsules: 'capsules'});\n\n/**\n * Lo que pidió el proyecto del vidrio, ya revisado: false (sin vidrio) o {opacity, surfaces}.\n *\n * @param {boolean|{opacity?: number, surfaces?: boolean}} glass\n * @returns {false|{opacity: number, surfaces: boolean}}\n */\nfunction glassSettingsOf(glass) {\n if (!glass) {\n return false;\n }\n const requested = glass === true ? {} : glass;\n const opacity = requested.opacity ?? GLASS_OPACITY;\n // un 80 en lugar de 0.8 daría un color inválido y la barra saldría sin fondo, sin ningún aviso\n if (typeof opacity !== 'number' || opacity < 0 || opacity > 1) {\n throw new RangeError(`createToolkitTheme: glass.opacity va de 0 a 1 (llegó ${opacity}).`);\n }\n const surfaces = Boolean(requested.surfaces);\n // se permite, pero con advertencia: la guía de Apple pide el contenido sin vidrio y cada tarjeta desenfoca lo de atrás\n if (surfaces && !hasWarnedAboutGlassSurfaces) {\n hasWarnedAboutGlassSurfaces = true;\n log.warn('glass.surfaces pone vidrio también en el contenido (tarjetas, avisos, tabla): pesa más en equipos modestos '\n + 'y la guía de Apple no lo recomienda («no use Liquid Glass en la capa del contenido»). Úselo en una portada o una '\n + 'demostración, no en pantallas de trabajo.');\n }\n return {opacity, surfaces};\n}\n\n/**\n * @param {object} [options]\n * @param {{light?: object|boolean, dark?: object|boolean}} [options.colorSchemes] los colores de cada modo; por omisión los de\n * Stackcraft; true: los de MUI tal cual\n * @param {'class'|'data'|'media'|string} [options.colorSchemeSelector] cómo se elige el modo; por omisión 'class'\n * @param {string} [options.fontFamily] por omisión la letra del sistema\n * @param {boolean|{opacity?: number, surfaces?: boolean}} [options.glass] vidrio líquido en lo que flota y en los\n * controles; por omisión no. Con {opacity} se elige qué tan opaco (0 a 1; por omisión GLASS_OPACITY, 0.6) y con\n * {surfaces: true} también las tarjetas del contenido (por omisión sólidas, como pide la guía; avisa en consola)\n * @param {'standard'|'minimal'} [options.look] el estilo (THEME_LOOK): el de Stackcraft (por omisión) o el minimalista,\n * plano y tonal (sin bordes ni sombras: las superficies se separan por su tono; sin vidrio aunque se pida)\n * @param {'capsules'|'band'} [options.bar] la barra de arriba con vidrio o con el minimalista (TOP_BAR): por omisión en\n * cápsulas; 'band' la franja de lado a lado\n * @param {{light?: {default?: string, paper?: string, fill?: string, floating?: string}, dark?: {default?: string, paper?: string, fill?: string, floating?: string}}} [options.minimalTones]\n * los tonos del minimalista con los colores de la marca, por modo: default (el fondo de la página), paper (las tarjetas,\n * un escalón arriba), fill (el relleno de campos, grupos y botones sin color) y floating (la barra de pestañas del\n * teléfono y lo que flota). Lo que no se pase se queda con los grises de Apple (MINIMAL_TONES). OJO: con el minimalista\n * el fondo de la página sale de aquí y no de la paleta (sin minimalTones, los grises de Apple aunque la paleta traiga\n * su background)\n * @param {{radius?: number, light?: {fill?: string, hoverFill?: string, border?: string, hoverBorder?: string}, dark?: {fill?: string, hoverFill?: string, border?: string, hoverBorder?: string}}} [options.fields]\n * cómo se ven los campos de captura (con vidrio, con el minimalista y dentro de FormSection), por modo: fill (el\n * relleno), hoverFill (con el cursor encima), border y hoverBorder (la orilla); y radius (las esquinas, en px). Lo que no\n * se pase se queda como el estilo lo trae (FIELD_TONES: el gris de Apple; con el minimalista, su relleno). Van en la\n * paleta de cada modo (palette.field), así que también se pueden escribir en colorSchemes y cambian solos con el modo.\n * Ejemplo, campos blancos con borde en claro: {light: {fill: '#FFFFFF', hoverFill: '#FFFFFF', border: '#C4CDD5'}}\n * @param {object} [options.components] ajustes propios de componentes (se suman; en el mismo estilo ganan los del proyecto)\n * @param {object} [options.overrides] cualquier otra cosa de createTheme (breakpoints, spacing…)\n * @returns {object} el tema de MUI\n */\nexport function createToolkitTheme({\n colorSchemes = {light: {palette: stackcraftLightPalette}, dark: {palette: stackcraftDarkPalette}},\n colorSchemeSelector = 'class',\n fontFamily = SYSTEM_FONT_FAMILY,\n glass = false,\n look = THEME_LOOK.standard,\n bar = TOP_BAR.capsules,\n minimalTones = {},\n fields = {},\n components = {},\n overrides = {},\n} = {}) {\n // un nombre mal escrito dejaría la franja sin avisar: mejor que truene al armar el tema\n if (!Object.values(TOP_BAR).includes(bar)) {\n throw new RangeError(`createToolkitTheme: bar es '${TOP_BAR.capsules}' o '${TOP_BAR.band}' (llegó ${bar}).`);\n }\n const isMinimal = look === THEME_LOOK.minimal;\n // el minimalista es sólido: sin vidrio aunque se pida\n const glassSettings = isMinimal ? null : glassSettingsOf(glass);\n const frameworkComponents = isMinimal\n ? mergeComponents(toolkitComponents(), minimalComponents())\n : (glassSettings ? mergeComponents(toolkitComponents(), glassComponents({surfaces: glassSettings.surfaces})) : toolkitComponents());\n // el minimalista separa las superficies por su tono: el fondo de la página y la tarjeta un escalón arriba (los grises de\n // Apple o los tonos de la marca que pasó el proyecto)\n const tones = isMinimal ? minimalTonesOf(minimalTones) : null;\n // los campos de cada modo: lo del estilo (el gris de Apple o, con el minimalista, su relleno), encima lo de `fields` y\n // encima lo que el proyecto escribió en su paleta (palette.field)\n const fieldTonesOf = (mode, scheme) => {\n const lookTones = tones?.[mode]\n ? {...FIELD_TONES[mode], fill: tones[mode].fill, hoverFill: tones[mode].fill}\n : FIELD_TONES[mode] ?? FIELD_TONES.light;\n return {...lookTones, ...fields[mode], ...scheme?.palette?.field};\n };\n const schemes = Object.fromEntries(Object.entries(colorSchemes).map(([mode, scheme]) => [mode, {\n ...scheme,\n palette: {\n ...scheme?.palette,\n ...(isMinimal && {background: tones[mode] ? {default: tones[mode].default, paper: tones[mode].paper} : scheme?.palette?.background}),\n field: fieldTonesOf(mode, scheme),\n },\n }]));\n const baseTheme = createTheme({\n cssVariables: {colorSchemeSelector},\n colorSchemes: schemes,\n // el espaciado entre letras (tracking) de la tabla de SF Pro de Apple para cada tamaño (appleTracking.js). MUI\n // trae uno POSITIVO pensado para Roboto (+0.15 px en el texto, +0.4 px en botones y textos chicos) y con la letra del\n // sistema se veía la letra separada (lo reportaron: «kerning»); Apple, de 13 a 22 pt, lo cierra\n typography: {\n fontFamily,\n h1: {letterSpacing: trackingOf(96)},\n h2: {letterSpacing: trackingOf(60)},\n h3: {letterSpacing: trackingOf(48)},\n h4: {letterSpacing: trackingOf(34)},\n h5: {fontWeight: 600, letterSpacing: trackingOf(24)},\n h6: {fontWeight: 600, letterSpacing: trackingOf(20)},\n subtitle1: {letterSpacing: trackingOf(16)},\n subtitle2: {letterSpacing: trackingOf(14)},\n body1: {fontSize: '1rem', letterSpacing: trackingOf(16)},\n body2: {fontSize: '0.9375rem', letterSpacing: trackingOf(15)},\n button: {fontSize: '0.9375rem', textTransform: 'none', fontWeight: 500, letterSpacing: trackingOf(15)},\n caption: {letterSpacing: trackingOf(12)},\n },\n transitions: {\n duration: {\n shortest: 150,\n shorter: 180,\n short: 200,\n standard: 220,\n complex: 280,\n enteringScreen: 220,\n leavingScreen: 220,\n },\n },\n shape: {borderRadius: CORNER_RADIUS_PIXELS},\n components: mergeComponents(frameworkComponents, components),\n // sin sombras en el minimalista: lo plano es la idea\n ...(isMinimal && {shadows: Array(SHADOW_LEVELS).fill('none')}),\n // minimalTones: los tonos con que se pintan los rellenos y lo que flota (minimalComponents los lee del tema)\n // fields: las esquinas de los campos (sus tonos van en la paleta: palette.field)\n toolkit: {glass: glassSettings, look, bar, minimalTones: tones, fields: {radius: fields.radius}},\n ...overrides,\n });\n return responsiveFontSizes(baseTheme);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -199,20 +199,64 @@ function contrastWithWhiteOf(channels) {
|
|
|
199
199
|
const luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
|
|
200
200
|
return 1.05 / (luminance + 0.05);
|
|
201
201
|
}
|
|
202
|
-
|
|
202
|
+
const FIELD_TONES = Object.freeze({
|
|
203
|
+
light: Object.freeze({ fill: FIELD_WELL_FILL.light.rest, hoverFill: FIELD_WELL_FILL.light.hover, border: "transparent", hoverBorder: "transparent" }),
|
|
204
|
+
dark: Object.freeze({ fill: FIELD_WELL_FILL.dark.rest, hoverFill: FIELD_WELL_FILL.dark.hover, border: "transparent", hoverBorder: "transparent" })
|
|
205
|
+
});
|
|
206
|
+
function fieldPaletteOf(theme) {
|
|
207
|
+
return paletteOf(theme).field ?? null;
|
|
208
|
+
}
|
|
209
|
+
function fieldEdgeOf(color) {
|
|
210
|
+
return `inset 0 0 0 1px ${color}`;
|
|
211
|
+
}
|
|
212
|
+
function fieldRadiusOf(theme, lookRadius) {
|
|
213
|
+
return theme.toolkit?.fields?.radius ?? lookRadius;
|
|
214
|
+
}
|
|
215
|
+
function fieldWellStylesOf(theme, { radius = FIELD_WELL_RADIUS_PIXELS } = {}) {
|
|
216
|
+
const base = { backgroundImage: "none", backdropFilter: "none", WebkitBackdropFilter: "none", borderRadius: fieldRadiusOf(theme, radius) };
|
|
217
|
+
const field = fieldPaletteOf(theme);
|
|
218
|
+
if (field) {
|
|
219
|
+
return {
|
|
220
|
+
...base,
|
|
221
|
+
backgroundColor: field.fill,
|
|
222
|
+
boxShadow: fieldEdgeOf(field.border),
|
|
223
|
+
"&:hover": { backgroundColor: field.hoverFill, boxShadow: fieldEdgeOf(field.hoverBorder) }
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
const { light, dark } = FIELD_TONES;
|
|
203
227
|
return {
|
|
204
|
-
|
|
205
|
-
backdropFilter: "none",
|
|
206
|
-
WebkitBackdropFilter: "none",
|
|
207
|
-
boxShadow: "none",
|
|
208
|
-
borderRadius: FIELD_WELL_RADIUS_PIXELS,
|
|
228
|
+
...base,
|
|
209
229
|
...lightDarkStylesOf(
|
|
210
230
|
theme,
|
|
211
|
-
{ backgroundColor:
|
|
212
|
-
{ backgroundColor:
|
|
231
|
+
{ backgroundColor: light.fill, boxShadow: fieldEdgeOf(light.border), "&:hover": { backgroundColor: light.hoverFill, boxShadow: fieldEdgeOf(light.hoverBorder) } },
|
|
232
|
+
{ backgroundColor: dark.fill, boxShadow: fieldEdgeOf(dark.border), "&:hover": { backgroundColor: dark.hoverFill, boxShadow: fieldEdgeOf(dark.hoverBorder) } }
|
|
213
233
|
)
|
|
214
234
|
};
|
|
215
235
|
}
|
|
236
|
+
function fieldVariablesOf(theme) {
|
|
237
|
+
const variablesOf = (tones) => ({
|
|
238
|
+
"--calcita-field-fill": tones.fill,
|
|
239
|
+
"--calcita-field-hover-fill": tones.hoverFill,
|
|
240
|
+
"--calcita-field-edge": fieldEdgeOf(tones.border),
|
|
241
|
+
"--calcita-field-hover-edge": fieldEdgeOf(tones.hoverBorder)
|
|
242
|
+
});
|
|
243
|
+
const field = fieldPaletteOf(theme);
|
|
244
|
+
if (field) {
|
|
245
|
+
return variablesOf(field);
|
|
246
|
+
}
|
|
247
|
+
return { ...variablesOf(FIELD_TONES.light), ...theme.applyStyles("dark", variablesOf(FIELD_TONES.dark)) };
|
|
248
|
+
}
|
|
249
|
+
function fieldWellFromVariablesOf(theme) {
|
|
250
|
+
return {
|
|
251
|
+
backgroundImage: "none",
|
|
252
|
+
backdropFilter: "none",
|
|
253
|
+
WebkitBackdropFilter: "none",
|
|
254
|
+
borderRadius: fieldRadiusOf(theme, FIELD_WELL_RADIUS_PIXELS),
|
|
255
|
+
backgroundColor: "var(--calcita-field-fill)",
|
|
256
|
+
boxShadow: "var(--calcita-field-edge)",
|
|
257
|
+
"&:hover": { backgroundColor: "var(--calcita-field-hover-fill)", boxShadow: "var(--calcita-field-hover-edge)" }
|
|
258
|
+
};
|
|
259
|
+
}
|
|
216
260
|
function canvasFieldStylesOf(theme) {
|
|
217
261
|
const paper = paletteOf(theme).background.paper;
|
|
218
262
|
return {
|
|
@@ -298,6 +342,7 @@ function scrollEdgeStylesOf(theme) {
|
|
|
298
342
|
};
|
|
299
343
|
}
|
|
300
344
|
export {
|
|
345
|
+
FIELD_TONES,
|
|
301
346
|
GLASS_INSET_PIXELS,
|
|
302
347
|
GLASS_LENS,
|
|
303
348
|
GLASS_LENS_FLAG_SELECTOR,
|
|
@@ -307,6 +352,9 @@ export {
|
|
|
307
352
|
accentTextStylesOf,
|
|
308
353
|
ambientBackgroundOf,
|
|
309
354
|
canvasFieldStylesOf,
|
|
355
|
+
fieldPaletteOf,
|
|
356
|
+
fieldVariablesOf,
|
|
357
|
+
fieldWellFromVariablesOf,
|
|
310
358
|
fieldWellStylesOf,
|
|
311
359
|
fixedBackgroundLayerOf,
|
|
312
360
|
glassDropOf,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glassSurface.js","sources":["../../src/theme/glassSurface.js"],"sourcesContent":["// El «vidrio líquido» (Liquid Glass de Apple, 2025) en su versión de CSS: una superficie poco transparente que deja ver,\n// desenfocado, lo que pasa por detrás, con un brillo en el borde de arriba. La guía de Apple (Human Interface Guidelines,\n// «Materials»: https://developer.apple.com/design/human-interface-guidelines/materials) separa dos capas, y aquí igual:\n// - VIDRIO (glassStylesOf): «a distinct functional layer for controls and navigation elements… that floats above the\n// content layer». En el framework: la barra de arriba, el menú lateral, los menús y ventanitas, los diálogos, los\n// tooltips, los avisos, el panel de descargas, el botón flotante y, en los controles, la «gota» que marca lo elegido.\n// - MATERIAL (materialStylesOf): «Don't use Liquid Glass in the content layer»; el contenido usa los materiales estándar\n// (vidrio esmerilado, sin el brillo del borde) y los gruesos, más opacos, porque «provide better contrast for text».\n// Es lo que llevan las tarjetas con createToolkitTheme({glass: {surfaces: true}}).\n//\n// Decisiones, con su porqué:\n// - 60 % opaco por omisión. Con 80 %, en claro el vidrio era casi blanco sobre un lienzo casi blanco y se leía como\n// «cápsulas con sombra» (lo dijo el autor), no como vidrio: Apple dice que el vidrio «has no inherent color, and\n// instead takes on colors from the content directly behind it», y para eso tiene que dejar pasar el color. El material\n// del contenido es «delgado» (MATERIAL_OPACITY_OFFSET): con 74 % las tarjetas se veían planas, de un solo color (lo dijo\n// el autor); con el desenfoque de 20 px el texto se sigue leyendo. El proyecto lo cambia con\n// createToolkitTheme({glass: {opacity: 0.8}}), que mueve las dos.\n// - Lo que dibuja el vidrio es su filo de luz, como la orilla de una lente: brillante arriba a la izquierda (de donde\n// viene la luz), más suave abajo a la derecha, y un resplandor por dentro; la sombra de afuera es corta.\n// - Se pinta sólido si la persona pidió menos transparencia o más contraste en su equipo, o si el navegador no sabe\n// desenfocar: la misma guía pide respetar «Reducir transparencia», y Apple tuvo que agregar el control en iOS 26.1\n// porque el texto sobre vidrio no se leía.\n// - Con vidrio, el lienzo lleva unas manchas de color (ambientBackgroundOf): sobre un lienzo liso, el vidrio no\n// se distingue de una superficie sólida, porque no hay nada que desenfocar.\n// - Esquinas concéntricas: la de afuera es la de adentro más el margen (los renglones del menú lateral son de 12 px a 8 px\n// del borde, así que el panel es de 20 px). Apple lo pide así; si no, las esquinas «no casan» y se nota.\n// - Sin refracción (la lupa que deforma lo de atrás): en la web solo sale con filtros SVG que hoy funcionan nada más en\n// Chrome, o con WebGL. Esto es la versión que funciona en todos.\n// - color-mix y no alpha(): sirve igual con las variables CSS del tema (var(--mui-palette-…)) que con un color normal.\n//\n// OJO: backdrop-filter vuelve a la superficie el «contenedor» de lo que lleve adentro con position: fixed. Lo que deba\n// quedar fijo a la ventana va fuera de ella (los menús de MUI ya van en un portal).\n//\n// Funciones puras, sin React: function (regla de la casa).\nimport {paletteOf} from '@/theme/components/paletteOf.js';\nimport {lightDarkStylesOf} from '@/theme/lightDarkStyles.js';\n\n/** Qué tan opaca es la superficie (0 a 1). */\nexport const GLASS_OPACITY = 0.6;\n\n/** Las esquinas de lo que flota grande (menú lateral, barra, diálogos): renglones de 12 px a 8 px del borde. */\nexport const GLASS_PANEL_RADIUS_PIXELS = 20;\n\n/** Las esquinas de los menús y ventanitas: renglones de 8 px a 4 px del borde. */\nexport const GLASS_MENU_RADIUS_PIXELS = 12;\n\n/**\n * Lo que se separa de la orilla de la ventana lo que flota (la barra, el menú lateral, los cajones y la hoja de abajo):\n * Apple lo pide para que el contenido se asome por detrás («half sheets are inset from the edge of the display to allow\n * content to peek through from beneath them», Adopting Liquid Glass).\n */\nexport const GLASS_INSET_PIXELS = 8;\n\nconst GLASS_BLUR = 'blur(20px) saturate(180%)';\n\n/**\n * El lente de cada tamaño (ver lensRulesOf), medido en capturas de Chrome: el control chico (botón, chip) más claro y con\n * la orilla más marcada; el panel (barra, menú, diálogo) más grueso, porque lleva texto («Liquid Glass appears more opaque\n * in larger elements like sidebars to preserve legibility», HIG «Color»). edgeFraction y scale van en fracción del tamaño\n * del vidrio; clearerBy es cuánto menos tinte lleva que el esmerilado.\n */\nexport const GLASS_LENS = Object.freeze({\n control: {filterId: 'toolkit-glass-lens-control', edgeFraction: 0.25, scale: 0.2, blurPixels: 3, clearerBy: 0.25},\n panel: {filterId: 'toolkit-glass-lens-panel', edgeFraction: 0.12, scale: 0.05, blurPixels: 10, clearerBy: 0.1},\n});\n\n// el gris de la gota en oscuro (por ciento de blanco): lo elegido se tiene que notar (glassDropOf)\nconst DARK_DROP_WHITE_PERCENT = 18;\n// cuánto negro (en claro) o blanco (en oscuro) lleva un texto del color del tema para leerse (accentTextStylesOf)\nconst ACCENT_TEXT_SHADE_PERCENT = 30;\n// el pozo de los campos (fieldWellStylesOf): el gris de relleno de Apple en claro y un oscurecido en oscuro\nconst FIELD_WELL_RADIUS_PIXELS = 12;\nconst FIELD_WELL_FILL = Object.freeze({\n light: {rest: 'rgba(118, 118, 128, 0.12)', hover: 'rgba(118, 118, 128, 0.18)'},\n // en oscuro el gris de Apple, MÁS CLARO que lo de atrás (su «tertiary fill»): con negro al 32 % el campo se perdía\n dark: {rest: 'rgba(118, 118, 128, 0.24)', hover: 'rgba(118, 118, 128, 0.30)'},\n});\n// el campo suelto sobre el lienzo (canvasFieldStylesOf): lámina clara en claro, oscura en oscuro, con su filo\nconst CANVAS_FIELD = Object.freeze({\n light: {rest: 'rgba(255, 255, 255, 0.62)', hover: 'rgba(255, 255, 255, 0.78)', edge: 'rgba(15, 23, 42, 0.10)'},\n // en oscuro, el gris de relleno de Apple (más claro que el fondo). Con negro al 34 % el campo contra el fondo casi negro\n // medía 1.01 : 1 y no se veía (lo reportaron: el buscador «se pierde»); con este, 1.26 : 1, y su filo aparte\n dark: {rest: 'rgba(118, 118, 128, 0.24)', hover: 'rgba(118, 118, 128, 0.30)', edge: 'rgba(255, 255, 255, 0.10)'},\n});\n// el contraste mínimo de WCAG para letra normal, y cómo se oscurece un relleno hasta lograrlo (whiteLabelFillOf)\nconst MIN_TEXT_CONTRAST = 4.5;\nconst FILL_SHARE_STEP_PERCENT = 5;\nconst MIN_FILL_SHARE_PERCENT = 30;\n\n/** La marca que GlassLensFilter pone en <body> cuando el navegador sí pinta el lente. */\nexport const GLASS_LENS_FLAG_SELECTOR = 'body[data-glass-lens=\"on\"]';\n\n/**\n * El selector de «este control está dentro de una tarjeta» (cualquier Paper: tarjeta, diálogo, menú), donde el control ya\n * no es vidrio. Va en dos versiones, sin y con la marca del lente: la regla del lente (una etiqueta y dos clases) le ganaba\n * a la de la tarjeta (dos clases) y los botones dentro de una tarjeta volvían a ser vidrio. Medido en Chrome.\n *\n * @param {string} [suffix] lo que va pegado al control (p. ej. ':not(.MuiButtonGroup-grouped)')\n * @returns {string}\n */\nexport function insideContentSelectorOf(suffix = '') {\n return `.MuiPaper-root &${suffix}, ${GLASS_LENS_FLAG_SELECTOR} .MuiPaper-root &${suffix}`;\n}\nconst REDUCED_TRANSPARENCY_QUERY = '@media (prefers-reduced-transparency: reduce), (prefers-contrast: more)';\nconst NO_BACKDROP_FILTER_QUERY = '@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)))';\n\n// qué tan fuertes son las manchas del lienzo (por ciento del color). En oscuro van MÁS fuertes que en claro: sobre un lienzo\n// casi negro, unas manchas tenues no dan nada que desenfocar y el vidrio se ve como un gris sólido.\n// La de en medio (center) va detrás del contenido: sin ella, en claro las tarjetas de vidrio quedaban sobre blanco y se\n// veían sólidas (medido en las capturas de Chrome).\nconst AMBIENT_STRENGTH_LIGHT = Object.freeze({primary: 40, info: 30, accent: 30, center: 16});\n// en oscuro: manchas de los tonos oscuros sobre un casi negro con un toque azul (como los fondos oscuros de Apple). Antes\n// eran los tonos vivos al 36 % sobre #0A0A0A: aclaraban el fondo hasta el gris de las tarjetas y los elementos se perdían\n// (lo reportaron; medido: tarjeta contra fondo 1.12 : 1). Ahora 1.28 : 1 en el peor punto\nconst AMBIENT_STRENGTH_DARK = Object.freeze({primary: 18, info: 18, accent: 12, center: 10});\nconst DARK_CANVAS = Object.freeze({base: '#05070B'});\n\n// el filo de la lente: la luz de arriba a la izquierda (rimLight), la de abajo a la derecha más suave (rimShade), un\n// resplandor por dentro (innerGlow), una línea fina de afuera que lo separa del lienzo (outline) y la sombra que lo\n// despega (shadow). En oscuro el filo es más tenue, pero la sombra más fuerte: una negra suave no se ve sobre casi negro.\n// Un control chico (botón, chip) lleva una sombra corta (controlShadow): la de un panel se veía como neblina alrededor y,\n// dentro de una tira que se desliza (los filtros rápidos), la tira la cortaba en un rectángulo.\nconst GLASS_EDGE_LIGHT = Object.freeze({\n rimLight: 'rgba(255, 255, 255, 0.95)', rimShade: 'rgba(255, 255, 255, 0.5)', innerGlow: 'rgba(255, 255, 255, 0.45)',\n outline: 'rgba(15, 23, 42, 0.07)', shadow: '0 6px 20px rgba(15, 23, 42, 0.10)',\n controlShadow: '0 1px 2px rgba(15, 23, 42, 0.10), 0 2px 6px rgba(15, 23, 42, 0.06)',\n});\nconst GLASS_EDGE_DARK = Object.freeze({\n rimLight: 'rgba(255, 255, 255, 0.32)', rimShade: 'rgba(255, 255, 255, 0.12)', innerGlow: 'rgba(255, 255, 255, 0.07)',\n outline: 'rgba(0, 0, 0, 0.35)', shadow: '0 8px 28px rgba(0, 0, 0, 0.45)',\n controlShadow: '0 1px 2px rgba(0, 0, 0, 0.40), 0 2px 6px rgba(0, 0, 0, 0.25)',\n});\n// lo ancho del resplandor de adentro (px): lo que se ve como el grosor del vidrio en la orilla\nconst INNER_GLOW_PIXELS = 12;\n// en oscuro el vidrio se aclara un poco sobre su color: un gris igual de oscuro que el lienzo no se distingue de él aunque\n// desenfoque. Es lo que Apple hace en oscuro: lo que va al frente usa los colores «elevated», más claros, «making\n// foreground interfaces appear to advance» (HIG, Dark Mode). Con 8 % las tarjetas y los controles se perdían en el fondo\n// oscuro (lo reportaron); con 16 % y el lienzo nuevo (DARK_CANVAS) la tarjeta se separa 1.28 : 1 del fondo y el control\n// 1.32 : 1 (medido; Apple, su tarjeta #1C1C1E sobre negro: 1.23 : 1)\nconst DARK_GLASS_LIFT_PERCENT = 16;\n\n// el material del contenido: sin brillo de borde (eso es del vidrio de los controles), con una línea fina de afuera que lo\n// separa del lienzo y una sombra suave. En oscuro la línea es clara: una oscura no se ve sobre casi negro\nconst MATERIAL_EDGE_LIGHT = Object.freeze({outline: 'rgba(15, 23, 42, 0.08)', shadow: '0 1px 2px rgba(15, 23, 42, 0.06), 0 8px 24px rgba(15, 23, 42, 0.06)'});\nconst MATERIAL_EDGE_DARK = Object.freeze({outline: 'rgba(255, 255, 255, 0.08)', shadow: '0 8px 24px rgba(0, 0, 0, 0.35)'});\n// el material del contenido es «delgado» (HIG «Materials»: «Thinner materials… help people retain their context by\n// providing a visible reminder of the content that's in the background»): menos opaco que el vidrio de los controles. Con\n// el «grueso» (+0.14, 74 %) las tarjetas se veían planas; el texto se lee por el desenfoque de 20 px, y con «Reducir\n// transparencia» se pinta sólido. En oscuro resta menos: con 45 % la tarjeta casi no se separaba del fondo (medido 1.12 : 1)\nconst MATERIAL_OPACITY_OFFSET = Object.freeze({light: -0.15, dark: -0.05});\n// el material «grueso» (por ciento): tapa lo que pasa por debajo, como la columna fija de una tabla\nconst THICK_MATERIAL_PERCENT = 92;\n\n/**\n * Si el tema trae el vidrio prendido (createToolkitTheme({glass: …})). Lo usan los componentes del framework que flotan\n * (el marco, el panel de descargas, los avisos) y lo puede usar el proyecto para lo suyo.\n *\n * @param {object} theme el tema de MUI\n * @returns {boolean}\n */\nexport function isGlassTheme(theme) {\n return Boolean(theme?.toolkit?.glass);\n}\n\n/**\n * La opacidad del vidrio del tema: la que pidió el proyecto o GLASS_OPACITY.\n *\n * @param {object} theme\n * @returns {number}\n */\nexport function glassOpacityOf(theme) {\n return theme?.toolkit?.glass?.opacity ?? GLASS_OPACITY;\n}\n\n/**\n * El estilo de una superficie de vidrio sobre un color.\n *\n * @param {string} solidColor el color sólido de la superficie (p. ej. palette.background.paper o primary.main)\n * @param {object} [options]\n * @param {number} [options.opacity] por omisión GLASS_OPACITY\n * @param {boolean} [options.isDark] en oscuro el vidrio se aclara un poco y su filo brilla más\n * @param {boolean} [options.isControl] un control chico (botón, chip): sombra corta en vez de la de un panel\n * @returns {object} estilos para styleOverrides o sx\n */\nexport function glassSurfaceOf(solidColor, {opacity = GLASS_OPACITY, isDark = false, isControl = false} = {}) {\n const edge = isDark ? GLASS_EDGE_DARK : GLASS_EDGE_LIGHT;\n const tint = isDark ? `color-mix(in srgb, ${solidColor}, white ${DARK_GLASS_LIFT_PERCENT}%)` : solidColor;\n return {\n backgroundColor: `color-mix(in srgb, ${tint} ${Math.round(opacity * 100)}%, transparent)`,\n backdropFilter: GLASS_BLUR,\n WebkitBackdropFilter: GLASS_BLUR,\n backgroundImage: 'linear-gradient(180deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0) 40%)',\n boxShadow: [\n `inset 1px 1px 0 ${edge.rimLight}`,\n `inset -1px -1px 0 ${edge.rimShade}`,\n `inset 0 0 ${INNER_GLOW_PIXELS}px ${edge.innerGlow}`,\n `0 0 0 1px ${edge.outline}`,\n isControl ? edge.controlShadow : edge.shadow,\n ].join(', '),\n ...solidFallbackOf({backgroundColor: solidColor, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n\n/**\n * Lo que se pinta en lugar del vidrio si la persona pidió menos transparencia o más contraste, o si el navegador no sabe\n * desenfocar. Para lo transparente que no es una superficie (el fondo oscuro detrás de un diálogo, la perilla del\n * deslizador al arrastrarla).\n *\n * @param {object} solidStyle los estilos sólidos\n * @returns {object}\n */\nexport function solidFallbackOf(solidStyle) {\n return {[REDUCED_TRANSPARENCY_QUERY]: solidStyle, [NO_BACKDROP_FILTER_QUERY]: solidStyle};\n}\n\n/**\n * El vidrio sobre un color del tema en claro y en oscuro, con la opacidad del tema. Es lo que usan los ajustes de\n * componentes, y lo que usa el proyecto para algo suyo que flote:\n * sx={(theme) => glassStylesOf(theme)} // sobre el color de las tarjetas\n * sx={(theme) => glassStylesOf(theme, {color: paletteOf(theme).primary.main})} // vidrio del color principal\n *\n * @param {object} theme el tema de MUI\n * @param {object} [options]\n * @param {string} [options.color] el color de la superficie; por omisión el de las tarjetas (background.paper)\n * @param {string} [options.darkColor] el de modo oscuro, si es otro; por omisión el mismo\n * @param {number} [options.opacity] por omisión la del tema\n * @param {boolean} [options.isControl] un control chico (botón, chip): sombra corta en vez de la de un panel\n * @returns {object}\n */\nexport function glassStylesOf(theme, {color, darkColor, opacity, isControl = false} = {}) {\n const lightColor = color ?? paletteOf(theme).background.paper;\n const glassOpacity = opacity ?? glassOpacityOf(theme);\n return {\n ...lightDarkStylesOf(theme,\n glassSurfaceOf(lightColor, {opacity: glassOpacity, isControl}),\n glassSurfaceOf(darkColor ?? lightColor, {opacity: glassOpacity, isDark: true, isControl})),\n ...lensRulesOf(theme, {lightColor, darkColor: darkColor ?? lightColor, opacity: glassOpacity, isControl}),\n };\n}\n\n/**\n * El LENTE: lo que, según Apple, define al vidrio líquido («The primary way Liquid Glass visually defines itself is through\n * something called Lensing… previous materials scattered light, this new set of materials dynamically bends, shapes, and\n * concentrates light», WWDC25 «Meet Liquid Glass»). La orilla dobla lo de atrás (un filtro SVG de desplazamiento,\n * GlassLensFilter) y el centro queda más claro: menos tinte y menos desenfoque que el esmerilado.\n *\n * Solo en Chrome y sus parientes (Edge, Brave, Arc): son los únicos que aplican un filtro SVG en backdrop-filter; Firefox\n * lo acepta sin pintarlo (el vidrio se quedaría sin desenfoque) y Safari no lo entiende. Por eso va detrás de la marca que\n * GlassLensFilter pone en <body> solo en esos navegadores; en los demás queda el esmerilado. Con «Reducir transparencia» o\n * «Aumentar contraste» se pinta sólido igual que siempre.\n *\n * OJO: el modo oscuro va en su propia regla y no anidado: el selector de oscuro vive en <html> y, anidado debajo de la\n * marca de <body>, buscaría un .dark DENTRO de <body> y nunca coincidiría.\n *\n * @param {object} theme\n * @param {{lightColor: string, darkColor: string, opacity: number, isControl: boolean}} options\n * @returns {object}\n */\nfunction lensRulesOf(theme, {lightColor, darkColor, opacity, isControl}) {\n const lens = isControl ? GLASS_LENS.control : GLASS_LENS.panel;\n const lensOpacity = Math.max(0, opacity - lens.clearerBy);\n const backdrop = `blur(${lens.blurPixels}px) saturate(180%) url(#${lens.filterId})`;\n const lensSurfaceOf = (solidColor, isDark) => {\n const tint = isDark ? `color-mix(in srgb, ${solidColor}, white ${DARK_GLASS_LIFT_PERCENT}%)` : solidColor;\n return {\n backgroundColor: `color-mix(in srgb, ${tint} ${Math.round(lensOpacity * 100)}%, transparent)`,\n backdropFilter: backdrop,\n WebkitBackdropFilter: backdrop,\n ...solidFallbackOf({backgroundColor: solidColor, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n };\n const lensKey = `${GLASS_LENS_FLAG_SELECTOR} &`;\n // la regla de oscuro del tema: un selector (*:where(.dark) &) o una media query, según cómo elija el modo el proyecto\n const darkKey = Object.keys(theme.applyStyles('dark', {}))[0];\n if (!darkKey) {\n return {[lensKey]: lensSurfaceOf(lightColor, false)};\n }\n const darkLens = darkKey.startsWith('@')\n ? {[darkKey]: {[lensKey]: lensSurfaceOf(darkColor, true)}}\n : {[darkKey.replace('&', lensKey)]: lensSurfaceOf(darkColor, true)};\n return {[lensKey]: lensSurfaceOf(lightColor, false), ...darkLens};\n}\n\n/**\n * El mapa de desplazamiento del lente (una imagen SVG): rojo para lo de lado y verde para lo de arriba abajo; 128 en medio\n * es «no mover». En la orilla de la izquierda y la de arriba vale más (toma de adentro) y en la de la derecha y la de\n * abajo, menos (también de adentro): así la orilla dobla lo de atrás hacia el centro, como una lente convexa, y nunca toma\n * de afuera del vidrio (afuera no hay imagen y la orilla se quedaba en blanco).\n *\n * @param {number} edgeFraction lo ancho de la orilla que dobla (0 a 0.5 del tamaño del vidrio)\n * @returns {string} data URI para el feImage del filtro\n */\nexport function lensDisplacementMapOf(edgeFraction) {\n const inner = 1 - edgeFraction;\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100\" height=\"100\" preserveAspectRatio=\"none\"><defs>'\n + `<linearGradient id=\"x\" x1=\"0\" x2=\"1\"><stop offset=\"0\" stop-color=\"#ff0000\"/><stop offset=\"${edgeFraction}\" stop-color=\"#800000\"/>`\n + `<stop offset=\"${inner}\" stop-color=\"#800000\"/><stop offset=\"1\" stop-color=\"#000000\"/></linearGradient>`\n + `<linearGradient id=\"y\" x1=\"0\" x2=\"0\" y1=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#00ff00\"/><stop offset=\"${edgeFraction}\" stop-color=\"#008000\"/>`\n + `<stop offset=\"${inner}\" stop-color=\"#008000\"/><stop offset=\"1\" stop-color=\"#000000\"/></linearGradient>`\n + '</defs><rect width=\"100\" height=\"100\" fill=\"url(#x)\"/><rect width=\"100\" height=\"100\" fill=\"url(#y)\" style=\"mix-blend-mode:screen\"/></svg>';\n return `data:image/svg+xml,${encodeURIComponent(svg)}`;\n}\n\n/**\n * El material del contenido sobre un color: esmerilado como el vidrio pero sin el brillo del borde, y más transparente.\n *\n * @param {string} solidColor\n * @param {object} [options]\n * @param {number} [options.opacity] la del vidrio; el material le suma MATERIAL_OPACITY_OFFSET de su modo (le resta)\n * @param {boolean} [options.isDark]\n * @returns {object}\n */\nexport function materialSurfaceOf(solidColor, {opacity = GLASS_OPACITY, isDark = false} = {}) {\n const edge = isDark ? MATERIAL_EDGE_DARK : MATERIAL_EDGE_LIGHT;\n const tint = isDark ? `color-mix(in srgb, ${solidColor}, white ${DARK_GLASS_LIFT_PERCENT}%)` : solidColor;\n const offset = isDark ? MATERIAL_OPACITY_OFFSET.dark : MATERIAL_OPACITY_OFFSET.light;\n const materialOpacity = Math.min(1, Math.max(0, opacity + offset));\n return {\n backgroundColor: `color-mix(in srgb, ${tint} ${Math.round(materialOpacity * 100)}%, transparent)`,\n backdropFilter: GLASS_BLUR,\n WebkitBackdropFilter: GLASS_BLUR,\n backgroundImage: 'none',\n boxShadow: `0 0 0 1px ${edge.outline}, ${edge.shadow}`,\n ...solidFallbackOf({backgroundColor: solidColor, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n\n/**\n * El material del contenido en claro y en oscuro (las tarjetas con glass: {surfaces: true}). Para algo del proyecto que va\n * en el contenido: sx={(theme) => materialStylesOf(theme)}.\n *\n * @param {object} theme\n * @param {object} [options]\n * @param {string} [options.color] por omisión el de las tarjetas (background.paper)\n * @param {string} [options.darkColor] por omisión el mismo\n * @returns {object}\n */\nexport function materialStylesOf(theme, {color, darkColor} = {}) {\n const lightColor = color ?? paletteOf(theme).background.paper;\n const opacity = glassOpacityOf(theme);\n return lightDarkStylesOf(theme, materialSurfaceOf(lightColor, {opacity}), materialSurfaceOf(darkColor ?? lightColor, {opacity, isDark: true}));\n}\n\n/**\n * Solo el fondo del material, sin su línea ni su sombra: para lo que va DENTRO de una tarjeta y debe tapar lo que pasa por\n * debajo sin verse como un parche sólido (la columna pegada de la tabla al deslizarla de lado). Va como capa\n * (background-image) y no como color: así el color propio del elemento (el del renglón: la cebra, el cursor encima) se\n * sigue pintando encima.\n *\n * Con {thick: true}, el material «grueso» de Apple (HIG «Materials»: los gruesos son para leer sobre otro contenido): el\n * mismo desenfoque al 92 %. Es el de la columna fija de una tabla: con el delgado de la tarjeta (45 a 55 %) se veían pasar\n * por detrás las otras columnas (lo reportaron).\n *\n * @param {object} theme\n * @param {object} [options]\n * @param {boolean} [options.thick] el material grueso, para tapar lo que pasa por debajo\n * @returns {object}\n */\nexport function materialBackgroundOf(theme, {thick = false} = {}) {\n const paper = paletteOf(theme).background.paper;\n const opacityOf = (offset) => (thick ? THICK_MATERIAL_PERCENT : Math.round(Math.min(1, Math.max(0, glassOpacityOf(theme) + offset)) * 100));\n const layerOf = (color) => `linear-gradient(${color}, ${color})`;\n const frostedOf = (tint, opacity) => ({\n backgroundImage: layerOf(`color-mix(in srgb, ${tint} ${opacity}%, transparent)`),\n backdropFilter: GLASS_BLUR,\n WebkitBackdropFilter: GLASS_BLUR,\n });\n return {\n ...lightDarkStylesOf(theme,\n frostedOf(paper, opacityOf(MATERIAL_OPACITY_OFFSET.light)),\n frostedOf(`color-mix(in srgb, ${paper}, white ${DARK_GLASS_LIFT_PERCENT}%)`, opacityOf(MATERIAL_OPACITY_OFFSET.dark))),\n ...solidFallbackOf({backgroundImage: layerOf(paper), backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n\n/**\n * La «gota» que marca lo elegido dentro de un control (la pestaña, la opción, el renglón del menú lateral): en claro, una\n * pastilla blanca con su brillo y su sombra; en oscuro, un relleno gris parejo, como el renglón elegido de las barras\n * laterales de Apple en oscuro. No es transparente del todo: va DENTRO de algo que ya puede ser de vidrio (un menú), y\n * vidrio sobre vidrio no se lee.\n * OJO, oscuro: con blanco al 14 % casi no se veía, y su línea de luz arriba dibujaba un arco raro en la esquina («no se\n * nota la selección», «se ve raro»; lo reportaron). Va al 18 % y sin línea.\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function glassDropOf(theme) {\n const palette = paletteOf(theme);\n return lightDarkStylesOf(theme, {\n backgroundColor: palette.background.paper,\n color: palette.text.primary,\n boxShadow: 'inset 0 1px 0 rgba(255, 255, 255, 0.6), 0 1px 3px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.08)',\n }, {\n backgroundColor: `color-mix(in srgb, ${palette.common.white} ${DARK_DROP_WHITE_PERCENT}%, transparent)`,\n boxShadow: '0 1px 3px rgba(0, 0, 0, 0.35)',\n });\n}\n\n/**\n * El relleno de un control lleno de color (el botón principal, la etiqueta elegida) para llevar letra BLANCA y que se lea:\n * el color del tema oscurecido lo justo para llegar a 4.5 : 1 (WCAG). En oscuro la paleta trae letra negra sobre el\n * naranja («El suyo», «Guardar»: se veía feo, lo reportaron) y el blanco sobre el naranja tal cual da 2.85 : 1; con el\n * naranja al 75 % y blanco da 4.79 : 1. Se calcula con el color que elija el proyecto, no con uno fijo.\n *\n * @param {string} rawColor el color en #RRGGBB o #RGB (el de la paleta, no la variable CSS)\n * @returns {string|null} el relleno en #RRGGBB; null si el color no viene en hexadecimal\n */\nexport function whiteLabelFillOf(rawColor) {\n const channels = hexChannelsOf(rawColor);\n if (!channels) {\n return null;\n }\n // del color tal cual hacia el negro, en pasos de 5 %, hasta que la letra blanca se lea\n for (let share = 100; share >= MIN_FILL_SHARE_PERCENT; share -= FILL_SHARE_STEP_PERCENT) {\n const mixed = channels.map((channel) => Math.round((channel * share) / 100));\n if (contrastWithWhiteOf(mixed) >= MIN_TEXT_CONTRAST) {\n return `#${mixed.map((channel) => channel.toString(16).padStart(2, '0')).join('')}`;\n }\n }\n return `#${channels.map((channel) => Math.round((channel * MIN_FILL_SHARE_PERCENT) / 100).toString(16).padStart(2, '0')).join('')}`;\n}\n\n/**\n * Los tres canales de un color #RRGGBB o #RGB (0 a 255); null si no es hexadecimal.\n *\n * @param {string} color\n * @returns {number[]|null}\n */\nfunction hexChannelsOf(color) {\n const match = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(String(color ?? '').trim());\n if (!match) {\n return null;\n }\n const digits = match[1].length === 3 ? [...match[1]].map((digit) => digit + digit).join('') : match[1];\n return [0, 2, 4].map((start) => parseInt(digits.slice(start, start + 2), 16));\n}\n\n/**\n * El contraste de la letra blanca sobre un color (fórmula de WCAG).\n *\n * @param {number[]} channels\n * @returns {number}\n */\nfunction contrastWithWhiteOf(channels) {\n const [red, green, blue] = channels.map((channel) => {\n const unit = channel / 255;\n return unit <= 0.03928 ? unit / 12.92 : ((unit + 0.055) / 1.055) ** 2.4;\n });\n const luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue;\n return 1.05 / (luminance + 0.05);\n}\n\n/**\n * El «pozo» de un campo de texto dentro del contenido (una tarjeta, un formulario agrupado), como los de Apple: un relleno\n * parejo con esquinas de 12 px, del gris de relleno de Apple («tertiary fill»): tenue en claro y más claro que la tarjeta en\n * oscuro (con negro, en oscuro se perdía). Sin vidrio adentro de la tarjeta: ahí no tiene nada que dejar\n * ver. Con el cursor encima se marca apenas; antes el relleno salía solo con el cursor y en cuadro («hovers espantosos»).\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function fieldWellStylesOf(theme) {\n return {\n backgroundImage: 'none',\n backdropFilter: 'none',\n WebkitBackdropFilter: 'none',\n boxShadow: 'none',\n borderRadius: FIELD_WELL_RADIUS_PIXELS,\n ...lightDarkStylesOf(theme,\n {backgroundColor: FIELD_WELL_FILL.light.rest, '&:hover': {backgroundColor: FIELD_WELL_FILL.light.hover}},\n {backgroundColor: FIELD_WELL_FILL.dark.rest, '&:hover': {backgroundColor: FIELD_WELL_FILL.dark.hover}}),\n };\n}\n\n/**\n * Un campo de texto suelto sobre el lienzo (fuera de una tarjeta): una lámina de vidrio clara en claro y el gris de relleno\n * de Apple en oscuro, más claro que el fondo casi negro. Con «Reducir transparencia» se pinta sólido.\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function canvasFieldStylesOf(theme) {\n const paper = paletteOf(theme).background.paper;\n return {\n backgroundImage: 'none',\n backdropFilter: GLASS_BLUR,\n WebkitBackdropFilter: GLASS_BLUR,\n borderRadius: FIELD_WELL_RADIUS_PIXELS,\n ...lightDarkStylesOf(theme, {\n backgroundColor: CANVAS_FIELD.light.rest,\n boxShadow: `0 0 0 1px ${CANVAS_FIELD.light.edge}`,\n '&:hover': {backgroundColor: CANVAS_FIELD.light.hover},\n }, {\n backgroundColor: CANVAS_FIELD.dark.rest,\n boxShadow: `0 0 0 1px ${CANVAS_FIELD.dark.edge}`,\n '&:hover': {backgroundColor: CANVAS_FIELD.dark.hover},\n }),\n ...solidFallbackOf({backgroundColor: paper, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n\n/**\n * El color de un TEXTO que debe ir del color del tema (una liga, un botón de solo texto, el renglón elegido del menú, el\n * valor de una fecha): el color de la paleta oscurecido en claro y aclarado en oscuro, para que se lea. Medido (WCAG pide\n * 4.5 : 1 en letra normal): el naranja de la marca sobre una tarjeta clara daba 2.78 : 1 y sobre su propio tinte en oscuro\n * 4.41 : 1 (el reporte: «cuesta leer», «se pierde»); con 30 % de negro en claro da 5.24 : 1 y con 30 % de blanco en\n * oscuro 8.23 : 1. Los botones con relleno de color NO usan esto: van con letra de un solo color (HIG «Buttons»: «Avoid\n * applying a similar color to button labels and content layer backgrounds»).\n *\n * @param {object} theme\n * @param {string} [colorName] primary, error, success… (por omisión primary)\n * @returns {object} {color, y el de oscuro}\n */\nexport function accentTextStylesOf(theme, colorName = 'primary') {\n const palette = paletteOf(theme);\n const main = (palette[colorName] ?? palette.primary).main;\n const keep = 100 - ACCENT_TEXT_SHADE_PERCENT;\n return lightDarkStylesOf(theme, {color: `color-mix(in srgb, ${main} ${keep}%, black)`}, {color: `color-mix(in srgb, ${main} ${keep}%, white)`});\n}\n\n/**\n * Un fondo FIJO a la ventana que no se mueve al deslizar, también en el iPhone: va en una capa aparte (::before con\n * position: fixed) detrás del contenido del elemento. Así el vidrio se ve pasar por encima de un fondo quieto.\n *\n * OJO: background-attachment: fixed no sirve para esto. Safari del iPhone y del iPad lo ignora y el fondo se movía con\n * todo (lo vio el autor en el teléfono); además, en escritorio vuelve a pintar todo el fondo en cada paso al deslizar.\n * La capa va con z-index -1 dentro de un contexto propio (isolation): queda arriba del color del elemento y abajo de su\n * contenido. Si el elemento es una caja con esquinas (la escena de un ejemplo), clip-path la recorta a la caja.\n *\n * @param {object} layerStyles el fondo de la capa (backgroundColor, backgroundImage…; puede llevar el modo oscuro)\n * @param {object} [options]\n * @param {string} [options.clipPath] p. ej. 'inset(0 round 20px)' para una caja; sin él, la capa ocupa toda la ventana\n * @returns {object} estilos para el sx del elemento\n */\nexport function fixedBackgroundLayerOf(layerStyles, {clipPath} = {}) {\n return {\n isolation: 'isolate',\n ...(clipPath && {clipPath}),\n // OJO, iPhone: con inset: 0 el alto de la capa cambia cuando la barra de Safari se esconde al deslizar, y el fondo\n // «seguía al scroll» (lo vio el autor en su teléfono). Medida fija de toda la pantalla (100vw × 100lvh, el alto con\n // la barra escondida; 100vh donde no hay lvh) y su propia capa de composición (translateZ), que es lo que la deja\n // quieta en WebKit\n '&::before': {\n content: '\"\"',\n position: 'fixed',\n top: 0,\n left: 0,\n width: '100vw',\n height: '100vh',\n '@supports (height: 100lvh)': {height: '100lvh'},\n transform: 'translateZ(0)',\n willChange: 'transform',\n zIndex: -1,\n pointerEvents: 'none',\n ...layerStyles,\n },\n };\n}\n\n/**\n * El fondo del lienzo con vidrio: manchas del color principal y del de información, fijas a la ventana, para\n * que el vidrio tenga algo que desenfocar. AppLayout ya lo pone; una pantalla fuera del marco (el inicio de sesión) lo usa\n * con sx={(theme) => ambientBackgroundOf(theme)}.\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function ambientBackgroundOf(theme) {\n const palette = paletteOf(theme);\n const washOf = (strength, tones) => [\n `radial-gradient(60vmax 45vmax at 0% 0%, color-mix(in srgb, ${tones.primary} ${strength.primary}%, transparent), transparent 70%)`,\n `radial-gradient(50vmax 40vmax at 100% 15%, color-mix(in srgb, ${tones.info} ${strength.info}%, transparent), transparent 70%)`,\n `radial-gradient(55vmax 45vmax at 70% 100%, color-mix(in srgb, ${tones.accent} ${strength.accent}%, transparent), transparent 70%)`,\n `radial-gradient(45vmax 35vmax at 45% 50%, color-mix(in srgb, ${tones.info} ${strength.center}%, transparent), transparent 70%)`,\n ].join(', ');\n const lightTones = {primary: palette.primary.main, info: palette.info.main, accent: palette.primary.light};\n // en oscuro, los tonos OSCUROS de la paleta sobre un casi negro: el color tiñe sin aclarar el fondo, y las tarjetas y el\n // vidrio (más claros) no se pierden (ver DARK_CANVAS)\n const darkTones = {primary: palette.primary.dark, info: palette.info.dark, accent: palette.primary.dark};\n return {\n ...lightDarkStylesOf(theme, {backgroundColor: palette.background.default}, {backgroundColor: DARK_CANVAS.base}),\n ...fixedBackgroundLayerOf(lightDarkStylesOf(theme,\n {backgroundColor: palette.background.default, backgroundImage: washOf(AMBIENT_STRENGTH_LIGHT, lightTones)},\n {backgroundColor: DARK_CANVAS.base, backgroundImage: washOf(AMBIENT_STRENGTH_DARK, darkTones)})),\n };\n}\n\n// la orilla de arriba con la barra en cápsulas: cuánto tinte del lienzo lleva y cuánto desenfoca (px)\nconst SCROLL_EDGE_TINT_PERCENT = 55;\nconst SCROLL_EDGE_BLUR_PIXELS = 12;\n\n/**\n * La orilla de arriba cuando la barra va en cápsulas (TOP_BAR.capsules con vidrio, como las ventanas de macOS Tahoe; Apple le\n * llama «scroll edge effect»): lo que pasa por debajo se desenfoca y se desvanece hacia el contenido, para que el título\n * y las cápsulas se lean sobre cualquier cosa. Con «Reducir transparencia» o sin backdrop-filter, el color del lienzo.\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function scrollEdgeStylesOf(theme) {\n const palette = paletteOf(theme);\n const tintOf = (canvas) => `color-mix(in srgb, ${canvas} ${SCROLL_EDGE_TINT_PERCENT}%, transparent)`;\n const blur = `blur(${SCROLL_EDGE_BLUR_PIXELS}px)`;\n // de arriba (cubre) hacia abajo (se desvanece): sin raya donde termina\n const fade = 'linear-gradient(to bottom, black 45%, transparent)';\n return {\n ...lightDarkStylesOf(theme, {backgroundColor: tintOf(palette.background.default)}, {backgroundColor: tintOf(DARK_CANVAS.base)}),\n backdropFilter: blur,\n WebkitBackdropFilter: blur,\n maskImage: fade,\n WebkitMaskImage: fade,\n ...solidFallbackOf({backgroundColor: palette.background.default, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"glassSurface.js","sources":["../../src/theme/glassSurface.js"],"sourcesContent":["// El «vidrio líquido» (Liquid Glass de Apple, 2025) en su versión de CSS: una superficie poco transparente que deja ver,\n// desenfocado, lo que pasa por detrás, con un brillo en el borde de arriba. La guía de Apple (Human Interface Guidelines,\n// «Materials»: https://developer.apple.com/design/human-interface-guidelines/materials) separa dos capas, y aquí igual:\n// - VIDRIO (glassStylesOf): «a distinct functional layer for controls and navigation elements… that floats above the\n// content layer». En el framework: la barra de arriba, el menú lateral, los menús y ventanitas, los diálogos, los\n// tooltips, los avisos, el panel de descargas, el botón flotante y, en los controles, la «gota» que marca lo elegido.\n// - MATERIAL (materialStylesOf): «Don't use Liquid Glass in the content layer»; el contenido usa los materiales estándar\n// (vidrio esmerilado, sin el brillo del borde) y los gruesos, más opacos, porque «provide better contrast for text».\n// Es lo que llevan las tarjetas con createToolkitTheme({glass: {surfaces: true}}).\n//\n// Decisiones, con su porqué:\n// - 60 % opaco por omisión. Con 80 %, en claro el vidrio era casi blanco sobre un lienzo casi blanco y se leía como\n// «cápsulas con sombra» (lo dijo el autor), no como vidrio: Apple dice que el vidrio «has no inherent color, and\n// instead takes on colors from the content directly behind it», y para eso tiene que dejar pasar el color. El material\n// del contenido es «delgado» (MATERIAL_OPACITY_OFFSET): con 74 % las tarjetas se veían planas, de un solo color (lo dijo\n// el autor); con el desenfoque de 20 px el texto se sigue leyendo. El proyecto lo cambia con\n// createToolkitTheme({glass: {opacity: 0.8}}), que mueve las dos.\n// - Lo que dibuja el vidrio es su filo de luz, como la orilla de una lente: brillante arriba a la izquierda (de donde\n// viene la luz), más suave abajo a la derecha, y un resplandor por dentro; la sombra de afuera es corta.\n// - Se pinta sólido si la persona pidió menos transparencia o más contraste en su equipo, o si el navegador no sabe\n// desenfocar: la misma guía pide respetar «Reducir transparencia», y Apple tuvo que agregar el control en iOS 26.1\n// porque el texto sobre vidrio no se leía.\n// - Con vidrio, el lienzo lleva unas manchas de color (ambientBackgroundOf): sobre un lienzo liso, el vidrio no\n// se distingue de una superficie sólida, porque no hay nada que desenfocar.\n// - Esquinas concéntricas: la de afuera es la de adentro más el margen (los renglones del menú lateral son de 12 px a 8 px\n// del borde, así que el panel es de 20 px). Apple lo pide así; si no, las esquinas «no casan» y se nota.\n// - Sin refracción (la lupa que deforma lo de atrás): en la web solo sale con filtros SVG que hoy funcionan nada más en\n// Chrome, o con WebGL. Esto es la versión que funciona en todos.\n// - color-mix y no alpha(): sirve igual con las variables CSS del tema (var(--mui-palette-…)) que con un color normal.\n//\n// OJO: backdrop-filter vuelve a la superficie el «contenedor» de lo que lleve adentro con position: fixed. Lo que deba\n// quedar fijo a la ventana va fuera de ella (los menús de MUI ya van en un portal).\n//\n// Funciones puras, sin React: function (regla de la casa).\nimport {paletteOf} from '@/theme/components/paletteOf.js';\nimport {lightDarkStylesOf} from '@/theme/lightDarkStyles.js';\n\n/** Qué tan opaca es la superficie (0 a 1). */\nexport const GLASS_OPACITY = 0.6;\n\n/** Las esquinas de lo que flota grande (menú lateral, barra, diálogos): renglones de 12 px a 8 px del borde. */\nexport const GLASS_PANEL_RADIUS_PIXELS = 20;\n\n/** Las esquinas de los menús y ventanitas: renglones de 8 px a 4 px del borde. */\nexport const GLASS_MENU_RADIUS_PIXELS = 12;\n\n/**\n * Lo que se separa de la orilla de la ventana lo que flota (la barra, el menú lateral, los cajones y la hoja de abajo):\n * Apple lo pide para que el contenido se asome por detrás («half sheets are inset from the edge of the display to allow\n * content to peek through from beneath them», Adopting Liquid Glass).\n */\nexport const GLASS_INSET_PIXELS = 8;\n\nconst GLASS_BLUR = 'blur(20px) saturate(180%)';\n\n/**\n * El lente de cada tamaño (ver lensRulesOf), medido en capturas de Chrome: el control chico (botón, chip) más claro y con\n * la orilla más marcada; el panel (barra, menú, diálogo) más grueso, porque lleva texto («Liquid Glass appears more opaque\n * in larger elements like sidebars to preserve legibility», HIG «Color»). edgeFraction y scale van en fracción del tamaño\n * del vidrio; clearerBy es cuánto menos tinte lleva que el esmerilado.\n */\nexport const GLASS_LENS = Object.freeze({\n control: {filterId: 'toolkit-glass-lens-control', edgeFraction: 0.25, scale: 0.2, blurPixels: 3, clearerBy: 0.25},\n panel: {filterId: 'toolkit-glass-lens-panel', edgeFraction: 0.12, scale: 0.05, blurPixels: 10, clearerBy: 0.1},\n});\n\n// el gris de la gota en oscuro (por ciento de blanco): lo elegido se tiene que notar (glassDropOf)\nconst DARK_DROP_WHITE_PERCENT = 18;\n// cuánto negro (en claro) o blanco (en oscuro) lleva un texto del color del tema para leerse (accentTextStylesOf)\nconst ACCENT_TEXT_SHADE_PERCENT = 30;\n// el pozo de los campos (fieldWellStylesOf): el gris de relleno de Apple en claro y un oscurecido en oscuro\nconst FIELD_WELL_RADIUS_PIXELS = 12;\nconst FIELD_WELL_FILL = Object.freeze({\n light: {rest: 'rgba(118, 118, 128, 0.12)', hover: 'rgba(118, 118, 128, 0.18)'},\n // en oscuro el gris de Apple, MÁS CLARO que lo de atrás (su «tertiary fill»): con negro al 32 % el campo se perdía\n dark: {rest: 'rgba(118, 118, 128, 0.24)', hover: 'rgba(118, 118, 128, 0.30)'},\n});\n// el campo suelto sobre el lienzo (canvasFieldStylesOf): lámina clara en claro, oscura en oscuro, con su filo\nconst CANVAS_FIELD = Object.freeze({\n light: {rest: 'rgba(255, 255, 255, 0.62)', hover: 'rgba(255, 255, 255, 0.78)', edge: 'rgba(15, 23, 42, 0.10)'},\n // en oscuro, el gris de relleno de Apple (más claro que el fondo). Con negro al 34 % el campo contra el fondo casi negro\n // medía 1.01 : 1 y no se veía (lo reportaron: el buscador «se pierde»); con este, 1.26 : 1, y su filo aparte\n dark: {rest: 'rgba(118, 118, 128, 0.24)', hover: 'rgba(118, 118, 128, 0.30)', edge: 'rgba(255, 255, 255, 0.10)'},\n});\n// el contraste mínimo de WCAG para letra normal, y cómo se oscurece un relleno hasta lograrlo (whiteLabelFillOf)\nconst MIN_TEXT_CONTRAST = 4.5;\nconst FILL_SHARE_STEP_PERCENT = 5;\nconst MIN_FILL_SHARE_PERCENT = 30;\n\n/** La marca que GlassLensFilter pone en <body> cuando el navegador sí pinta el lente. */\nexport const GLASS_LENS_FLAG_SELECTOR = 'body[data-glass-lens=\"on\"]';\n\n/**\n * El selector de «este control está dentro de una tarjeta» (cualquier Paper: tarjeta, diálogo, menú), donde el control ya\n * no es vidrio. Va en dos versiones, sin y con la marca del lente: la regla del lente (una etiqueta y dos clases) le ganaba\n * a la de la tarjeta (dos clases) y los botones dentro de una tarjeta volvían a ser vidrio. Medido en Chrome.\n *\n * @param {string} [suffix] lo que va pegado al control (p. ej. ':not(.MuiButtonGroup-grouped)')\n * @returns {string}\n */\nexport function insideContentSelectorOf(suffix = '') {\n return `.MuiPaper-root &${suffix}, ${GLASS_LENS_FLAG_SELECTOR} .MuiPaper-root &${suffix}`;\n}\nconst REDUCED_TRANSPARENCY_QUERY = '@media (prefers-reduced-transparency: reduce), (prefers-contrast: more)';\nconst NO_BACKDROP_FILTER_QUERY = '@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)))';\n\n// qué tan fuertes son las manchas del lienzo (por ciento del color). En oscuro van MÁS fuertes que en claro: sobre un lienzo\n// casi negro, unas manchas tenues no dan nada que desenfocar y el vidrio se ve como un gris sólido.\n// La de en medio (center) va detrás del contenido: sin ella, en claro las tarjetas de vidrio quedaban sobre blanco y se\n// veían sólidas (medido en las capturas de Chrome).\nconst AMBIENT_STRENGTH_LIGHT = Object.freeze({primary: 40, info: 30, accent: 30, center: 16});\n// en oscuro: manchas de los tonos oscuros sobre un casi negro con un toque azul (como los fondos oscuros de Apple). Antes\n// eran los tonos vivos al 36 % sobre #0A0A0A: aclaraban el fondo hasta el gris de las tarjetas y los elementos se perdían\n// (lo reportaron; medido: tarjeta contra fondo 1.12 : 1). Ahora 1.28 : 1 en el peor punto\nconst AMBIENT_STRENGTH_DARK = Object.freeze({primary: 18, info: 18, accent: 12, center: 10});\nconst DARK_CANVAS = Object.freeze({base: '#05070B'});\n\n// el filo de la lente: la luz de arriba a la izquierda (rimLight), la de abajo a la derecha más suave (rimShade), un\n// resplandor por dentro (innerGlow), una línea fina de afuera que lo separa del lienzo (outline) y la sombra que lo\n// despega (shadow). En oscuro el filo es más tenue, pero la sombra más fuerte: una negra suave no se ve sobre casi negro.\n// Un control chico (botón, chip) lleva una sombra corta (controlShadow): la de un panel se veía como neblina alrededor y,\n// dentro de una tira que se desliza (los filtros rápidos), la tira la cortaba en un rectángulo.\nconst GLASS_EDGE_LIGHT = Object.freeze({\n rimLight: 'rgba(255, 255, 255, 0.95)', rimShade: 'rgba(255, 255, 255, 0.5)', innerGlow: 'rgba(255, 255, 255, 0.45)',\n outline: 'rgba(15, 23, 42, 0.07)', shadow: '0 6px 20px rgba(15, 23, 42, 0.10)',\n controlShadow: '0 1px 2px rgba(15, 23, 42, 0.10), 0 2px 6px rgba(15, 23, 42, 0.06)',\n});\nconst GLASS_EDGE_DARK = Object.freeze({\n rimLight: 'rgba(255, 255, 255, 0.32)', rimShade: 'rgba(255, 255, 255, 0.12)', innerGlow: 'rgba(255, 255, 255, 0.07)',\n outline: 'rgba(0, 0, 0, 0.35)', shadow: '0 8px 28px rgba(0, 0, 0, 0.45)',\n controlShadow: '0 1px 2px rgba(0, 0, 0, 0.40), 0 2px 6px rgba(0, 0, 0, 0.25)',\n});\n// lo ancho del resplandor de adentro (px): lo que se ve como el grosor del vidrio en la orilla\nconst INNER_GLOW_PIXELS = 12;\n// en oscuro el vidrio se aclara un poco sobre su color: un gris igual de oscuro que el lienzo no se distingue de él aunque\n// desenfoque. Es lo que Apple hace en oscuro: lo que va al frente usa los colores «elevated», más claros, «making\n// foreground interfaces appear to advance» (HIG, Dark Mode). Con 8 % las tarjetas y los controles se perdían en el fondo\n// oscuro (lo reportaron); con 16 % y el lienzo nuevo (DARK_CANVAS) la tarjeta se separa 1.28 : 1 del fondo y el control\n// 1.32 : 1 (medido; Apple, su tarjeta #1C1C1E sobre negro: 1.23 : 1)\nconst DARK_GLASS_LIFT_PERCENT = 16;\n\n// el material del contenido: sin brillo de borde (eso es del vidrio de los controles), con una línea fina de afuera que lo\n// separa del lienzo y una sombra suave. En oscuro la línea es clara: una oscura no se ve sobre casi negro\nconst MATERIAL_EDGE_LIGHT = Object.freeze({outline: 'rgba(15, 23, 42, 0.08)', shadow: '0 1px 2px rgba(15, 23, 42, 0.06), 0 8px 24px rgba(15, 23, 42, 0.06)'});\nconst MATERIAL_EDGE_DARK = Object.freeze({outline: 'rgba(255, 255, 255, 0.08)', shadow: '0 8px 24px rgba(0, 0, 0, 0.35)'});\n// el material del contenido es «delgado» (HIG «Materials»: «Thinner materials… help people retain their context by\n// providing a visible reminder of the content that's in the background»): menos opaco que el vidrio de los controles. Con\n// el «grueso» (+0.14, 74 %) las tarjetas se veían planas; el texto se lee por el desenfoque de 20 px, y con «Reducir\n// transparencia» se pinta sólido. En oscuro resta menos: con 45 % la tarjeta casi no se separaba del fondo (medido 1.12 : 1)\nconst MATERIAL_OPACITY_OFFSET = Object.freeze({light: -0.15, dark: -0.05});\n// el material «grueso» (por ciento): tapa lo que pasa por debajo, como la columna fija de una tabla\nconst THICK_MATERIAL_PERCENT = 92;\n\n/**\n * Si el tema trae el vidrio prendido (createToolkitTheme({glass: …})). Lo usan los componentes del framework que flotan\n * (el marco, el panel de descargas, los avisos) y lo puede usar el proyecto para lo suyo.\n *\n * @param {object} theme el tema de MUI\n * @returns {boolean}\n */\nexport function isGlassTheme(theme) {\n return Boolean(theme?.toolkit?.glass);\n}\n\n/**\n * La opacidad del vidrio del tema: la que pidió el proyecto o GLASS_OPACITY.\n *\n * @param {object} theme\n * @returns {number}\n */\nexport function glassOpacityOf(theme) {\n return theme?.toolkit?.glass?.opacity ?? GLASS_OPACITY;\n}\n\n/**\n * El estilo de una superficie de vidrio sobre un color.\n *\n * @param {string} solidColor el color sólido de la superficie (p. ej. palette.background.paper o primary.main)\n * @param {object} [options]\n * @param {number} [options.opacity] por omisión GLASS_OPACITY\n * @param {boolean} [options.isDark] en oscuro el vidrio se aclara un poco y su filo brilla más\n * @param {boolean} [options.isControl] un control chico (botón, chip): sombra corta en vez de la de un panel\n * @returns {object} estilos para styleOverrides o sx\n */\nexport function glassSurfaceOf(solidColor, {opacity = GLASS_OPACITY, isDark = false, isControl = false} = {}) {\n const edge = isDark ? GLASS_EDGE_DARK : GLASS_EDGE_LIGHT;\n const tint = isDark ? `color-mix(in srgb, ${solidColor}, white ${DARK_GLASS_LIFT_PERCENT}%)` : solidColor;\n return {\n backgroundColor: `color-mix(in srgb, ${tint} ${Math.round(opacity * 100)}%, transparent)`,\n backdropFilter: GLASS_BLUR,\n WebkitBackdropFilter: GLASS_BLUR,\n backgroundImage: 'linear-gradient(180deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0) 40%)',\n boxShadow: [\n `inset 1px 1px 0 ${edge.rimLight}`,\n `inset -1px -1px 0 ${edge.rimShade}`,\n `inset 0 0 ${INNER_GLOW_PIXELS}px ${edge.innerGlow}`,\n `0 0 0 1px ${edge.outline}`,\n isControl ? edge.controlShadow : edge.shadow,\n ].join(', '),\n ...solidFallbackOf({backgroundColor: solidColor, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n\n/**\n * Lo que se pinta en lugar del vidrio si la persona pidió menos transparencia o más contraste, o si el navegador no sabe\n * desenfocar. Para lo transparente que no es una superficie (el fondo oscuro detrás de un diálogo, la perilla del\n * deslizador al arrastrarla).\n *\n * @param {object} solidStyle los estilos sólidos\n * @returns {object}\n */\nexport function solidFallbackOf(solidStyle) {\n return {[REDUCED_TRANSPARENCY_QUERY]: solidStyle, [NO_BACKDROP_FILTER_QUERY]: solidStyle};\n}\n\n/**\n * El vidrio sobre un color del tema en claro y en oscuro, con la opacidad del tema. Es lo que usan los ajustes de\n * componentes, y lo que usa el proyecto para algo suyo que flote:\n * sx={(theme) => glassStylesOf(theme)} // sobre el color de las tarjetas\n * sx={(theme) => glassStylesOf(theme, {color: paletteOf(theme).primary.main})} // vidrio del color principal\n *\n * @param {object} theme el tema de MUI\n * @param {object} [options]\n * @param {string} [options.color] el color de la superficie; por omisión el de las tarjetas (background.paper)\n * @param {string} [options.darkColor] el de modo oscuro, si es otro; por omisión el mismo\n * @param {number} [options.opacity] por omisión la del tema\n * @param {boolean} [options.isControl] un control chico (botón, chip): sombra corta en vez de la de un panel\n * @returns {object}\n */\nexport function glassStylesOf(theme, {color, darkColor, opacity, isControl = false} = {}) {\n const lightColor = color ?? paletteOf(theme).background.paper;\n const glassOpacity = opacity ?? glassOpacityOf(theme);\n return {\n ...lightDarkStylesOf(theme,\n glassSurfaceOf(lightColor, {opacity: glassOpacity, isControl}),\n glassSurfaceOf(darkColor ?? lightColor, {opacity: glassOpacity, isDark: true, isControl})),\n ...lensRulesOf(theme, {lightColor, darkColor: darkColor ?? lightColor, opacity: glassOpacity, isControl}),\n };\n}\n\n/**\n * El LENTE: lo que, según Apple, define al vidrio líquido («The primary way Liquid Glass visually defines itself is through\n * something called Lensing… previous materials scattered light, this new set of materials dynamically bends, shapes, and\n * concentrates light», WWDC25 «Meet Liquid Glass»). La orilla dobla lo de atrás (un filtro SVG de desplazamiento,\n * GlassLensFilter) y el centro queda más claro: menos tinte y menos desenfoque que el esmerilado.\n *\n * Solo en Chrome y sus parientes (Edge, Brave, Arc): son los únicos que aplican un filtro SVG en backdrop-filter; Firefox\n * lo acepta sin pintarlo (el vidrio se quedaría sin desenfoque) y Safari no lo entiende. Por eso va detrás de la marca que\n * GlassLensFilter pone en <body> solo en esos navegadores; en los demás queda el esmerilado. Con «Reducir transparencia» o\n * «Aumentar contraste» se pinta sólido igual que siempre.\n *\n * OJO: el modo oscuro va en su propia regla y no anidado: el selector de oscuro vive en <html> y, anidado debajo de la\n * marca de <body>, buscaría un .dark DENTRO de <body> y nunca coincidiría.\n *\n * @param {object} theme\n * @param {{lightColor: string, darkColor: string, opacity: number, isControl: boolean}} options\n * @returns {object}\n */\nfunction lensRulesOf(theme, {lightColor, darkColor, opacity, isControl}) {\n const lens = isControl ? GLASS_LENS.control : GLASS_LENS.panel;\n const lensOpacity = Math.max(0, opacity - lens.clearerBy);\n const backdrop = `blur(${lens.blurPixels}px) saturate(180%) url(#${lens.filterId})`;\n const lensSurfaceOf = (solidColor, isDark) => {\n const tint = isDark ? `color-mix(in srgb, ${solidColor}, white ${DARK_GLASS_LIFT_PERCENT}%)` : solidColor;\n return {\n backgroundColor: `color-mix(in srgb, ${tint} ${Math.round(lensOpacity * 100)}%, transparent)`,\n backdropFilter: backdrop,\n WebkitBackdropFilter: backdrop,\n ...solidFallbackOf({backgroundColor: solidColor, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n };\n const lensKey = `${GLASS_LENS_FLAG_SELECTOR} &`;\n // la regla de oscuro del tema: un selector (*:where(.dark) &) o una media query, según cómo elija el modo el proyecto\n const darkKey = Object.keys(theme.applyStyles('dark', {}))[0];\n if (!darkKey) {\n return {[lensKey]: lensSurfaceOf(lightColor, false)};\n }\n const darkLens = darkKey.startsWith('@')\n ? {[darkKey]: {[lensKey]: lensSurfaceOf(darkColor, true)}}\n : {[darkKey.replace('&', lensKey)]: lensSurfaceOf(darkColor, true)};\n return {[lensKey]: lensSurfaceOf(lightColor, false), ...darkLens};\n}\n\n/**\n * El mapa de desplazamiento del lente (una imagen SVG): rojo para lo de lado y verde para lo de arriba abajo; 128 en medio\n * es «no mover». En la orilla de la izquierda y la de arriba vale más (toma de adentro) y en la de la derecha y la de\n * abajo, menos (también de adentro): así la orilla dobla lo de atrás hacia el centro, como una lente convexa, y nunca toma\n * de afuera del vidrio (afuera no hay imagen y la orilla se quedaba en blanco).\n *\n * @param {number} edgeFraction lo ancho de la orilla que dobla (0 a 0.5 del tamaño del vidrio)\n * @returns {string} data URI para el feImage del filtro\n */\nexport function lensDisplacementMapOf(edgeFraction) {\n const inner = 1 - edgeFraction;\n const svg = '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100\" height=\"100\" preserveAspectRatio=\"none\"><defs>'\n + `<linearGradient id=\"x\" x1=\"0\" x2=\"1\"><stop offset=\"0\" stop-color=\"#ff0000\"/><stop offset=\"${edgeFraction}\" stop-color=\"#800000\"/>`\n + `<stop offset=\"${inner}\" stop-color=\"#800000\"/><stop offset=\"1\" stop-color=\"#000000\"/></linearGradient>`\n + `<linearGradient id=\"y\" x1=\"0\" x2=\"0\" y1=\"0\" y2=\"1\"><stop offset=\"0\" stop-color=\"#00ff00\"/><stop offset=\"${edgeFraction}\" stop-color=\"#008000\"/>`\n + `<stop offset=\"${inner}\" stop-color=\"#008000\"/><stop offset=\"1\" stop-color=\"#000000\"/></linearGradient>`\n + '</defs><rect width=\"100\" height=\"100\" fill=\"url(#x)\"/><rect width=\"100\" height=\"100\" fill=\"url(#y)\" style=\"mix-blend-mode:screen\"/></svg>';\n return `data:image/svg+xml,${encodeURIComponent(svg)}`;\n}\n\n/**\n * El material del contenido sobre un color: esmerilado como el vidrio pero sin el brillo del borde, y más transparente.\n *\n * @param {string} solidColor\n * @param {object} [options]\n * @param {number} [options.opacity] la del vidrio; el material le suma MATERIAL_OPACITY_OFFSET de su modo (le resta)\n * @param {boolean} [options.isDark]\n * @returns {object}\n */\nexport function materialSurfaceOf(solidColor, {opacity = GLASS_OPACITY, isDark = false} = {}) {\n const edge = isDark ? MATERIAL_EDGE_DARK : MATERIAL_EDGE_LIGHT;\n const tint = isDark ? `color-mix(in srgb, ${solidColor}, white ${DARK_GLASS_LIFT_PERCENT}%)` : solidColor;\n const offset = isDark ? MATERIAL_OPACITY_OFFSET.dark : MATERIAL_OPACITY_OFFSET.light;\n const materialOpacity = Math.min(1, Math.max(0, opacity + offset));\n return {\n backgroundColor: `color-mix(in srgb, ${tint} ${Math.round(materialOpacity * 100)}%, transparent)`,\n backdropFilter: GLASS_BLUR,\n WebkitBackdropFilter: GLASS_BLUR,\n backgroundImage: 'none',\n boxShadow: `0 0 0 1px ${edge.outline}, ${edge.shadow}`,\n ...solidFallbackOf({backgroundColor: solidColor, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n\n/**\n * El material del contenido en claro y en oscuro (las tarjetas con glass: {surfaces: true}). Para algo del proyecto que va\n * en el contenido: sx={(theme) => materialStylesOf(theme)}.\n *\n * @param {object} theme\n * @param {object} [options]\n * @param {string} [options.color] por omisión el de las tarjetas (background.paper)\n * @param {string} [options.darkColor] por omisión el mismo\n * @returns {object}\n */\nexport function materialStylesOf(theme, {color, darkColor} = {}) {\n const lightColor = color ?? paletteOf(theme).background.paper;\n const opacity = glassOpacityOf(theme);\n return lightDarkStylesOf(theme, materialSurfaceOf(lightColor, {opacity}), materialSurfaceOf(darkColor ?? lightColor, {opacity, isDark: true}));\n}\n\n/**\n * Solo el fondo del material, sin su línea ni su sombra: para lo que va DENTRO de una tarjeta y debe tapar lo que pasa por\n * debajo sin verse como un parche sólido (la columna pegada de la tabla al deslizarla de lado). Va como capa\n * (background-image) y no como color: así el color propio del elemento (el del renglón: la cebra, el cursor encima) se\n * sigue pintando encima.\n *\n * Con {thick: true}, el material «grueso» de Apple (HIG «Materials»: los gruesos son para leer sobre otro contenido): el\n * mismo desenfoque al 92 %. Es el de la columna fija de una tabla: con el delgado de la tarjeta (45 a 55 %) se veían pasar\n * por detrás las otras columnas (lo reportaron).\n *\n * @param {object} theme\n * @param {object} [options]\n * @param {boolean} [options.thick] el material grueso, para tapar lo que pasa por debajo\n * @returns {object}\n */\nexport function materialBackgroundOf(theme, {thick = false} = {}) {\n const paper = paletteOf(theme).background.paper;\n const opacityOf = (offset) => (thick ? THICK_MATERIAL_PERCENT : Math.round(Math.min(1, Math.max(0, glassOpacityOf(theme) + offset)) * 100));\n const layerOf = (color) => `linear-gradient(${color}, ${color})`;\n const frostedOf = (tint, opacity) => ({\n backgroundImage: layerOf(`color-mix(in srgb, ${tint} ${opacity}%, transparent)`),\n backdropFilter: GLASS_BLUR,\n WebkitBackdropFilter: GLASS_BLUR,\n });\n return {\n ...lightDarkStylesOf(theme,\n frostedOf(paper, opacityOf(MATERIAL_OPACITY_OFFSET.light)),\n frostedOf(`color-mix(in srgb, ${paper}, white ${DARK_GLASS_LIFT_PERCENT}%)`, opacityOf(MATERIAL_OPACITY_OFFSET.dark))),\n ...solidFallbackOf({backgroundImage: layerOf(paper), backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n\n/**\n * La «gota» que marca lo elegido dentro de un control (la pestaña, la opción, el renglón del menú lateral): en claro, una\n * pastilla blanca con su brillo y su sombra; en oscuro, un relleno gris parejo, como el renglón elegido de las barras\n * laterales de Apple en oscuro. No es transparente del todo: va DENTRO de algo que ya puede ser de vidrio (un menú), y\n * vidrio sobre vidrio no se lee.\n * OJO, oscuro: con blanco al 14 % casi no se veía, y su línea de luz arriba dibujaba un arco raro en la esquina («no se\n * nota la selección», «se ve raro»; lo reportaron). Va al 18 % y sin línea.\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function glassDropOf(theme) {\n const palette = paletteOf(theme);\n return lightDarkStylesOf(theme, {\n backgroundColor: palette.background.paper,\n color: palette.text.primary,\n boxShadow: 'inset 0 1px 0 rgba(255, 255, 255, 0.6), 0 1px 3px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.08)',\n }, {\n backgroundColor: `color-mix(in srgb, ${palette.common.white} ${DARK_DROP_WHITE_PERCENT}%, transparent)`,\n boxShadow: '0 1px 3px rgba(0, 0, 0, 0.35)',\n });\n}\n\n/**\n * El relleno de un control lleno de color (el botón principal, la etiqueta elegida) para llevar letra BLANCA y que se lea:\n * el color del tema oscurecido lo justo para llegar a 4.5 : 1 (WCAG). En oscuro la paleta trae letra negra sobre el\n * naranja («El suyo», «Guardar»: se veía feo, lo reportaron) y el blanco sobre el naranja tal cual da 2.85 : 1; con el\n * naranja al 75 % y blanco da 4.79 : 1. Se calcula con el color que elija el proyecto, no con uno fijo.\n *\n * @param {string} rawColor el color en #RRGGBB o #RGB (el de la paleta, no la variable CSS)\n * @returns {string|null} el relleno en #RRGGBB; null si el color no viene en hexadecimal\n */\nexport function whiteLabelFillOf(rawColor) {\n const channels = hexChannelsOf(rawColor);\n if (!channels) {\n return null;\n }\n // del color tal cual hacia el negro, en pasos de 5 %, hasta que la letra blanca se lea\n for (let share = 100; share >= MIN_FILL_SHARE_PERCENT; share -= FILL_SHARE_STEP_PERCENT) {\n const mixed = channels.map((channel) => Math.round((channel * share) / 100));\n if (contrastWithWhiteOf(mixed) >= MIN_TEXT_CONTRAST) {\n return `#${mixed.map((channel) => channel.toString(16).padStart(2, '0')).join('')}`;\n }\n }\n return `#${channels.map((channel) => Math.round((channel * MIN_FILL_SHARE_PERCENT) / 100).toString(16).padStart(2, '0')).join('')}`;\n}\n\n/**\n * Los tres canales de un color #RRGGBB o #RGB (0 a 255); null si no es hexadecimal.\n *\n * @param {string} color\n * @returns {number[]|null}\n */\nfunction hexChannelsOf(color) {\n const match = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(String(color ?? '').trim());\n if (!match) {\n return null;\n }\n const digits = match[1].length === 3 ? [...match[1]].map((digit) => digit + digit).join('') : match[1];\n return [0, 2, 4].map((start) => parseInt(digits.slice(start, start + 2), 16));\n}\n\n/**\n * El contraste de la letra blanca sobre un color (fórmula de WCAG).\n *\n * @param {number[]} channels\n * @returns {number}\n */\nfunction contrastWithWhiteOf(channels) {\n const [red, green, blue] = channels.map((channel) => {\n const unit = channel / 255;\n return unit <= 0.03928 ? unit / 12.92 : ((unit + 0.055) / 1.055) ** 2.4;\n });\n const luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue;\n return 1.05 / (luminance + 0.05);\n}\n\n/**\n * Los tonos de los campos por omisión, por modo: fill (el relleno), hoverFill (con el cursor encima), border y hoverBorder\n * (la orilla; transparente: el pozo de Apple no lleva). createToolkitTheme los pone en la paleta de cada modo\n * (palette.field) y el proyecto los cambia con `fields` o con su paleta: blancos con borde, del tono de su marca…\n */\nexport const FIELD_TONES = Object.freeze({\n light: Object.freeze({fill: FIELD_WELL_FILL.light.rest, hoverFill: FIELD_WELL_FILL.light.hover, border: 'transparent', hoverBorder: 'transparent'}),\n dark: Object.freeze({fill: FIELD_WELL_FILL.dark.rest, hoverFill: FIELD_WELL_FILL.dark.hover, border: 'transparent', hoverBorder: 'transparent'}),\n});\n\n/**\n * Los tonos de los campos del tema (palette.field, que llena createToolkitTheme; con sus variables CSS cambian solos con el\n * modo, sin reglas de oscuro), o null si el tema no los trae (un createTheme de MUI sin Calcita).\n *\n * @param {object} theme\n * @returns {{fill: string, hoverFill: string, border: string, hoverBorder: string}|null}\n */\nexport function fieldPaletteOf(theme) {\n return paletteOf(theme).field ?? null;\n}\n\n/** La orilla de un campo: una línea por dentro (sombra inset), que no mueve el texto ni pelea con el aro del foco (outline). */\nfunction fieldEdgeOf(color) {\n return `inset 0 0 0 1px ${color}`;\n}\n\n/** Las esquinas de los campos: las que pidió el proyecto (createToolkitTheme fields.radius) o las de cada estilo. */\nfunction fieldRadiusOf(theme, lookRadius) {\n return theme.toolkit?.fields?.radius ?? lookRadius;\n}\n\n/**\n * El «pozo» de un campo de texto dentro del contenido (una tarjeta, un formulario agrupado), como los de Apple: un relleno\n * parejo con esquinas de 12 px, del gris de relleno de Apple («tertiary fill»): tenue en claro y más claro que la tarjeta en\n * oscuro (con negro, en oscuro se perdía). Sin vidrio adentro de la tarjeta: ahí no tiene nada que dejar\n * ver. Con el cursor encima se marca apenas; antes el relleno salía solo con el cursor y en cuadro («hovers espantosos»).\n * Los tonos y las esquinas los puede cambiar el proyecto (createToolkitTheme fields).\n *\n * @param {object} theme\n * @param {{radius?: number}} [options] las esquinas del estilo que lo pide (el minimalista las tiene más chicas)\n * @returns {object}\n */\nexport function fieldWellStylesOf(theme, {radius = FIELD_WELL_RADIUS_PIXELS} = {}) {\n const base = {backgroundImage: 'none', backdropFilter: 'none', WebkitBackdropFilter: 'none', borderRadius: fieldRadiusOf(theme, radius)};\n const field = fieldPaletteOf(theme);\n if (field) {\n return {\n ...base,\n backgroundColor: field.fill,\n boxShadow: fieldEdgeOf(field.border),\n '&:hover': {backgroundColor: field.hoverFill, boxShadow: fieldEdgeOf(field.hoverBorder)},\n };\n }\n const {light, dark} = FIELD_TONES;\n return {\n ...base,\n ...lightDarkStylesOf(theme,\n {backgroundColor: light.fill, boxShadow: fieldEdgeOf(light.border), '&:hover': {backgroundColor: light.hoverFill, boxShadow: fieldEdgeOf(light.hoverBorder)}},\n {backgroundColor: dark.fill, boxShadow: fieldEdgeOf(dark.border), '&:hover': {backgroundColor: dark.hoverFill, boxShadow: fieldEdgeOf(dark.hoverBorder)}}),\n };\n}\n\n/**\n * Los tonos de los campos como variables (--calcita-field-*) para un contenedor: el renglón de FormSection las pone en sí\n * mismo y sus campos las leen (fieldWellFromVariablesOf). OJO, trampa pagada: el renglón le gana al tema con selectores\n * largos («html body &&& .MuiOutlinedInput-root») y una regla de oscuro anidada ahí abajo nunca aplicaba (en oscuro el\n * campo salía con el gris de claro). En el contenedor la regla de oscuro sí aplica, y los campos heredan la variable.\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function fieldVariablesOf(theme) {\n const variablesOf = (tones) => ({\n '--calcita-field-fill': tones.fill,\n '--calcita-field-hover-fill': tones.hoverFill,\n '--calcita-field-edge': fieldEdgeOf(tones.border),\n '--calcita-field-hover-edge': fieldEdgeOf(tones.hoverBorder),\n });\n const field = fieldPaletteOf(theme);\n if (field) {\n return variablesOf(field);\n }\n return {...variablesOf(FIELD_TONES.light), ...theme.applyStyles('dark', variablesOf(FIELD_TONES.dark))};\n}\n\n/**\n * El pozo de un campo leyendo las variables de su contenedor (fieldVariablesOf).\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function fieldWellFromVariablesOf(theme) {\n return {\n backgroundImage: 'none',\n backdropFilter: 'none',\n WebkitBackdropFilter: 'none',\n borderRadius: fieldRadiusOf(theme, FIELD_WELL_RADIUS_PIXELS),\n backgroundColor: 'var(--calcita-field-fill)',\n boxShadow: 'var(--calcita-field-edge)',\n '&:hover': {backgroundColor: 'var(--calcita-field-hover-fill)', boxShadow: 'var(--calcita-field-hover-edge)'},\n };\n}\n\n/**\n * Un campo de texto suelto sobre el lienzo (fuera de una tarjeta): una lámina de vidrio clara en claro y el gris de relleno\n * de Apple en oscuro, más claro que el fondo casi negro. Con «Reducir transparencia» se pinta sólido.\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function canvasFieldStylesOf(theme) {\n const paper = paletteOf(theme).background.paper;\n return {\n backgroundImage: 'none',\n backdropFilter: GLASS_BLUR,\n WebkitBackdropFilter: GLASS_BLUR,\n borderRadius: FIELD_WELL_RADIUS_PIXELS,\n ...lightDarkStylesOf(theme, {\n backgroundColor: CANVAS_FIELD.light.rest,\n boxShadow: `0 0 0 1px ${CANVAS_FIELD.light.edge}`,\n '&:hover': {backgroundColor: CANVAS_FIELD.light.hover},\n }, {\n backgroundColor: CANVAS_FIELD.dark.rest,\n boxShadow: `0 0 0 1px ${CANVAS_FIELD.dark.edge}`,\n '&:hover': {backgroundColor: CANVAS_FIELD.dark.hover},\n }),\n ...solidFallbackOf({backgroundColor: paper, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n\n/**\n * El color de un TEXTO que debe ir del color del tema (una liga, un botón de solo texto, el renglón elegido del menú, el\n * valor de una fecha): el color de la paleta oscurecido en claro y aclarado en oscuro, para que se lea. Medido (WCAG pide\n * 4.5 : 1 en letra normal): el naranja de la marca sobre una tarjeta clara daba 2.78 : 1 y sobre su propio tinte en oscuro\n * 4.41 : 1 (el reporte: «cuesta leer», «se pierde»); con 30 % de negro en claro da 5.24 : 1 y con 30 % de blanco en\n * oscuro 8.23 : 1. Los botones con relleno de color NO usan esto: van con letra de un solo color (HIG «Buttons»: «Avoid\n * applying a similar color to button labels and content layer backgrounds»).\n *\n * @param {object} theme\n * @param {string} [colorName] primary, error, success… (por omisión primary)\n * @returns {object} {color, y el de oscuro}\n */\nexport function accentTextStylesOf(theme, colorName = 'primary') {\n const palette = paletteOf(theme);\n const main = (palette[colorName] ?? palette.primary).main;\n const keep = 100 - ACCENT_TEXT_SHADE_PERCENT;\n return lightDarkStylesOf(theme, {color: `color-mix(in srgb, ${main} ${keep}%, black)`}, {color: `color-mix(in srgb, ${main} ${keep}%, white)`});\n}\n\n/**\n * Un fondo FIJO a la ventana que no se mueve al deslizar, también en el iPhone: va en una capa aparte (::before con\n * position: fixed) detrás del contenido del elemento. Así el vidrio se ve pasar por encima de un fondo quieto.\n *\n * OJO: background-attachment: fixed no sirve para esto. Safari del iPhone y del iPad lo ignora y el fondo se movía con\n * todo (lo vio el autor en el teléfono); además, en escritorio vuelve a pintar todo el fondo en cada paso al deslizar.\n * La capa va con z-index -1 dentro de un contexto propio (isolation): queda arriba del color del elemento y abajo de su\n * contenido. Si el elemento es una caja con esquinas (la escena de un ejemplo), clip-path la recorta a la caja.\n *\n * @param {object} layerStyles el fondo de la capa (backgroundColor, backgroundImage…; puede llevar el modo oscuro)\n * @param {object} [options]\n * @param {string} [options.clipPath] p. ej. 'inset(0 round 20px)' para una caja; sin él, la capa ocupa toda la ventana\n * @returns {object} estilos para el sx del elemento\n */\nexport function fixedBackgroundLayerOf(layerStyles, {clipPath} = {}) {\n return {\n isolation: 'isolate',\n ...(clipPath && {clipPath}),\n // OJO, iPhone: con inset: 0 el alto de la capa cambia cuando la barra de Safari se esconde al deslizar, y el fondo\n // «seguía al scroll» (lo vio el autor en su teléfono). Medida fija de toda la pantalla (100vw × 100lvh, el alto con\n // la barra escondida; 100vh donde no hay lvh) y su propia capa de composición (translateZ), que es lo que la deja\n // quieta en WebKit\n '&::before': {\n content: '\"\"',\n position: 'fixed',\n top: 0,\n left: 0,\n width: '100vw',\n height: '100vh',\n '@supports (height: 100lvh)': {height: '100lvh'},\n transform: 'translateZ(0)',\n willChange: 'transform',\n zIndex: -1,\n pointerEvents: 'none',\n ...layerStyles,\n },\n };\n}\n\n/**\n * El fondo del lienzo con vidrio: manchas del color principal y del de información, fijas a la ventana, para\n * que el vidrio tenga algo que desenfocar. AppLayout ya lo pone; una pantalla fuera del marco (el inicio de sesión) lo usa\n * con sx={(theme) => ambientBackgroundOf(theme)}.\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function ambientBackgroundOf(theme) {\n const palette = paletteOf(theme);\n const washOf = (strength, tones) => [\n `radial-gradient(60vmax 45vmax at 0% 0%, color-mix(in srgb, ${tones.primary} ${strength.primary}%, transparent), transparent 70%)`,\n `radial-gradient(50vmax 40vmax at 100% 15%, color-mix(in srgb, ${tones.info} ${strength.info}%, transparent), transparent 70%)`,\n `radial-gradient(55vmax 45vmax at 70% 100%, color-mix(in srgb, ${tones.accent} ${strength.accent}%, transparent), transparent 70%)`,\n `radial-gradient(45vmax 35vmax at 45% 50%, color-mix(in srgb, ${tones.info} ${strength.center}%, transparent), transparent 70%)`,\n ].join(', ');\n const lightTones = {primary: palette.primary.main, info: palette.info.main, accent: palette.primary.light};\n // en oscuro, los tonos OSCUROS de la paleta sobre un casi negro: el color tiñe sin aclarar el fondo, y las tarjetas y el\n // vidrio (más claros) no se pierden (ver DARK_CANVAS)\n const darkTones = {primary: palette.primary.dark, info: palette.info.dark, accent: palette.primary.dark};\n return {\n ...lightDarkStylesOf(theme, {backgroundColor: palette.background.default}, {backgroundColor: DARK_CANVAS.base}),\n ...fixedBackgroundLayerOf(lightDarkStylesOf(theme,\n {backgroundColor: palette.background.default, backgroundImage: washOf(AMBIENT_STRENGTH_LIGHT, lightTones)},\n {backgroundColor: DARK_CANVAS.base, backgroundImage: washOf(AMBIENT_STRENGTH_DARK, darkTones)})),\n };\n}\n\n// la orilla de arriba con la barra en cápsulas: cuánto tinte del lienzo lleva y cuánto desenfoca (px)\nconst SCROLL_EDGE_TINT_PERCENT = 55;\nconst SCROLL_EDGE_BLUR_PIXELS = 12;\n\n/**\n * La orilla de arriba cuando la barra va en cápsulas (TOP_BAR.capsules con vidrio, como las ventanas de macOS Tahoe; Apple le\n * llama «scroll edge effect»): lo que pasa por debajo se desenfoca y se desvanece hacia el contenido, para que el título\n * y las cápsulas se lean sobre cualquier cosa. Con «Reducir transparencia» o sin backdrop-filter, el color del lienzo.\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function scrollEdgeStylesOf(theme) {\n const palette = paletteOf(theme);\n const tintOf = (canvas) => `color-mix(in srgb, ${canvas} ${SCROLL_EDGE_TINT_PERCENT}%, transparent)`;\n const blur = `blur(${SCROLL_EDGE_BLUR_PIXELS}px)`;\n // de arriba (cubre) hacia abajo (se desvanece): sin raya donde termina\n const fade = 'linear-gradient(to bottom, black 45%, transparent)';\n return {\n ...lightDarkStylesOf(theme, {backgroundColor: tintOf(palette.background.default)}, {backgroundColor: tintOf(DARK_CANVAS.base)}),\n backdropFilter: blur,\n WebkitBackdropFilter: blur,\n maskImage: fade,\n WebkitMaskImage: fade,\n ...solidFallbackOf({backgroundColor: palette.background.default, backdropFilter: 'none', WebkitBackdropFilter: 'none'}),\n };\n}\n"],"names":[],"mappings":";;AAsCY,MAAC,gBAAgB;AAGjB,MAAC,4BAA4B;AAG7B,MAAC,2BAA2B;AAO5B,MAAC,qBAAqB;AAElC,MAAM,aAAa;AAQP,MAAC,aAAa,OAAO,OAAO;AAAA,EACpC,SAAS,EAAC,UAAU,8BAA8B,cAAc,MAAM,OAAO,KAAK,YAAY,GAAG,WAAW,KAAI;AAAA,EAChH,OAAO,EAAC,UAAU,4BAA4B,cAAc,MAAM,OAAO,MAAM,YAAY,IAAI,WAAW,IAAG;AACjH,CAAC;AAGD,MAAM,0BAA0B;AAEhC,MAAM,4BAA4B;AAElC,MAAM,2BAA2B;AACjC,MAAM,kBAAkB,OAAO,OAAO;AAAA,EAClC,OAAO,EAAC,MAAM,6BAA6B,OAAO,4BAA2B;AAAA;AAAA,EAE7E,MAAM,EAAC,MAAM,6BAA6B,OAAO,4BAA2B;AAChF,CAAC;AAED,MAAM,eAAe,OAAO,OAAO;AAAA,EAC/B,OAAO,EAAC,MAAM,6BAA6B,OAAO,6BAA6B,MAAM,yBAAwB;AAAA;AAAA;AAAA,EAG7G,MAAM,EAAC,MAAM,6BAA6B,OAAO,6BAA6B,MAAM,4BAA2B;AACnH,CAAC;AAED,MAAM,oBAAoB;AAC1B,MAAM,0BAA0B;AAChC,MAAM,yBAAyB;AAGnB,MAAC,2BAA2B;AAUjC,SAAS,wBAAwB,SAAS,IAAI;AACjD,SAAO,mBAAmB,MAAM,KAAK,wBAAwB,oBAAoB,MAAM;AAC3F;AACA,MAAM,6BAA6B;AACnC,MAAM,2BAA2B;AAMjC,MAAM,yBAAyB,OAAO,OAAO,EAAC,SAAS,IAAI,MAAM,IAAI,QAAQ,IAAI,QAAQ,GAAE,CAAC;AAI5F,MAAM,wBAAwB,OAAO,OAAO,EAAC,SAAS,IAAI,MAAM,IAAI,QAAQ,IAAI,QAAQ,GAAE,CAAC;AAC3F,MAAM,cAAc,OAAO,OAAO,EAAC,MAAM,UAAS,CAAC;AAOnD,MAAM,mBAAmB,OAAO,OAAO;AAAA,EACnC,UAAU;AAAA,EAA6B,UAAU;AAAA,EAA4B,WAAW;AAAA,EACxF,SAAS;AAAA,EAA0B,QAAQ;AAAA,EAC3C,eAAe;AACnB,CAAC;AACD,MAAM,kBAAkB,OAAO,OAAO;AAAA,EAClC,UAAU;AAAA,EAA6B,UAAU;AAAA,EAA6B,WAAW;AAAA,EACzF,SAAS;AAAA,EAAuB,QAAQ;AAAA,EACxC,eAAe;AACnB,CAAC;AAED,MAAM,oBAAoB;AAM1B,MAAM,0BAA0B;AAIhC,MAAM,sBAAsB,OAAO,OAAO,EAAC,SAAS,0BAA0B,QAAQ,sEAAqE,CAAC;AAC5J,MAAM,qBAAqB,OAAO,OAAO,EAAC,SAAS,6BAA6B,QAAQ,iCAAgC,CAAC;AAKzH,MAAM,0BAA0B,OAAO,OAAO,EAAC,OAAO,OAAO,MAAM,MAAK,CAAC;AAEzE,MAAM,yBAAyB;AASxB,SAAS,aAAa,OAAO;AAChC,SAAO,QAAQ,OAAO,SAAS,KAAK;AACxC;AAQO,SAAS,eAAe,OAAO;AAClC,SAAO,OAAO,SAAS,OAAO,WAAW;AAC7C;AAYO,SAAS,eAAe,YAAY,EAAC,UAAU,eAAe,SAAS,OAAO,YAAY,MAAK,IAAI,IAAI;AAC1G,QAAM,OAAO,SAAS,kBAAkB;AACxC,QAAM,OAAO,SAAS,sBAAsB,UAAU,WAAW,uBAAuB,OAAO;AAC/F,SAAO;AAAA,IACH,iBAAiB,sBAAsB,IAAI,IAAI,KAAK,MAAM,UAAU,GAAG,CAAC;AAAA,IACxE,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,iBAAiB;AAAA,IACjB,WAAW;AAAA,MACP,mBAAmB,KAAK,QAAQ;AAAA,MAChC,qBAAqB,KAAK,QAAQ;AAAA,MAClC,aAAa,iBAAiB,MAAM,KAAK,SAAS;AAAA,MAClD,aAAa,KAAK,OAAO;AAAA,MACzB,YAAY,KAAK,gBAAgB,KAAK;AAAA,IAClD,EAAU,KAAK,IAAI;AAAA,IACX,GAAG,gBAAgB,EAAC,iBAAiB,YAAY,gBAAgB,QAAQ,sBAAsB,OAAM,CAAC;AAAA,EAC9G;AACA;AAUO,SAAS,gBAAgB,YAAY;AACxC,SAAO,EAAC,CAAC,0BAA0B,GAAG,YAAY,CAAC,wBAAwB,GAAG,WAAU;AAC5F;AAgBO,SAAS,cAAc,OAAO,EAAC,OAAO,WAAW,SAAS,YAAY,MAAK,IAAI,IAAI;AACtF,QAAM,aAAa,SAAS,UAAU,KAAK,EAAE,WAAW;AACxD,QAAM,eAAe,WAAW,eAAe,KAAK;AACpD,SAAO;AAAA,IACH,GAAG;AAAA,MAAkB;AAAA,MACjB,eAAe,YAAY,EAAC,SAAS,cAAc,UAAS,CAAC;AAAA,MAC7D,eAAe,aAAa,YAAY,EAAC,SAAS,cAAc,QAAQ,MAAM,UAAS,CAAC;AAAA,IAAC;AAAA,IAC7F,GAAG,YAAY,OAAO,EAAC,YAAY,WAAW,aAAa,YAAY,SAAS,cAAc,UAAS,CAAC;AAAA,EAChH;AACA;AAoBA,SAAS,YAAY,OAAO,EAAC,YAAY,WAAW,SAAS,UAAS,GAAG;AACrE,QAAM,OAAO,YAAY,WAAW,UAAU,WAAW;AACzD,QAAM,cAAc,KAAK,IAAI,GAAG,UAAU,KAAK,SAAS;AACxD,QAAM,WAAW,QAAQ,KAAK,UAAU,2BAA2B,KAAK,QAAQ;AAChF,QAAM,gBAAgB,CAAC,YAAY,WAAW;AAC1C,UAAM,OAAO,SAAS,sBAAsB,UAAU,WAAW,uBAAuB,OAAO;AAC/F,WAAO;AAAA,MACH,iBAAiB,sBAAsB,IAAI,IAAI,KAAK,MAAM,cAAc,GAAG,CAAC;AAAA,MAC5E,gBAAgB;AAAA,MAChB,sBAAsB;AAAA,MACtB,GAAG,gBAAgB,EAAC,iBAAiB,YAAY,gBAAgB,QAAQ,sBAAsB,OAAM,CAAC;AAAA,IAClH;AAAA,EACI;AACA,QAAM,UAAU,GAAG,wBAAwB;AAE3C,QAAM,UAAU,OAAO,KAAK,MAAM,YAAY,QAAQ,CAAA,CAAE,CAAC,EAAE,CAAC;AAC5D,MAAI,CAAC,SAAS;AACV,WAAO,EAAC,CAAC,OAAO,GAAG,cAAc,YAAY,KAAK,EAAC;AAAA,EACvD;AACA,QAAM,WAAW,QAAQ,WAAW,GAAG,IACjC,EAAC,CAAC,OAAO,GAAG,EAAC,CAAC,OAAO,GAAG,cAAc,WAAW,IAAI,EAAC,EAAC,IACvD,EAAC,CAAC,QAAQ,QAAQ,KAAK,OAAO,CAAC,GAAG,cAAc,WAAW,IAAI,EAAC;AACtE,SAAO,EAAC,CAAC,OAAO,GAAG,cAAc,YAAY,KAAK,GAAG,GAAG,SAAQ;AACpE;AAWO,SAAS,sBAAsB,cAAc;AAChD,QAAM,QAAQ,IAAI;AAClB,QAAM,MAAM,+LACuF,YAAY,yCACxF,KAAK,2LACqF,YAAY,yCACtG,KAAK;AAE5B,SAAO,sBAAsB,mBAAmB,GAAG,CAAC;AACxD;AAWO,SAAS,kBAAkB,YAAY,EAAC,UAAU,eAAe,SAAS,MAAK,IAAI,IAAI;AAC1F,QAAM,OAAO,SAAS,qBAAqB;AAC3C,QAAM,OAAO,SAAS,sBAAsB,UAAU,WAAW,uBAAuB,OAAO;AAC/F,QAAM,SAAS,SAAS,wBAAwB,OAAO,wBAAwB;AAC/E,QAAM,kBAAkB,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,UAAU,MAAM,CAAC;AACjE,SAAO;AAAA,IACH,iBAAiB,sBAAsB,IAAI,IAAI,KAAK,MAAM,kBAAkB,GAAG,CAAC;AAAA,IAChF,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,iBAAiB;AAAA,IACjB,WAAW,aAAa,KAAK,OAAO,KAAK,KAAK,MAAM;AAAA,IACpD,GAAG,gBAAgB,EAAC,iBAAiB,YAAY,gBAAgB,QAAQ,sBAAsB,OAAM,CAAC;AAAA,EAC9G;AACA;AAYO,SAAS,iBAAiB,OAAO,EAAC,OAAO,UAAS,IAAI,CAAA,GAAI;AAC7D,QAAM,aAAa,SAAS,UAAU,KAAK,EAAE,WAAW;AACxD,QAAM,UAAU,eAAe,KAAK;AACpC,SAAO,kBAAkB,OAAO,kBAAkB,YAAY,EAAC,QAAO,CAAC,GAAG,kBAAkB,aAAa,YAAY,EAAC,SAAS,QAAQ,KAAI,CAAC,CAAC;AACjJ;AAiBO,SAAS,qBAAqB,OAAO,EAAC,QAAQ,MAAK,IAAI,CAAA,GAAI;AAC9D,QAAM,QAAQ,UAAU,KAAK,EAAE,WAAW;AAC1C,QAAM,YAAY,CAAC,WAAY,QAAQ,yBAAyB,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,eAAe,KAAK,IAAI,MAAM,CAAC,IAAI,GAAG;AACzI,QAAM,UAAU,CAAC,UAAU,mBAAmB,KAAK,KAAK,KAAK;AAC7D,QAAM,YAAY,CAAC,MAAM,aAAa;AAAA,IAClC,iBAAiB,QAAQ,sBAAsB,IAAI,IAAI,OAAO,iBAAiB;AAAA,IAC/E,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,EAC9B;AACI,SAAO;AAAA,IACH,GAAG;AAAA,MAAkB;AAAA,MACjB,UAAU,OAAO,UAAU,wBAAwB,KAAK,CAAC;AAAA,MACzD,UAAU,sBAAsB,KAAK,WAAW,uBAAuB,MAAM,UAAU,wBAAwB,IAAI,CAAC;AAAA,IAAC;AAAA,IACzH,GAAG,gBAAgB,EAAC,iBAAiB,QAAQ,KAAK,GAAG,gBAAgB,QAAQ,sBAAsB,OAAM,CAAC;AAAA,EAClH;AACA;AAaO,SAAS,YAAY,OAAO;AAC/B,QAAM,UAAU,UAAU,KAAK;AAC/B,SAAO,kBAAkB,OAAO;AAAA,IAC5B,iBAAiB,QAAQ,WAAW;AAAA,IACpC,OAAO,QAAQ,KAAK;AAAA,IACpB,WAAW;AAAA,EACnB,GAAO;AAAA,IACC,iBAAiB,sBAAsB,QAAQ,OAAO,KAAK,IAAI,uBAAuB;AAAA,IACtF,WAAW;AAAA,EACnB,CAAK;AACL;AAWO,SAAS,iBAAiB,UAAU;AACvC,QAAM,WAAW,cAAc,QAAQ;AACvC,MAAI,CAAC,UAAU;AACX,WAAO;AAAA,EACX;AAEA,WAAS,QAAQ,KAAK,SAAS,wBAAwB,SAAS,yBAAyB;AACrF,UAAM,QAAQ,SAAS,IAAI,CAAC,YAAY,KAAK,MAAO,UAAU,QAAS,GAAG,CAAC;AAC3E,QAAI,oBAAoB,KAAK,KAAK,mBAAmB;AACjD,aAAO,IAAI,MAAM,IAAI,CAAC,YAAY,QAAQ,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;AAAA,IACrF;AAAA,EACJ;AACA,SAAO,IAAI,SAAS,IAAI,CAAC,YAAY,KAAK,MAAO,UAAU,yBAA0B,GAAG,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;AACrI;AAQA,SAAS,cAAc,OAAO;AAC1B,QAAM,QAAQ,gCAAgC,KAAK,OAAO,SAAS,EAAE,EAAE,MAAM;AAC7E,MAAI,CAAC,OAAO;AACR,WAAO;AAAA,EACX;AACA,QAAM,SAAS,MAAM,CAAC,EAAE,WAAW,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,QAAQ,KAAK,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC;AACrG,SAAO,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,UAAU,SAAS,OAAO,MAAM,OAAO,QAAQ,CAAC,GAAG,EAAE,CAAC;AAChF;AAQA,SAAS,oBAAoB,UAAU;AACnC,QAAM,CAAC,KAAK,OAAO,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY;AACjD,UAAM,OAAO,UAAU;AACvB,WAAO,QAAQ,UAAU,OAAO,UAAU,OAAO,SAAS,UAAU;AAAA,EACxE,CAAC;AACD,QAAM,YAAY,SAAS,MAAM,SAAS,QAAQ,SAAS;AAC3D,SAAO,QAAQ,YAAY;AAC/B;AAOY,MAAC,cAAc,OAAO,OAAO;AAAA,EACrC,OAAO,OAAO,OAAO,EAAC,MAAM,gBAAgB,MAAM,MAAM,WAAW,gBAAgB,MAAM,OAAO,QAAQ,eAAe,aAAa,cAAa,CAAC;AAAA,EAClJ,MAAM,OAAO,OAAO,EAAC,MAAM,gBAAgB,KAAK,MAAM,WAAW,gBAAgB,KAAK,OAAO,QAAQ,eAAe,aAAa,cAAa,CAAC;AACnJ,CAAC;AASM,SAAS,eAAe,OAAO;AAClC,SAAO,UAAU,KAAK,EAAE,SAAS;AACrC;AAGA,SAAS,YAAY,OAAO;AACxB,SAAO,mBAAmB,KAAK;AACnC;AAGA,SAAS,cAAc,OAAO,YAAY;AACtC,SAAO,MAAM,SAAS,QAAQ,UAAU;AAC5C;AAaO,SAAS,kBAAkB,OAAO,EAAC,SAAS,yBAAwB,IAAI,CAAA,GAAI;AAC/E,QAAM,OAAO,EAAC,iBAAiB,QAAQ,gBAAgB,QAAQ,sBAAsB,QAAQ,cAAc,cAAc,OAAO,MAAM,EAAC;AACvI,QAAM,QAAQ,eAAe,KAAK;AAClC,MAAI,OAAO;AACP,WAAO;AAAA,MACH,GAAG;AAAA,MACH,iBAAiB,MAAM;AAAA,MACvB,WAAW,YAAY,MAAM,MAAM;AAAA,MACnC,WAAW,EAAC,iBAAiB,MAAM,WAAW,WAAW,YAAY,MAAM,WAAW,EAAC;AAAA,IACnG;AAAA,EACI;AACA,QAAM,EAAC,OAAO,KAAI,IAAI;AACtB,SAAO;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,MAAkB;AAAA,MACjB,EAAC,iBAAiB,MAAM,MAAM,WAAW,YAAY,MAAM,MAAM,GAAG,WAAW,EAAC,iBAAiB,MAAM,WAAW,WAAW,YAAY,MAAM,WAAW,EAAC,EAAC;AAAA,MAC5J,EAAC,iBAAiB,KAAK,MAAM,WAAW,YAAY,KAAK,MAAM,GAAG,WAAW,EAAC,iBAAiB,KAAK,WAAW,WAAW,YAAY,KAAK,WAAW,EAAC,EAAC;AAAA,IAAC;AAAA,EACrK;AACA;AAWO,SAAS,iBAAiB,OAAO;AACpC,QAAM,cAAc,CAAC,WAAW;AAAA,IAC5B,wBAAwB,MAAM;AAAA,IAC9B,8BAA8B,MAAM;AAAA,IACpC,wBAAwB,YAAY,MAAM,MAAM;AAAA,IAChD,8BAA8B,YAAY,MAAM,WAAW;AAAA,EACnE;AACI,QAAM,QAAQ,eAAe,KAAK;AAClC,MAAI,OAAO;AACP,WAAO,YAAY,KAAK;AAAA,EAC5B;AACA,SAAO,EAAC,GAAG,YAAY,YAAY,KAAK,GAAG,GAAG,MAAM,YAAY,QAAQ,YAAY,YAAY,IAAI,CAAC,EAAC;AAC1G;AAQO,SAAS,yBAAyB,OAAO;AAC5C,SAAO;AAAA,IACH,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,cAAc,cAAc,OAAO,wBAAwB;AAAA,IAC3D,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,WAAW,EAAC,iBAAiB,mCAAmC,WAAW,kCAAiC;AAAA,EACpH;AACA;AASO,SAAS,oBAAoB,OAAO;AACvC,QAAM,QAAQ,UAAU,KAAK,EAAE,WAAW;AAC1C,SAAO;AAAA,IACH,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,cAAc;AAAA,IACd,GAAG,kBAAkB,OAAO;AAAA,MACxB,iBAAiB,aAAa,MAAM;AAAA,MACpC,WAAW,aAAa,aAAa,MAAM,IAAI;AAAA,MAC/C,WAAW,EAAC,iBAAiB,aAAa,MAAM,MAAK;AAAA,IACjE,GAAW;AAAA,MACC,iBAAiB,aAAa,KAAK;AAAA,MACnC,WAAW,aAAa,aAAa,KAAK,IAAI;AAAA,MAC9C,WAAW,EAAC,iBAAiB,aAAa,KAAK,MAAK;AAAA,IAChE,CAAS;AAAA,IACD,GAAG,gBAAgB,EAAC,iBAAiB,OAAO,gBAAgB,QAAQ,sBAAsB,OAAM,CAAC;AAAA,EACzG;AACA;AAcO,SAAS,mBAAmB,OAAO,YAAY,WAAW;AAC7D,QAAM,UAAU,UAAU,KAAK;AAC/B,QAAM,QAAQ,QAAQ,SAAS,KAAK,QAAQ,SAAS;AACrD,QAAM,OAAO,MAAM;AACnB,SAAO,kBAAkB,OAAO,EAAC,OAAO,sBAAsB,IAAI,IAAI,IAAI,YAAW,GAAG,EAAC,OAAO,sBAAsB,IAAI,IAAI,IAAI,YAAW,CAAC;AAClJ;AAgBO,SAAS,uBAAuB,aAAa,EAAC,SAAQ,IAAI,CAAA,GAAI;AACjE,SAAO;AAAA,IACH,WAAW;AAAA,IACX,GAAI,YAAY,EAAC,SAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,IAKzB,aAAa;AAAA,MACT,SAAS;AAAA,MACT,UAAU;AAAA,MACV,KAAK;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,8BAA8B,EAAC,QAAQ,SAAQ;AAAA,MAC/C,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,GAAG;AAAA,IACf;AAAA,EACA;AACA;AAUO,SAAS,oBAAoB,OAAO;AACvC,QAAM,UAAU,UAAU,KAAK;AAC/B,QAAM,SAAS,CAAC,UAAU,UAAU;AAAA,IAChC,8DAA8D,MAAM,OAAO,IAAI,SAAS,OAAO;AAAA,IAC/F,iEAAiE,MAAM,IAAI,IAAI,SAAS,IAAI;AAAA,IAC5F,iEAAiE,MAAM,MAAM,IAAI,SAAS,MAAM;AAAA,IAChG,gEAAgE,MAAM,IAAI,IAAI,SAAS,MAAM;AAAA,EACrG,EAAM,KAAK,IAAI;AACX,QAAM,aAAa,EAAC,SAAS,QAAQ,QAAQ,MAAM,MAAM,QAAQ,KAAK,MAAM,QAAQ,QAAQ,QAAQ,MAAK;AAGzG,QAAM,YAAY,EAAC,SAAS,QAAQ,QAAQ,MAAM,MAAM,QAAQ,KAAK,MAAM,QAAQ,QAAQ,QAAQ,KAAI;AACvG,SAAO;AAAA,IACH,GAAG,kBAAkB,OAAO,EAAC,iBAAiB,QAAQ,WAAW,QAAO,GAAG,EAAC,iBAAiB,YAAY,KAAI,CAAC;AAAA,IAC9G,GAAG,uBAAuB;AAAA,MAAkB;AAAA,MACxC,EAAC,iBAAiB,QAAQ,WAAW,SAAS,iBAAiB,OAAO,wBAAwB,UAAU,EAAC;AAAA,MACzG,EAAC,iBAAiB,YAAY,MAAM,iBAAiB,OAAO,uBAAuB,SAAS,EAAC;AAAA,IAAC,CAAC;AAAA,EAC3G;AACA;AAGA,MAAM,2BAA2B;AACjC,MAAM,0BAA0B;AAUzB,SAAS,mBAAmB,OAAO;AACtC,QAAM,UAAU,UAAU,KAAK;AAC/B,QAAM,SAAS,CAAC,WAAW,sBAAsB,MAAM,IAAI,wBAAwB;AACnF,QAAM,OAAO,QAAQ,uBAAuB;AAE5C,QAAM,OAAO;AACb,SAAO;AAAA,IACH,GAAG,kBAAkB,OAAO,EAAC,iBAAiB,OAAO,QAAQ,WAAW,OAAO,EAAC,GAAG,EAAC,iBAAiB,OAAO,YAAY,IAAI,EAAC,CAAC;AAAA,IAC9H,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,WAAW;AAAA,IACX,iBAAiB;AAAA,IACjB,GAAG,gBAAgB,EAAC,iBAAiB,QAAQ,WAAW,SAAS,gBAAgB,QAAQ,sBAAsB,OAAM,CAAC;AAAA,EAC9H;AACA;"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export { MINIMAL_BACKGROUND, MINIMAL_TONES } from './theme/components/minimalCom
|
|
|
15
15
|
export { STACKCRAFT, stackcraftDarkPalette, stackcraftLightPalette } from './theme/stackcraftPalette.js';
|
|
16
16
|
export { toolkitComponents } from './theme/toolkitComponents.js';
|
|
17
17
|
export { mergeComponents } from './theme/mergeComponents.js';
|
|
18
|
-
export { GLASS_INSET_PIXELS, GLASS_MENU_RADIUS_PIXELS, GLASS_OPACITY, GLASS_PANEL_RADIUS_PIXELS, ambientBackgroundOf, glassDropOf, glassStylesOf, glassSurfaceOf, accentTextStylesOf, canvasFieldStylesOf, fieldWellStylesOf, fixedBackgroundLayerOf, isGlassTheme, materialBackgroundOf, materialStylesOf, materialSurfaceOf, scrollEdgeStylesOf, } from './theme/glassSurface.js';
|
|
18
|
+
export { GLASS_INSET_PIXELS, GLASS_MENU_RADIUS_PIXELS, GLASS_OPACITY, GLASS_PANEL_RADIUS_PIXELS, ambientBackgroundOf, glassDropOf, glassStylesOf, glassSurfaceOf, FIELD_TONES, accentTextStylesOf, canvasFieldStylesOf, fieldPaletteOf, fieldWellStylesOf, fixedBackgroundLayerOf, isGlassTheme, materialBackgroundOf, materialStylesOf, materialSurfaceOf, scrollEdgeStylesOf, } from './theme/glassSurface.js';
|
|
19
19
|
export { AppLayout, MENU_POSITION } from './appShell/AppLayout.js';
|
|
20
20
|
export { AuthLayout } from './appShell/AuthLayout.js';
|
|
21
21
|
export { default as BarActions } from './appShell/BarActions.js';
|
|
@@ -32,11 +32,17 @@ export declare const TOP_BAR: Readonly<{
|
|
|
32
32
|
* teléfono y lo que flota). Lo que no se pase se queda con los grises de Apple (MINIMAL_TONES). OJO: con el minimalista
|
|
33
33
|
* el fondo de la página sale de aquí y no de la paleta (sin minimalTones, los grises de Apple aunque la paleta traiga
|
|
34
34
|
* su background)
|
|
35
|
+
* @param {{radius?: number, light?: {fill?: string, hoverFill?: string, border?: string, hoverBorder?: string}, dark?: {fill?: string, hoverFill?: string, border?: string, hoverBorder?: string}}} [options.fields]
|
|
36
|
+
* cómo se ven los campos de captura (con vidrio, con el minimalista y dentro de FormSection), por modo: fill (el
|
|
37
|
+
* relleno), hoverFill (con el cursor encima), border y hoverBorder (la orilla); y radius (las esquinas, en px). Lo que no
|
|
38
|
+
* se pase se queda como el estilo lo trae (FIELD_TONES: el gris de Apple; con el minimalista, su relleno). Van en la
|
|
39
|
+
* paleta de cada modo (palette.field), así que también se pueden escribir en colorSchemes y cambian solos con el modo.
|
|
40
|
+
* Ejemplo, campos blancos con borde en claro: {light: {fill: '#FFFFFF', hoverFill: '#FFFFFF', border: '#C4CDD5'}}
|
|
35
41
|
* @param {object} [options.components] ajustes propios de componentes (se suman; en el mismo estilo ganan los del proyecto)
|
|
36
42
|
* @param {object} [options.overrides] cualquier otra cosa de createTheme (breakpoints, spacing…)
|
|
37
43
|
* @returns {object} el tema de MUI
|
|
38
44
|
*/
|
|
39
|
-
export declare function createToolkitTheme({ colorSchemes, colorSchemeSelector, fontFamily, glass, look, bar, minimalTones, components, overrides, }?: {
|
|
45
|
+
export declare function createToolkitTheme({ colorSchemes, colorSchemeSelector, fontFamily, glass, look, bar, minimalTones, fields, components, overrides, }?: {
|
|
40
46
|
colorSchemes?: {
|
|
41
47
|
light?: object | boolean;
|
|
42
48
|
dark?: object | boolean;
|
|
@@ -63,6 +69,21 @@ export declare function createToolkitTheme({ colorSchemes, colorSchemeSelector,
|
|
|
63
69
|
floating?: string;
|
|
64
70
|
};
|
|
65
71
|
};
|
|
72
|
+
fields?: {
|
|
73
|
+
radius?: number;
|
|
74
|
+
light?: {
|
|
75
|
+
fill?: string;
|
|
76
|
+
hoverFill?: string;
|
|
77
|
+
border?: string;
|
|
78
|
+
hoverBorder?: string;
|
|
79
|
+
};
|
|
80
|
+
dark?: {
|
|
81
|
+
fill?: string;
|
|
82
|
+
hoverFill?: string;
|
|
83
|
+
border?: string;
|
|
84
|
+
hoverBorder?: string;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
66
87
|
components?: object;
|
|
67
88
|
overrides?: object;
|
|
68
89
|
}): object;
|
|
@@ -179,16 +179,69 @@ export declare function glassDropOf(theme: object): object;
|
|
|
179
179
|
* @returns {string|null} el relleno en #RRGGBB; null si el color no viene en hexadecimal
|
|
180
180
|
*/
|
|
181
181
|
export declare function whiteLabelFillOf(rawColor: string): string | null;
|
|
182
|
+
/**
|
|
183
|
+
* Los tonos de los campos por omisión, por modo: fill (el relleno), hoverFill (con el cursor encima), border y hoverBorder
|
|
184
|
+
* (la orilla; transparente: el pozo de Apple no lleva). createToolkitTheme los pone en la paleta de cada modo
|
|
185
|
+
* (palette.field) y el proyecto los cambia con `fields` o con su paleta: blancos con borde, del tono de su marca…
|
|
186
|
+
*/
|
|
187
|
+
export declare const FIELD_TONES: Readonly<{
|
|
188
|
+
light: Readonly<{
|
|
189
|
+
fill: string;
|
|
190
|
+
hoverFill: string;
|
|
191
|
+
border: "transparent";
|
|
192
|
+
hoverBorder: "transparent";
|
|
193
|
+
}>;
|
|
194
|
+
dark: Readonly<{
|
|
195
|
+
fill: string;
|
|
196
|
+
hoverFill: string;
|
|
197
|
+
border: "transparent";
|
|
198
|
+
hoverBorder: "transparent";
|
|
199
|
+
}>;
|
|
200
|
+
}>;
|
|
201
|
+
/**
|
|
202
|
+
* Los tonos de los campos del tema (palette.field, que llena createToolkitTheme; con sus variables CSS cambian solos con el
|
|
203
|
+
* modo, sin reglas de oscuro), o null si el tema no los trae (un createTheme de MUI sin Calcita).
|
|
204
|
+
*
|
|
205
|
+
* @param {object} theme
|
|
206
|
+
* @returns {{fill: string, hoverFill: string, border: string, hoverBorder: string}|null}
|
|
207
|
+
*/
|
|
208
|
+
export declare function fieldPaletteOf(theme: object): {
|
|
209
|
+
fill: string;
|
|
210
|
+
hoverFill: string;
|
|
211
|
+
border: string;
|
|
212
|
+
hoverBorder: string;
|
|
213
|
+
} | null;
|
|
182
214
|
/**
|
|
183
215
|
* El «pozo» de un campo de texto dentro del contenido (una tarjeta, un formulario agrupado), como los de Apple: un relleno
|
|
184
216
|
* parejo con esquinas de 12 px, del gris de relleno de Apple («tertiary fill»): tenue en claro y más claro que la tarjeta en
|
|
185
217
|
* oscuro (con negro, en oscuro se perdía). Sin vidrio adentro de la tarjeta: ahí no tiene nada que dejar
|
|
186
218
|
* ver. Con el cursor encima se marca apenas; antes el relleno salía solo con el cursor y en cuadro («hovers espantosos»).
|
|
219
|
+
* Los tonos y las esquinas los puede cambiar el proyecto (createToolkitTheme fields).
|
|
220
|
+
*
|
|
221
|
+
* @param {object} theme
|
|
222
|
+
* @param {{radius?: number}} [options] las esquinas del estilo que lo pide (el minimalista las tiene más chicas)
|
|
223
|
+
* @returns {object}
|
|
224
|
+
*/
|
|
225
|
+
export declare function fieldWellStylesOf(theme: object, { radius }?: {
|
|
226
|
+
radius?: number;
|
|
227
|
+
}): object;
|
|
228
|
+
/**
|
|
229
|
+
* Los tonos de los campos como variables (--calcita-field-*) para un contenedor: el renglón de FormSection las pone en sí
|
|
230
|
+
* mismo y sus campos las leen (fieldWellFromVariablesOf). OJO, trampa pagada: el renglón le gana al tema con selectores
|
|
231
|
+
* largos («html body &&& .MuiOutlinedInput-root») y una regla de oscuro anidada ahí abajo nunca aplicaba (en oscuro el
|
|
232
|
+
* campo salía con el gris de claro). En el contenedor la regla de oscuro sí aplica, y los campos heredan la variable.
|
|
233
|
+
*
|
|
234
|
+
* @param {object} theme
|
|
235
|
+
* @returns {object}
|
|
236
|
+
*/
|
|
237
|
+
export declare function fieldVariablesOf(theme: object): object;
|
|
238
|
+
/**
|
|
239
|
+
* El pozo de un campo leyendo las variables de su contenedor (fieldVariablesOf).
|
|
187
240
|
*
|
|
188
241
|
* @param {object} theme
|
|
189
242
|
* @returns {object}
|
|
190
243
|
*/
|
|
191
|
-
export declare function
|
|
244
|
+
export declare function fieldWellFromVariablesOf(theme: object): object;
|
|
192
245
|
/**
|
|
193
246
|
* Un campo de texto suelto sobre el lienzo (fuera de una tarjeta): una lámina de vidrio clara en claro y el gris de relleno
|
|
194
247
|
* de Apple en oscuro, más claro que el fondo casi negro. Con «Reducir transparencia» se pinta sólido.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackcraftmx/calcita",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Componentes y utilidades de React con MUI para arrancar proyectos rápido: tabla de servidor, diálogos, avisos, descargas, formularios, formatos y reportes en Excel.",
|
|
5
5
|
"license": "FSL-1.1-MIT",
|
|
6
6
|
"author": "calcifux",
|