Material-ui: [withStyles] Adicione a capacidade de obter os adereços do componente de dentro do objeto de estilo

Criado em 2 ago. 2017  ·  39Comentários  ·  Fonte: mui-org/material-ui

Descrição

Ao usar createStyleSheet , não há como (pelo menos que eu conheça) acessar os adereços do componente. Acho isso importante, pois às vezes é necessário passar tamanhos, imagens de urls e outros estilos como adereços para o componente.

Hoje, a única solução para isso é separar essas coisas em estilos embutidos, mas até onde eu sei, o material-ui v1 usa jss e react-jss , e esses dois já lhe dão a possibilidade de acessar os adereços por meio de funções que recebem os adereços e depois retornam o estilo desejado, assim:

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

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

O que você acha de implementar algo assim no material-ui também?

enhancement important

Comentários muito úteis

Estou adicionando esse problema no marco v1.x. Muitas pessoas estão solicitando isso. Em breve chegaremos a ele.

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

Todos 39 comentários

react-jss implementa esse recurso. Você sempre pode usá-lo sobre nossa solução de estilo. A verdadeira motivação para implementar esse recurso aqui deve ser em torno de uma implementação interna mais simples / melhor dos componentes.

react-jss injectStyles () também faz isso, mas parece que seria melhor adicionar adereços a StyleRuleCallback .

const styles = (props, theme) => ({})
Dessa forma, você não está limitado a apenas valores dependendo dos adereços.

O feedback do color aos nossos componentes, em vez do predefinido. O impacto do tamanho do CSS não está claro, mas tornaria a substituição da cor do componente ainda mais simples. Isso é algo para investigar. Então, uma vez que o suporte do navegador de variáveis ​​css seja alto o suficiente (daqui a 2 anos?), Podemos confiar nele.

@oliviertassinari o tamanho do css não diminuiria em alguns casos?
Pelo que entendi, atualmente definimos todas as classes para ...Primary e ...Accent - essa mudança não significaria que teríamos apenas que manter as classes para ...Colorized ? Ou você está preocupado com o css gerado?

De qualquer forma, acho que isso melhoraria enormemente o dx, pois basicamente temos que reimplementar classes complexas como https://github.com/callemall/material-ui/blob/v1-beta/src/Button/Button.js#L11 quando deseja usar cores que não sejam da paleta.

o tamanho do css não diminuiria em alguns casos?

@sakulstra Difícil dizer. Vai depender da implementação. Pode ser :).

De uma perspectiva de digitação TypeScript, seria bom se _both_ props e theme pudessem ser acessados ​​desta forma dentro de uma especificação de estilos:

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

A razão é que o TypeScript freqüentemente falha em inferir o tipo certo para withStyles quando é passado um objeto de função, então você deve fornecer anotações de tipo extras para fazê-lo funcionar, por exemplo,

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

Se os adereços forem passados ​​também, isso se tornará

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

Qual é o status atual disso? Seria muito bom ter esse recurso

@lucasmafra Eu adicionei esse recurso ao marco pós-lançamento v1. Quanto mais cedo pudermos lançar a v1, melhor.

Essa funcionalidade é fundamental para poder escrever regras de estilo expressivas que combinam adereços, consultas de mídia e estados interativos. Você não pode substituir essa funcionalidade por estilos embutidos. Infelizmente, withStyles ser usado em nenhum dos meus projetos até que seja adicionado.

Você sempre pode configurar um tema personalizado e usar esta convenção: Nós realmente gostamos de como os componentes estilizados fornecem acesso ao props.theme pronto para uso, aninhando ThemeProvider dentro de MuiThemeProvider quando ambos chamados theme = {theme}. Ele estende o tema padrão que o mui expõe

//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']};
`

Eu só precisava usar valores de função, então usei a função react-jss ' injectSheet() . Estou acostumado a usar a função withStyles() do Mui, então há alguma desvantagem em usar injetSheet em vez de withStyles?

@ damien-monni Você não tem acesso ao seu tema MUI.

Olá a todos, só queria compartilhar minha versão da API com estilo de componentes de interface do usuário Material. Não é "pesadamente" testado, mas parece funcionar bem e fornece:

  • props e theme içados para a função de estilo.
  • Passando props customizado para o componente empacotado
  • Encaminhando referências via React.forwardRef
    (EDITAR: Os Refs estão trabalhando atualmente apenas para tags html, não para a maioria dos componentes de interface de usuário do Material de base, isso requer suporte interno. Posso trabalhar em um PR quando eu tiver tempo, exigiria a aceitação de function ou object prop-types e verificando os componentes sem estado para passar para o filho)

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;

Exemplo de uso

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,
  },
}));

Com adereços personalizados

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

@oliviertassinari Para resolver esse problema, estou usando a solução abaixo:

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

Funciona muito bem, mas há alguns problemas em potencial que não estou vendo? Eu não gosto de ter que chamar jss.setup duas vezes, por exemplo 😅. Não tenho certeza se entendi o ciclo de vida de jss . Fiquei surpreso por precisar invocar setup() aqui.

Funciona muito bem, mas há alguns problemas em potencial que não estou vendo?

@wcandillon Algum problema potencial que posso ver: 1. Você injetará novos nomes de classe toda vez que uma instância do componente for montada. 2. Você não poderá renderizar seu componente no lado do servidor. 3. Você não obterá a ordem correta de injeção de substituição de CSS.

Desenvolvi esta biblioteca para ter adereços com estilo:

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

Testado com sucesso em um projeto.

No início, eu uso a solução danielmahon, mas obtenho problema de herança de estilo.

@oliviertassinari Temos uma abordagem alternativa para criar css / animações dinâmicas no momento? Obrigado :)

@HunderlineK Algumas alternativas: https://material-ui.com/customization/overrides/#2 -dynamic-variação-para-uma-situação-única.

@danielmahon, sua abordagem é exatamente o que estou procurando agora para resolver meu problema, embora o "Componente com estilo" não seja renderizado novamente ao receber novos acessórios. Você já tentou mais alguma coisa?

Vou pensar em algo diferente, e se eu vier com algo, eu vou te dizer

💰 Acabei de anexar uma recompensa de $ 50 a esse :)

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

Como @lewisdiamond disse, const styles = (props, theme) => ({}) seria muito legal.

Ou const styles = (theme, props) => ({}) para ser talvez ininterrupto.

Estou adicionando esse problema no marco v1.x. Muitas pessoas estão solicitando isso. Em breve chegaremos a ele.

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

@oliviertassinari isso provavelmente tem implicações significativas para a digitação de withStyles , deixe-me saber se eu posso ajudar com isso

@pelotom Obrigado,

Há algum trabalho em andamento a respeito disso? É um recurso chave da IMO, talvez eu possa ajudar com isso.

EDIT: Comecei a trabalhar nisso. Conseguiu passar adereços para a função styles que withStyles aceita, o único problema é que os estilos não são atualizados quando os adereços mudam. Criará um PR quando isso for resolvido.

Olá, acabei de encontrar um caso de uso em que preciso personalizar as cores do componente avatar e não há outra maneira de controlar o estilo de todas as variantes do componente além desta.

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),
      }),
    },
});

Você pode verificar minha solução Japrogramer: https://github.com/JacquesBonet/jss-material-ui

obrigado, vou dar uma olhada nisso.

Eu precisava desse recurso hoje cedo, então escrevi um HOC. withStyles faz algum cache por conta própria, então eu realmente não posso dizer o quanto isso afeta isso, mas vou olhar para a implementação de cache de withStyles em meu tempo livre, por enquanto, quem estiver procurando por um maneira rápida de obter adereços e tema para tocar bem, pronto

Aviso

Este componente fará uma remontagem completa se os adereços mudarem algo a ver com o número do índice da classe da folha de estilo mudando ou algo no 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

Exemplo de uso

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)

conclusão

Simples e funciona (mas remova o custo total da remontagem também)

Com essa mudança, podemos remover o uso de estilo embutido da biblioteca em favor de 100% JSS? Meu aplicativo não funciona com estilos embutidos e quando fui substituir o efeito cascata por JSS, percebi que precisava desse recurso. Talvez um pequeno impacto no desempenho, mas parece mais limpo.

@koshea abandonou o estilo embutido. Eu também realmente não gosto de estilos embutidos, ele deve funcionar muito bem como um substituto para withStyles como decorador ou como no exemplo.

Também gostaria de mencionar que o uso de estilos embutidos não permite habilitar uma forte política de segurança de conteúdo.
Requer a adição da bandeira unsafe-inline às diretivas de estilos, o que não é seguro.

Estilos dinâmicos com suporte de adereços devem resolver esse problema

Oi pessoal, desculpe entrar na discussão "assim". Recentemente, comecei a usar o Mui (com Typescript) e, embora a ache uma biblioteca extremamente poderosa, ela certamente tem suas complexidades.

Notei em alguns comentários acima que há uma pequena discussão sobre se esse recurso deveria ser (props, theme) => {} ou (theme, props) => {} . Eu gostaria de reforçar o que @pelotom disse sobre fazer props e theme propriedades nomeadas em seu comentário . Tornar assim provavelmente tornará mais fácil para nós refatorar as definições de estilo, uma vez que essa mudança aconteça (o que estou realmente ansioso para ver). Saúde 🙂

Obrigado a todos pela paciência! Este problema está sendo resolvido em # 13503. É um requisito para os auxiliares de componente que desejamos implementar. Também começamos a experimentar a API de gancho: https://twitter.com/olivtassinari/status/1058805751404261376.

Isso chegou ao 4.0? Parece que o retorno de chamada makeStyles não tem um parâmetro props .

@ city41 const classes = useStyles(props);

Entendo. Então parece que é

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>;
}

Não vejo isso documentado na seção de estilos da API no site. Deixe-me ver se posso enviar um PR.

@ city41 Há um início de documentação em https://material-ui.com/styles/basics/#adapting -based-on-props.

legal, fico feliz em ver que os documentos estão sendo atualizados. para qualquer pessoa que venha a este problema, aqui está como eu combinei tema e adereços para estilizar um 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" />;
};

Como posso usar prop em um arquivo json de estilos externos?

por exemplo, este é um arquivo 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;

eu importo este arquivo e divulgo o 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'
                }
            }
        }
    },

  });

agora na função de cor, obtenho adereços = {}.

alguem pode me ajudar nesse sentido?

ATUALIZAR:

parece que estou fazendo algo errado porque estou recebendo um objeto vazio mesmo no meu arquivo styles.js principal

    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'
                }
            }
        }
    }
},
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

revskill10 picture revskill10  ·  3Comentários

TimoRuetten picture TimoRuetten  ·  3Comentários

ghost picture ghost  ·  3Comentários

sys13 picture sys13  ·  3Comentários

zabojad picture zabojad  ·  3Comentários