Material-ui: [withStyles] Ajout de la possibilité d'obtenir les accessoires du composant à partir de l'objet de style

Créé le 2 août 2017  ·  39Commentaires  ·  Source: mui-org/material-ui

La description

Lorsque vous utilisez createStyleSheet , il n'y a aucun moyen (du moins à ma connaissance) d'accéder aux accessoires du composant. Je pense que c'est important, car il est parfois nécessaire de transmettre des tailles, des images d'URL et d'autres styles en tant qu'accessoires au composant.

Aujourd'hui, la seule solution à cela est de séparer ces éléments en styles en ligne, mais pour autant que je sache, material-ui v1 utilise jss et react-jss , et ces deux vous donnent déjà la possibilité d'accéder aux props via des fonctions qui reçoivent les props puis retournent le style souhaité, comme ça :

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

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

Que pensez-vous d'implémenter quelque chose comme ça sur material-ui aussi ?

enhancement important

Commentaire le plus utile

J'ajoute ce problème dans le

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

Tous les 39 commentaires

react-jss implémente cette fonctionnalité. Vous pouvez toujours l'utiliser sur notre solution de coiffage. La véritable motivation pour implémenter cette fonctionnalité ici devrait être une implémentation interne plus simple/meilleure des composants.

react-jss injectStyles() le fait aussi, mais il semble qu'il serait préférable d'ajouter des accessoires au StyleRuleCallback .

const styles = (props, theme) => ({})
De cette façon, vous n'êtes pas limité aux seules valeurs en fonction des accessoires.

Les commentaires de color à nos composants, au lieu de celui prédéfini. L'impact de la taille CSS n'est pas clair, mais cela rendrait le remplacement de la couleur du composant encore plus simple. C'est quelque chose à enquêter. Ensuite, une fois que la prise en charge des variables CSS par le navigateur est suffisamment élevée (dans 2 ans ?), nous pouvons nous y fier.

@oliviertassinari la taille des css ne diminuerait-elle pas réellement dans certains cas ?
D'après ce que je comprends, nous définissons actuellement toutes les classes pour ...Primary et ...Accent - ce changement ne signifierait-il pas que nous n'aurions à maintenir les classes que pour ...Colorized ? Ou êtes-vous préoccupé par le css généré?

Quoi qu'il en soit, je pense que cela améliorerait énormément dx car nous devons essentiellement réimplémenter des classes complexes comme https://github.com/callemall/material-ui/blob/v1-beta/src/Button/Button.js#L11 lorsque nous voulez utiliser des couleurs non palette.

la taille du css ne diminuerait-elle pas réellement dans certains cas ?

@sakulstra Difficile à dire. Cela dépendra de la mise en œuvre. Peut-être :).

Du point de vue du typage TypeScript, ce serait bien si _both_ props et theme pouvaient être accédés de cette façon dans une spécification de styles :

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

La raison en est que TypeScript ne parvient souvent pas à déduire le bon type pour withStyles lorsqu'il est passé à un objet fonction, vous devez donc fournir des annotations de type supplémentaires pour le faire fonctionner, par exemple

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

Si des accessoires sont également transmis, cela deviendra

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

Quel est l'état actuel de cela? Ce serait vraiment sympa d'avoir cette fonction

@lucasmafra J'ai ajouté cette fonctionnalité au jalon de publication post v1. Plus tôt nous pourrons sortir la v1, mieux ce sera.

Cette fonctionnalité est essentielle pour pouvoir écrire des règles de style expressif qui combinent des accessoires, des requêtes multimédias et des états interactifs. Vous ne pouvez pas remplacer cette fonctionnalité par des styles en ligne. Malheureusement, withStyles est inutilisable dans aucun de mes projets jusqu'à ce que cela soit ajouté.

Vous pouvez toujours configurer un thème personnalisé et utiliser cette convention : nous aimons vraiment la façon dont les composants stylisés vous donnent accès à props.theme en imbriquant ThemeProvider dans MuiThemeProvider lorsque les deux sont appelés theme={theme}. Il étend le thème par défaut que mui expose

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

J'avais juste besoin d'utiliser des valeurs de fonction, j'ai donc utilisé la fonction injectSheet() react-jss. J'ai l'habitude d'utiliser la fonction withStyles() Mui, donc y a-t-il un inconvénient à utiliser injectSheet au lieu de withStyles ?

@damien-monni Vous n'avez pas accès à votre thème MUI.

Bonjour à tous, je voulais juste partager ma version de l'API Material-UI styled-components-like . Ce n'est pas "lourdement" testé mais il semble bien fonctionner et fournit :

  • Hissé props et theme pour styler la fonction.
  • Passer des props au composant encapsulé
  • Transférer les références via React.forwardRef
    (EDIT : les références ne fonctionnent actuellement que pour les balises html, pas pour la plupart des composants Material-UI de base, cela nécessite un support interne. Pourrait fonctionner sur un PR quand j'ai le temps, il faudrait accepter function ou object prop-types, et en vérifiant les composants sans état s'il faut passer à child )

Problèmes connexes : #10825, #7633

stylisé.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;

Exemple d'utilisation

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

Avec des accessoires personnalisés

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

@oliviertassinari Pour résoudre ce problème, j'utilise la solution ci-dessous :

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

Cela fonctionne très bien, mais y a-t-il des problèmes potentiels que je ne vois pas ? Je n'aime pas que je doive appeler jss.setup deux fois par exemple 😅. Je ne suis pas sûr de comprendre le cycle jss vie de setup() ici.

Cela fonctionne très bien, mais y a-t-il des problèmes potentiels que je ne vois pas ?

@wcandillon Certains problèmes potentiels que je peux voir: 1. Vous injecterez de nouveaux noms de classe à chaque fois qu'une instance du composant est montée. 2. Vous ne pourrez pas rendre votre composant côté serveur. 3. Vous n'obtiendrez pas le bon ordre d'injection de substitution CSS.

J'ai développé cette bibliothèque pour avoir des accessoires avec style :

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

Testé avec succès sur un projet.

Au début, j'utilise la solution danielmahon, mais j'ai un problème d'héritage de style.

@oliviertassinari Avons-nous une approche alternative pour créer des css/animations dynamiques en ce moment ? Merci :)

@HunderlineK Quelques alternatives : https://material-ui.com/customization/overrides/#2 -dynamic-variation-for-a-one-time-situation.

@danielmahon, votre approche est exactement ce que je recherche en ce moment pour résoudre mon problème, bien que le "composant stylisé" ne soit pas restitué lorsqu'il reçoit de nouveaux accessoires. As-tu essayé autre chose ?

Je penserai à quelque chose de différent, et si je trouve quelque chose je te le ferai savoir

💰 Je viens d'attacher une prime de 50 $ à celui-là :)

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

Comme l'a dit @lewisdiamond , const styles = (props, theme) => ({}) serait vraiment chouette.

Ou const styles = (theme, props) => ({}) pour être incassable peut-être.

J'ajoute ce problème dans le

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

@oliviertassinari cela a probablement des implications importantes pour la saisie de withStyles , faites-moi savoir si je peux vous aider avec ça

@pelotom Merci, je vous tiens au courant. J'espère pouvoir commencer à étudier la question ce mois-ci.

Y a-t-il des travaux en cours à ce sujet? C'est une fonctionnalité clé de l'OMI, je pourrais peut-être vous aider.

EDIT : j'ai commencé à travailler dessus. J'ai réussi à transmettre des accessoires à la fonction styles que withStyles accepte, le seul problème est que les styles ne sont pas mis à jour lorsque les accessoires changent. Créera un PR lorsque cela sera résolu.

Salut, je viens de tomber sur un cas d'utilisation où j'en avais besoin pour personnaliser les couleurs du composant avatar et il n'y a pas d'autre moyen de contrôler le style pour toutes les variantes du composant autre que celui-ci.

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

Vous pouvez consulter ma solution Japrogramer : https://github.com/JacquesBonet/jss-material-ui

merci, je vais y jeter un oeil.

J'avais besoin de cette fonctionnalité plus tôt dans la journée, j'ai donc écrit un HOC. withStyles fait de la mise en cache par lui-même, donc je ne peux pas vraiment dire à quel point cela affecte cela, mais je vais regarder l'implémentation de la mise en cache de withStyles dans mon temps libre, pour l'instant, tous ceux qui recherchent un un moyen rapide d'obtenir des accessoires et un thème pour bien jouer

Avertissement

Ce composant effectuera un remontage complet si les accessoires changent quelque chose à voir avec le numéro d'index de la classe de feuille de style changeant ou quelque chose dans le withStyles HOC

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

Exemple d'utilisation

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)

conclusion

Simple et fonctionne (mais rem le coût de remontage complet aussi)

Avec ce changement, pouvons-nous supprimer l'utilisation du style en ligne de la bibliothèque en faveur de 100 % JSS ? Mon application ne fonctionne pas avec les styles en ligne et lorsque je suis allé remplacer l'effet d'entraînement par JSS, j'ai réalisé que j'avais besoin de cette fonctionnalité. Peut-être un petit coup de performance, mais semble plus propre.

@koshea abandonne le style en ligne. Je n'aime pas non plus les styles en ligne, cela devrait très bien fonctionner en remplacement de withStyles tant que décorateur ou comme dans l'exemple.

Je voulais également mentionner que l'utilisation de styles en ligne ne permet pas d'activer une politique de sécurité du contenu solide.
Cela nécessite l'ajout unsafe-inline indicateur

Les styles dynamiques avec la prise en charge des accessoires devraient résoudre ce problème

Salut les gars, désolé d'entrer dans la discussion "juste comme ça". J'ai récemment commencé à utiliser Mui (avec Typescript) et même si je trouve que c'est une bibliothèque extrêmement puissante, elle a certainement ses complexités.

J'ai remarqué dans certains commentaires ci-dessus qu'il y a un peu de discussion pour savoir si cette fonctionnalité devrait être (props, theme) => {} ou (theme, props) => {} . J'aimerais renforcer ce que @pelotom a dit à propos de la création de propriétés nommées props et theme dans son commentaire . Le faire de cette façon nous permettra probablement de refactoriser plus facilement les définitions de style une fois ce changement effectué (ce que j'attends vraiment avec impatience). Bravo

Merci à tous pour la patience ! Ce problème est traité dans le #13503. C'est une exigence pour les assistants de composants que nous voulons implémenter. Nous avons également commencé à expérimenter l'API hook : https://twitter.com/olivtassinari/status/1058805751404261376.

Est-ce que cela en a fait 4.0 ? Il semble que le rappel makeStyles n'ait pas props paramètre

@city41 const classes = useStyles(props);

Je vois. Donc on dirait que c'est

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

Je ne vois pas cela documenté dans la section API de styles sur le site Web. Laissez-moi voir si je peux envoyer un PR.

@city41 Il y a un début de documentation dans https://material-ui.com/styles/basics/#adapting -based-on-props.

cool, content de voir que la doc est mise à jour. pour tous ceux qui abordent ce problème, voici comment j'ai combiné le thème et les accessoires pour styliser un composant

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

Comment puis-je utiliser prop dans un fichier json de styles externes ?

par exemple c'est un fichier externe

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;

j'importe ce fichier et répands l'objet

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'
                }
            }
        }
    },

  });

maintenant sur la fonction de couleur, j'obtiens des accessoires = {} .

quelqu'un peut-il m'aider à cet égard ?

METTRE À JOUR:

il semble que je fasse quelque chose de mal car j'obtiens un objet vide même dans mon fichier 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'
                }
            }
        }
    }
},
Cette page vous a été utile?
0 / 5 - 0 notes