4
votes

Comment puis-je imiter l'apparence du contour et de l'étiquette du champ de texte souligné Material-UI?

J'essaie d'imiter le champ de texte décrit dans Material-UI mais je ne sais pas comment masquer la bordure derrière le texte du titre.

Dans l'image ci-dessous, remarquez comment est extrait de la bibliothèque Material-UI et le titre cache la bordure derrière elle, mais lorsque j'ai essayé de l'imiter avec un composant personnalisé, je ne pouvais tout simplement pas cacher la bordure.

Sinon, existe-t-il un meilleur moyen de utiliser cette conception de contour au lieu de simplement l'implémenter avec CSS?

Mon composant actuel ressemble à ceci:

<div style={inputContainerStyle}>
        <div style={{
          ...titleStyle,
          transform: 'translate(-43px, -11px) scale(0.75)',
          fontSize: '17px',
          color: 'rgba(0, 0, 0, 0.54)',
          position: 'absolute',
        }}
        >
          Color
        </div>
        <div
          className="flex-row"
          style={{
            border: '1px solid rgba(0, 0, 0, 0.23)',
            padding: '18.5px 14px',
            borderRadius: '4px',
          }}
        >
          {
            availableColors.map(color => <div style={colorCircleStyle(color)} />)
          }
        </div>
      </div>


2 commentaires

Définir la couleur d'arrière-plan


Avez-vous essayé background-color: inherit sur le

Color
?


3 Réponses :


6
votes

UPDATE

Pour de nombreux scénarios, ma réponse ultérieure (qui évite d'utiliser TextField et n'a donc aucun effet secondaire sur le contexte FormControl ) peut être plus approprié: Comment puis-je définir un div avec contour statique similaire au champ de texte avec contour de Material-UI?


Il y a une grande flexibilité dans ce que vous pouvez faire avec TextField . TextField prend en charge le branchement de différents types d'entrées (par exemple, Select , input , sélecteurs personnalisés) via la propriété inputComponent . Vous pouvez en tirer parti pour mettre n'importe quoi dans son contour étiqueté en créant un composant personnalisé comme celui-ci OutlinedDiv:

import React from "react";
import ReactDOM from "react-dom";

import OutlinedDiv from "./OutlinedDiv";
import Avatar from "@material-ui/core/Avatar";
import deepOrange from "@material-ui/core/colors/deepOrange";
import deepPurple from "@material-ui/core/colors/deepPurple";
import red from "@material-ui/core/colors/red";
import green from "@material-ui/core/colors/green";
import blue from "@material-ui/core/colors/blue";
import Grid from "@material-ui/core/Grid";

function App() {
  return (
    <div className="App">
      <OutlinedDiv label="Color Picker">
        <Grid container justify="center" alignItems="center">
          <Avatar style={{ backgroundColor: deepOrange[500] }} />
          <Avatar style={{ backgroundColor: deepPurple[500] }} />
          <Avatar style={{ backgroundColor: red[500] }} />
          <Avatar style={{ backgroundColor: green[500] }} />
          <Avatar style={{ backgroundColor: blue[500] }} />
        </Grid>
      </OutlinedDiv>
      <br />
      <br />
      <OutlinedDiv label="Custom Outlined Thing">
        You can put whatever you want in here.
      </OutlinedDiv>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Le className code > passé au inputComponent prend en charge le CSS qui fait que tout fonctionne. Vous pouvez ensuite utiliser ceci comme dans ce qui suit:

import React from "react";

import TextField from "@material-ui/core/TextField";

const InputComponent = ({ inputRef, ...other }) => <div {...other} />;
const OutlinedDiv = ({ children, label }) => {
  return (
    <TextField
      variant="outlined"
      label={label}
      multiline
      InputLabelProps={{ shrink: true }}
      InputProps={{
        inputComponent: InputComponent
      }}
      inputProps={{ children: children }}
    />
  );
};
export default OutlinedDiv;

 Modifier le composant hiérarchisé personnalisé


4 commentaires

Depuis "@ material-ui / core": "4.0.0" cela ne fonctionne plus.

à l'intérieur de inputComponent de TextField a une classe .MuiInputBase-input , qui a un height définie et ne se redimensionne pas correctement. J'ai trouvé ceci dans les notes de mise à jour, mais je ne sais pas si c'est ce qui cause ce problème.


Comme solution, vous pouvez ajouter du style dans

:


@EganWolf Oui, cette pull request était à l'origine de la différence. J'ai ajouté le prop mutliline qui entraîne ensuite l'application d'un CSS légèrement différent pour la gestion de la hauteur.


J'ai des problèmes lors de l'utilisation de votre solution avec des entrées, car elles perdent le focus lors de la frappe. J'ai posé une nouvelle question décrivant ce problème.



0
votes

Appliquez simplement la même couleur d'arrière-plan sur le div de couleur que la couleur d'arrière-plan du parent , vous pouvez le faire en arrière-plan- couleur: héritez comme ceci:

<div style={inputContainerStyle}>
        <div style={{
          ...titleStyle,
          transform: 'translate(-43px, -11px) scale(0.75)',
          fontSize: '17px',
          color: 'rgba(0, 0, 0, 0.54)',
          position: 'absolute',
          background-color:'inherit' **(just add this line)**
        }}
        >
          Color
        </div>
        <div
          className="flex-row"
          style={{
            border: '1px solid rgba(0, 0, 0, 0.23)',
            padding: '18.5px 14px',
            borderRadius: '4px',
          }}
        >
          {
            availableColors.map(color => <div style={colorCircleStyle(color)} />)
          }
        </div>
      </div>


0 commentaires

0
votes

Le champ de texte décrit était vraiment difficile à mettre en œuvre. En poussant cette fonctionnalité, nous avons dû considérer plusieurs options, chacune avec ses propres inconvénients

  1. Élément SVG

Facile à créer et à animer, mais difficile à adapter aux éléments environnants. Si nous avions suivi cette voie, nous aurions dû écouter un certain type d'événement de redimensionnement, ce qui signifierait soit l'utilisation d'un événement de redimensionnement de fenêtre, qui n'est pas robuste, soit l'utilisation d'une fonctionnalité plus récente et moins prise en charge telle qu'un ResizeObserver / MutationObserver. Il existe des polyfills, mais cela aurait augmenté la taille du bundle d'environ 2K pour une fonctionnalité relativement petite.

La route SVG est probablement celle qui sera utilisée à l'avenir. Il convient également de noter que c'est ainsi que le Material Components Web de Google résout le problème. .

  1. Ancienne bordure simple avec un arrière-plan sur l'étiquette

C'est de loin l'approche la plus simple, mais elle est aussi quelque peu rigide. Vous pouvez voir un exemple de cela dans le nouveau flux de connexion de Google. Là, ils définissent la couleur d'arrière-plan sur le blanc. C'est probablement une bonne approche pour de nombreux utilisateurs, mais bien sûr, ne fonctionnera pas si votre arrière-plan est un dégradé ou un cas de bord similaire. Cela dit, il n'y a pas besoin de s'inquiéter du redimensionnement car ce n'est qu'une bordure.

  1. Champ et légende

C'est ce que nous avons finalement choisi, en grande partie à cause de sa flexibilité pour les utilisateurs finaux. Fieldset et son composant de légende sont tous deux des moyens intégrés d'atteindre à peu près cette fonctionnalité exacte. Les gros inconvénients à cela sont que le style entre les navigateurs est difficile et que les propriétés sur lesquelles nous animerions ne sont pas performantes, telles que la largeur de la légende. De plus, il est toujours préférable d'utiliser du HTML sémantique bien sûr, ce qui n'est pas le cas, ce qui signifie que nous devons utiliser aria-hidden pour demander aux lecteurs d'écran d'ignorer l'élément.

En fonction de vos objectifs, l'une de ces solutions peut vous convenir le mieux. Attention, trouver la solution parfaite qui résout tous ces problèmes peut être très délicat!


0 commentaires