Material-ui: [withStyles] Agregue la capacidad de obtener los accesorios del componente desde dentro del objeto de estilo

Creado en 2 ago. 2017  ·  39Comentarios  ·  Fuente: mui-org/material-ui

Descripción

Al usar createStyleSheet , no hay forma (al menos que yo sepa) de acceder a los accesorios del componente. Creo que esto es importante, ya que a veces se desea pasar tamaños, imágenes de URL y otros estilos como accesorios para el componente.

Hoy en día, la única solución a esto es separar estas cosas en estilos en línea, pero hasta donde yo sé, material-ui v1 usa jss y react-jss , y esos dos ya te dan la posibilidad de acceder a los accesorios a través de funciones que reciben los accesorios y luego devuelven el estilo deseado, así:

const styles = {
  button: {
    background: props => props.color
  },
  root: {
    backgroundImage: props => `url(${props.backgroundImage})`
  }
}

// Reference: https://github.com/cssinjs/react-jss#example

¿Qué piensas de implementar algo así en material-ui también?

enhancement important

Comentario más útil

Estoy agregando este problema en el hito v1.x. Mucha gente lo solicita. Pronto llegaremos a eso.

capture d ecran 2018-07-29 a 13 12 03

Todos 39 comentarios

react-jss implementa esa característica. Siempre puede usarlo sobre nuestra solución de peinado. La verdadera motivación para implementar esa característica aquí debería estar en torno a una implementación interna más simple / mejor de los componentes.

react-jss injectStyles () también hace esto, pero parece ser que sería mejor agregar accesorios al StyleRuleCallback .

const styles = (props, theme) => ({})
De esa manera, no está limitado solo a valores que dependen de los accesorios.

Los comentarios de color a nuestros componentes, en lugar del predefinido. El impacto del tamaño de CSS no está claro, pero simplificaría aún más la anulación del color del componente. Esto es algo para investigar. Entonces, una vez que el soporte del navegador de variables css sea lo suficientemente alto (¿dentro de 2 años?), Podemos confiar en él.

@oliviertassinari ¿No disminuiría realmente el tamaño de CSS en algunos casos?
Según lo entiendo, actualmente definimos todas las clases para ...Primary y ...Accent - ¿No significaría este cambio que solo tendríamos que mantener las clases por ...Colorized ? ¿O le preocupa el CSS generado?

De cualquier manera, creo que esto mejoraría enormemente dx, ya que básicamente tenemos que volver a implementar clases complejas como https://github.com/callemall/material-ui/blob/v1-beta/src/Button/Button.js#L11 cuando desea utilizar colores que no sean de paleta.

¿No disminuiría realmente el tamaño del CSS en algunos casos?

@sakulstra Difícil de decir. Dependerá de la implementación. Quizás :).

Desde una perspectiva de escritura en TypeScript, sería bueno si se pudiera acceder a _both_ props y theme esta manera dentro de una especificación de estilos:

const styles = {
  button: {
    background: ({ theme }) => theme.palette.primary[200]
  },
  root: {
    backgroundImage: ({ props }) => `url(${props.backgroundImage})`
  }
};

La razón es que TypeScript con frecuencia no infiere el tipo correcto para withStyles cuando se le pasa un objeto de función, por lo que debe proporcionar anotaciones de tipo adicionales para que funcione, por ejemplo

withStyles<'button' | 'root'>(theme => ...)

Si también se pasan los accesorios, esto se convertirá en

withStyles<'button' | 'root', Props>((theme, props) => ...)

¿Cuál es el estado actual de esto? Sería muy bueno tener esa característica.

@lucasmafra He agregado esta función al hito de lanzamiento posterior a la v1. Cuanto antes podamos lanzar v1, mejor.

Esta funcionalidad es clave para poder escribir reglas de estilo expresivo que combinen accesorios, consultas de medios y estados interactivos. No puede reemplazar esa funcionalidad con estilos en línea. Desafortunadamente, withStyles se puede utilizar en ninguno de mis proyectos hasta que se agregue.

Siempre puedes configurar un tema personalizado y usar esta convención: Nos gusta mucho cómo los componentes con estilo te dan acceso a props.theme al anidar ThemeProvider dentro de MuiThemeProvider cuando ambos llaman theme = {theme}. Extiende el tema predeterminado que mui expone.

//inline with HOC Method
 h1 style= {{ 'color: this.props.theme.palette.primary[500]' }}

//styled components ( no method necessary )
const Heading = styled.h1`
  color: ${p => p.theme.palette.primary['500']};
`

Solo necesitaba usar valores de función, así que usé la función injectSheet() react-jss. Estoy acostumbrado a usar la función withStyles() Mui, entonces, ¿hay algún inconveniente al usar injectSheet en lugar de withStyles?

@ damien-monni No tienes acceso a tu tema MUI.

Hola a todos, solo quería compartir mi versión de la API similar a componentes con estilo Material-UI. No se ha probado "en gran medida", pero parece funcionar bien y proporciona:

  • Elevó props y theme a la función de estilo.
  • Pasando props al componente envuelto
  • Reenvío de referencias a través de React.forwardRef
    (EDITAR: las referencias solo funcionan actualmente para etiquetas html, no para la mayoría de los componentes básicos de Material-UI, esto requiere soporte interno. Podría funcionar en un PR cuando tenga tiempo, requeriría aceptar function o object prop-types, y haciendo comprobaciones en los componentes sin estado si se deben pasar al niño)

Problemas relacionados: # 10825, # 7633

styled.js

import React, { Component } from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';

function styled(WrappedComponent, customProps) {
  return (style, options) => {
    class StyledComponent extends Component {
      render() {
        let {
          forwardRef,
          classes,
          className,
          ...passThroughProps
        } = this.props;
        return (
          <WrappedComponent
            ref={forwardRef}
            className={classNames(classes.root, className)}
            {...passThroughProps}
            {...customProps}
          />
        );
      }
    }

    StyledComponent.propTypes = {
      classes: PropTypes.object.isRequired,
      className: PropTypes.string,
    };

    let hoistedProps = {};

    const styles =
      typeof style === 'function'
        ? theme => {
            return { root: style({ ...theme, theme, props: hoistedProps }) };
          }
        : { root: style };

    const WithRef = withStyles(styles, options)(StyledComponent);

    return React.forwardRef((props, ref) => {
      hoistedProps = props;
      return <WithRef {...props} forwardRef={ref} />;
    });
  };
}

export default styled;

Uso de ejemplo

const MobileNav = styled('nav')(({ theme, props }) => ({
  '&.pos-fixed': {
    top: 0,
    position: props.fixed ? 'fixed' : 'absolute',
    zIndex: 99,
    animation: 'fadeInDown 0.3s ease-out forwards',
    backgroundColor: theme.palette.common.white,
  },
}));

Con accesorios personalizados

const StyledButton = styled(Button, { component: Link })(
  ({ theme, props }) => ({
    color: props.disabled ? 'gray' : 'blue',
    [theme.breakpoints.down('sm')]: {
      color: 'red',
    },
  })
);

@oliviertassinari Para resolver este problema, estoy usando la siguiente solución:

    componentWillMount() {
        const {color} = this.props;
        jss.setup(jssPreset());
        const stylesheet = jss.createStyleSheet({
            underline: {
              "&:after": {
                backgroundColor: `${color} !important`
              }
            }
        }).attach();
        this.underlineClass = stylesheet.classes.underline;
    }

Funciona muy bien, pero ¿hay algunos problemas potenciales que no veo? No me gusta que tenga que llamar a jss.setup dos veces, por ejemplo 😅. No estoy seguro de entender el ciclo jss vida de setup() aquí.

Funciona muy bien, pero ¿hay algunos problemas potenciales que no veo?

@wcandillon Algún problema potencial que puedo ver: 1. Inyectará nuevos nombres de clase cada vez que se monte una instancia del componente. 2. No podrá renderizar su componente en el lado del servidor. 3. No obtendrá el orden correcto de inyección de anulación de CSS.

Desarrollé esta biblioteca para tener accesorios con estilo:

https://github.com/JacquesBonet/jss-material-ui

Probado con éxito en un proyecto.

Al principio, uso la solución danielmahon, pero tengo un problema de herencia de estilo.

@oliviertassinari ¿Tenemos un enfoque alternativo para crear CSS / animaciones dinámicas en este momento? Gracias :)

@HunderlineK Algunas alternativas: https://material-ui.com/customization/overrides/#2 -dynamic-variación-for-a-one-time-status.

@danielmahon, tu enfoque es justo lo que estoy buscando en este momento para resolver mi problema, aunque el "Componente con estilo" no se vuelve a renderizar cuando recibe nuevos accesorios. ¿Has probado algo más?

Pensaré en algo diferente, y si se me ocurre algo, te lo haré saber

💰 Solo adjunto una recompensa de $ 50 a ese :)

https://www.bountysource.com/issues/47838203-withstyles-add-the-ability-to-get-the-component-s-props-from-within-the-style-object

Como dijo @lewisdiamond , const styles = (props, theme) => ({}) sería realmente genial.

O const styles = (theme, props) => ({}) para no romperse tal vez.

Estoy agregando este problema en el hito v1.x. Mucha gente lo solicita. Pronto llegaremos a eso.

capture d ecran 2018-07-29 a 13 12 03

@oliviertassinari, esto probablemente tenga implicaciones significativas para escribir withStyles , avíseme si puedo ayudar con eso

@pelotom Gracias, te lo haré saber. Espero poder empezar a analizar el problema este mes.

¿Hay trabajo en progreso al respecto? En mi opinión, es una característica clave, tal vez podría ayudar con ella.

EDITAR: comencé a trabajar en eso. Se las arregló para pasar accesorios a la función styles que acepta withStyles , el único problema es que los estilos no se actualizan cuando cambian los accesorios. Creará un PR cuando eso se resuelva.

Hola, acabo de encontrarme con un caso de uso en el que necesitaba esto para personalizar los colores del componente de avatar y no hay otra forma de controlar el estilo para todas las variantes del componente que no sea esta.

const styles = theme => ({
  chip:{
  },
  separator: {
    marginRight: theme.spacing.unit,
  },
  fright: {
    float: 'right',
  },
  fleft: {
    float: 'left',
  },
  outlinedPrimary:{
    color: props =>  stringToColor( props.username),
    border: props => `1px solid ${fade(stringToColor(props.username), 0.5)}`,
    '$clickable&:hover, $clickable&:focus, $deletable&:focus': props => ({
      backgroundColor: fade(stringToColor(props.username), theme.palette.action.hoverOpacity),
      border: `1px solid ${stringToColor(props.username)}`,
      }),
  },
  outlined: {
    backgroundColor: 'transparent',
    border: props => `1px solid ${
      theme.palette.type === 'light' ? stringToColor(props.username) : fade(stringToColor(props.username))
    }`,
    '$clickable&:hover, $clickable&:focus, $deletable&:focus': props => ({
      backgroundColor: fade(stringToColor(props.username), theme.palette.action.hoverOpacity),
      }),
    },
});

Puedes consultar mi solución Japrogramer: https://github.com/JacquesBonet/jss-material-ui

gracias, le echaré un vistazo.

Necesitaba esta función hoy, así que escribí un HOC. withStyles hace un poco de almacenamiento en caché por sí solo, así que no puedo decir cuánto afecta esto a eso, pero miraré la implementación de almacenamiento en caché de withStyles en mi tiempo libre, por ahora, cualquiera que busque un forma rápida de conseguir accesorios y temas para jugar bien ahí lo tienes

Advertencia

Este componente hará un remontaje completo si los accesorios cambian algo que ver con el número de índice de la clase de la hoja de estilo cambiando o algo en el HOC withStyles

import React from 'react';
import { withStyles } from '@material-ui/core/styles';

const { createElement, forwardRef } = React

const withPropsStyles = ( style ) => {

    const withPropsStyles = ( component ) => {

        return forwardRef( (props, ref) => {

            const proxy = (theme) => style(props, theme)

            const hoc = withStyles(proxy)(component)

            return props.children ? 
                createElement(hoc, { ...props, ref}, props.children) :
                createElement(hoc, {...props, ref}) 
        }) 
    }

    return withPropsStyles
}

export default withPropsStyles

Uso de ejemplo

const styles = (props, theme) => ({
    root:{
        backgroundColor: props.light ? theme.palette.primary.light : theme.palette.primary.main 
    },
})

const SomeComponent = ({classes}) => <div className={classes.root}/>

export default withPropsStyles(styles)(SomeComponent)

conclusión

Simple y funciona (pero remueve el costo total de remontaje también)

Con este cambio, ¿podemos eliminar el uso de estilo en línea de la biblioteca a favor de 100% JSS? Mi aplicación no funciona con estilos en línea y cuando fui a reemplazar el efecto dominó con JSS me di cuenta de que necesitaba esta función. Quizás un pequeño golpe de rendimiento, pero parece más limpio.

@koshea abandona el estilo en línea. Tampoco me gustan los estilos en línea, debería funcionar bien como un reemplazo directo de withStyles como decorador o como en el ejemplo.

También quería mencionar que el uso de estilos en línea no permite habilitar una política de seguridad de contenido sólida.
Requiere agregar la bandera unsafe-inline a las directivas de estilos, lo cual no es seguro.

Los estilos dinámicos con soporte de accesorios deberían resolver ese problema.

Hola chicos, perdón por saltar a la discusión "así". Recientemente comencé a usar Mui (con Typescript) y, aunque me parece una biblioteca extremadamente poderosa, ciertamente tiene sus complejidades.

Noté en algunos comentarios anteriores que hay una pequeña discusión sobre si esta característica debería ser (props, theme) => {} o (theme, props) => {} . Me gustaría reforzar lo que dijo @pelotom sobre hacer propiedades con nombre tanto props como theme en su comentario . Hacerlo de esa manera probablemente nos facilitará la refactorización de las definiciones de estilo una vez que este cambio aterrice (lo cual estoy ansioso por hacer). Saludos 🙂

¡Gracias a todos por la paciencia! Este problema se está solucionando en el número 13503. Es un requisito para los componentes auxiliares que queremos implementar. También hemos comenzado a experimentar con la API de enlace :

¿Esto lo convirtió en 4.0? Parece que la devolución makeStyles llamada props .

@ ciudad41 const classes = useStyles(props);

Veo. Entonces parece que lo es

const useStyles = makeStyles(theme => {
    return {
        foo: {
            color: theme.props.danger ? '#ff0000' : '#00ff00'
        }
    };
});

function MyComponent(props) {
    const classes = useStyles(props);

    return <div className={classes.foo}>...</div>;
}

No veo esto documentado en la sección de API de estilos en el sitio web. Déjame ver si puedo enviar un PR.

@ city41 Hay un comienzo de documentación en https://material-ui.com/styles/basics/#adapting -based-on-props.

Genial, me alegro de ver que los documentos se actualizan. para cualquier otra persona que venga a este número, así es como combiné el tema y los accesorios para diseñar un componente

import React from 'react';
import { Button, Theme, makeStyles } from '@material-ui/core';

interface ButtonProps {
    destructive: boolean;
}

const useButtonStyles = makeStyles<Theme, ButtonProps>(theme => {
    return {
        root: props => ({
            backgroundColor: props.destructive ? theme.palette.error.main : theme.palette.primary.main
        })
    };
});

export const PrimaryButton: React.FunctionComponent<ButtonProps> = props => {
    const classes = useButtonStyles(props);

    return <Button {...props} className={classes.root} variant="contained" />;
};

¿Cómo puedo usar prop en un archivo json de estilos externos?

por ejemplo, este es un archivo externo

const typographyStyle = {
  title2: {
    fontFamily:"Montserrat",
    fontStyle:"normal",
    fontWeight:"800",
    fontSize:"72px",
    lineHeight:"88px",
    letterSpacing:"-0.02em",
    // color:"#304C82"
    color : props => {
      console.log(props,'c1');
      return props.color
    }

  }
};

export default typographyStyle;

importo este archivo y extiendo el objeto

import typographyStyle from "../assets/jss/material-kit-pro-react/views/componentsSections/typographyStyle";


const styles = theme =>  ({
    ...typographyStyle,
    homeSearch:{
        width: '100%',
        '& div':{
            '& input':{
                "color":"#304C82",
                height: 65,
                fontFamily: 'Open Sans',
                fontStyle: 'normal',
                fontWeight: 800,
                fontSize: '48px',
                lineHeight: '65px',
                letterSpacing: '-0.03em',
                '&::placeholder':{
                    fontFamily: 'Open Sans',
                    fontStyle: 'normal',
                    fontWeight: 800,
                    fontSize: '48px',
                    lineHeight: '65px',
                    letterSpacing: '-0.03em',
                    color: '#EAEAEA'
                }
            }
        }
    },

  });

ahora en la función de color obtengo props = {}.

¿alguien puede ayudarme en este sentido?

ACTUALIZAR:

parece que estoy haciendo algo mal porque obtengo un objeto vacío incluso en mi archivo principal styles.js

    homeSearch: props => {
        console.log(props);
        return {
        width: '100%',
        border:  `1px solid ${props.color}`
        ,
        '& div':{
            '& input':{
                "color":"#304C82",
                height: 65,
                fontFamily: 'Open Sans',
                fontStyle: 'normal',
                fontWeight: 800,
                fontSize: '48px',
                lineHeight: '65px',
                letterSpacing: '-0.03em',
                '&::placeholder':{
                    fontFamily: 'Open Sans',
                    fontStyle: 'normal',
                    fontWeight: 800,
                    fontSize: '48px',
                    lineHeight: '65px',
                    letterSpacing: '-0.03em',
                    color: '#EAEAEA'
                }
            }
        }
    }
},
¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

newoga picture newoga  ·  3Comentarios

finaiized picture finaiized  ·  3Comentarios

ghost picture ghost  ·  3Comentarios

sys13 picture sys13  ·  3Comentarios

reflog picture reflog  ·  3Comentarios