CSS-in-TS
Las funciones del generador de hojas de estilo pueden describir los estilos generados mediante tipos especiales, de modo que al utilizarlas, TypeScript mostrará los selectores CSS disponibles. Esta característica utiliza genéricos de TypeScript, ocultando la implementación de los estilos tras la interfaz externa.
Descripción de los estilos
El primer paso para desarrollar estilos con EffCSS es capturar la funcionalidad proporcionada como un tipo de TypeScript. Desde la versión 4.6.0, no hay límite en los niveles de anidamiento de un objeto, y en cualquier nivel se pueden definir propiedades con un valor de cadena o numérico:
Para todos los niveles, se recomienda utilizar nombres descriptivos escritos en formato lowerCamelCase.
export type TCustomMaker = {
/**
* Width utility
*/
w: 's' | 'm' | 'l';
/**
* Logo
*/
logo: {
/**
* Spin animation
*/
spin: '';
/**
* Logo scale
*/
scale: 1 | 2;
};
/**
* Body
*/
body: {
/**
* Padding size
*/
p: 's' | 'm' | 'l';
};
/**
* Footer
*/
footer: {
/**
* Is footer hidden
*/
hidden: '';
};
/**
* Panel block
*/
panel: {
/**
* Is panel modal
*/
modal: '';
/**
* Max panel width
*/
max: 'vw' | 'parent';
/**
* Close button
*/
closeBtn: Record<string, never>;
}
};Implementación de estilos
El segundo paso para desarrollar estilos con EffCSS consiste en implementar la funcionalidad descrita dentro del marco de la función StyleSheet Maker. Para generar selectores únicos con el prefijo de hoja de estilo en EffCSS, se utiliza la utilidad select. Esta utilidad también verifica la validez de los selectores CSS implementados.
Cada selector se forma conectando, mediante una ruta, la propiedad deseada y añadiendo dos puntos : delante de su valor, si este no es un objeto.
import { TStyleSheetMaker } from 'effcss';
export type TCustomMaker = {...};
const maker: TStyleSheetMaker = ({
select,
}) => {
const selector = select<TCustomMaker>;
return {
[selector('logo')]: {
// ...
},
[selector('logo.scale:1')]: {
// ...
},
[selector('logo.spin:')]: {
// ...
},
[selector('panel.closeBtn')]: {
// ...
}
}
};
export default maker;Desde la versión 4.15.0, el tipo TStyleSheetMaker es genérico, toma el tipo de selectores públicos como parámetro, por lo que no es necesario pasar este parámetro a la utilidad select:
import { TStyleSheetMaker } from 'effcss';
export type TCustomMaker = {...};
const maker: TStyleSheetMaker<TCustomMaker> = ({
select,
}) => {
return {
[select('logo')]: {
// ...
},
[select('logo.scale:1')]: {
// ...
},
[select('logo.spin:')]: {
// ...
},
[select('panel.closeBtn')]: {
// ...
}
}
};
export default maker;Uso de estilos
Para obtener el resolvedor de selectores, debe pasar la función StyleSheet maker correspondiente al método use del objeto Style provider. El resolvedor tiene dos métodos, list y obj, que se utilizan para generar atributos HTML con los selectores necesarios:
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (use: IStyleProvider['use']) => {
const [css] = use(customStyle);
return {
firstElemAttrs: css.obj<TCustomMaker>({
w: 's',
panel: {
max: 'parent'
}
}), // {[attributeName]: 'selectors_string'}
secondElemAttrs: css.list<TCustomMaker>('logo.spin:', 'body.p:m') // {[attributeName]: 'selectors_string'}
};
};Modos de generación de atributos
El componente Style provider puede influir en la generación de selectores mediante dos atributos:
mode: puede tener el valora(utiliza los atributosdata-*) oc(utiliza el atributoclass). A partir de la versión 4.11.0, está marcado como obsoleto y se eliminará en la próxima versión principal. Utilice los métodosdxycxpara crear selectores explícitamente en forma de atributos de datos o nombres de clase, respectivamente.min: es un atributo booleano que permite minimizar los selectores BEM.
La generación de clases CSS es más predecible, y la generación de atributos de datos permite separar visualmente las diferentes hojas de estilo. Utilice la opción que prefiera.
La minimización conserva un prefijo único en el selector, por lo que los estilos de las diferentes tablas permanecerán aislados, mientras que la longitud de los selectores se reducirá significativamente.
Si se utiliza el modo de generación a y el framework utilizado admite esta sintaxis, los atributos resultantes se pueden pasar directamente al diseño:
<div {...firstElemAttrs}>...</div>Si se utiliza el modo de generación c, puede obtener las clases del objeto y pasarlas al diseño:
<div className={firstElemAttrs.class}>...</div>Generación explícita de nombres de clase
A partir de la versión 4.10.0, puede obtener directamente los selectores de clase CSS que necesita mediante la utilidad cx. Esta utilidad ignora el atributo mode del proveedor de estilos y devuelve una cadena con los nombres de clase:
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
const firstElemCls = provider.cx<TCustomMaker>(customStyle, {
w: 's',
panel: {
max: 'parent'
}
});
const secondElemCls = provider.cx<TCustomMaker>(customStyle, ['logo.spin:', 'body.p:m']);
return {
firstElemCls,
secondElemCls,
// starting from version 4.11.0 you can combine many selectors with `join`
combinedCls: provider.cx.join(firstElemCls, secondElemCls)
};
};Desde la versión 4.15.0, el tipo TStyleSheetMaker es genérico, toma el tipo de selectores públicos como parámetro, por lo que no es necesario pasar este parámetro al método cx:
import { IStyleProvider } from 'effcss';
import { default as customStyle } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
const firstElemCls = provider.cx(customStyle, {
w: 's',
panel: {
max: 'parent'
}
});
const secondElemCls = provider.cx(customStyle, ['logo.spin:', 'body.p:m']);
return {
firstElemCls,
secondElemCls,
// starting from version 4.11.0 you can combine many selectors with `join`
combinedCls: provider.cx.join(firstElemCls, secondElemCls)
};
};Generación explícita de atributos de datos
A partir de la versión 4.10.0, puede obtener directamente los selectores de atributos de datos CSS que necesita mediante la utilidad dx. Esta utilidad ignora el atributo mode del proveedor de estilos y devuelve un objeto con los siguientes atributos de datos:
import { IStyleProvider } from 'effcss';
import { default as customStyle, TCustomMaker } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
const firstElemAttrs = provider.dx<TCustomMaker>(customStyle, {
w: 's',
panel: {
max: 'parent'
}
});
const secondElemAttrs = provider.dx<TCustomMaker>(customStyle, ['logo.spin:', 'body.p:m']);
return {
firstElemAttrs,
secondElemAttrs,
// starting from version 4.11.0 you can combine many selectors with `join`
combinedAttrs: provider.dx.join(firstElemAttrs, secondElemAttrs)
};
};Desde la versión 4.15.0, el tipo TStyleSheetMaker es genérico, toma el tipo de selectores públicos como parámetro, por lo que no es necesario pasar este parámetro al método dx:
import { IStyleProvider } from 'effcss';
import { default as customStyle } from './styles/custom';
const getStyle = (provider: IStyleProvider) => {
const firstElemAttrs = provider.dx(customStyle, {
w: 's',
panel: {
max: 'parent'
}
});
const secondElemAttrs = provider.dx(customStyle, ['logo.spin:', 'body.p:m']);
return {
firstElemAttrs,
secondElemAttrs,
// starting from version 4.11.0 you can combine many selectors with `join`
combinedAttrs: provider.dx.join(firstElemAttrs, secondElemAttrs)
};
};WARNING
Cada StyleSheet maker crea solo una hoja de estilo, por lo que debe usar la utilidad cx o dx con un creador, pero no con ambos.
Beneficio
El enfoque descrito permite separar el contrato de la implementación. Durante el desarrollo, se sabe de antemano qué selectores CSS se deben proporcionar, y cualquier desarrollador externo puede importar el tipo TCustomMaker y obtener los estilos necesarios sin tener que consultar la función StyleSheet maker. Dado que los archivos JS suelen minificarse durante el ensamblaje, este enfoque ahorra mucho tiempo.
Además, EffCSS genera sus propios selectores únicos para cada hoja de estilo, lo que elimina el riesgo de tener que redefinirlos.
De este modo, EffCSS permite ir más allá de la creación habitual de CSS, acercándose al rol de CSS-in-TS.