Как добавить поддержку RTL для Material UI React - PullRequest
0 голосов
/ 28 мая 2019

Я создаю приложение LTR и хочу добавить поддержку RTL.Приложение основано на материале пользовательского интерфейса React.Я могу повернуть приложение в RTL, так как я использую CSS Flex Box, просто добавив dir = "rtl" в тело.Я также добавил direction = "rtl" к теме, как упоминалось здесь .

Однако не все было изменено.

Давайте рассмотрим это в качестве примера: Select Country LTR Как вы видите, у меня есть отступ слева от текстового элемента.В версии RTL, поскольку все было перевернуто, отступы слева не влияют на пользовательский интерфейс, я имею в виду, что отступы вправо должны показывать небольшое пространство между двумя элементами: Select Country RTL

Кажется, что я делаю что-то не так, потому что в документации Material UI здесь эта функция должна быть из коробки после добавления этого фрагмента и обернуть компонент вокруг него.

Это мойРодительский компонент App:

import React, { PureComponent } from "react";
import { theme } from "./styling/theme";
import Routes from "./Routes";
// Redux
import { Provider } from "react-redux";
import store from "./app/store";

import LoadingBar from "react-redux-loading-bar";
// CSS
import { MuiThemeProvider } from "@material-ui/core/styles";
// import { ThemeProvider } from "@material-ui/styles";
import { create } from "jss";
import rtl from "jss-rtl";
import JssProvider from "react-jss/lib/JssProvider";
// import { StylesProvider, jssPreset } from "@material-ui/styles";
import { createGenerateClassName, jssPreset } from "@material-ui/core/styles";
import { themeObject, colors } from "./styling/theme";
// Helpers
import get from "lodash/get";

// Configure JSS
const jss = create({ plugins: [...jssPreset().plugins, rtl()] });
const generateClassName = createGenerateClassName();

function RTL(props) {
  return (
    <JssProvider jss={jss} generateClassName={generateClassName}>
      {
        props.children
      }
    </JssProvider>
  );
}

class App extends PureComponent {
  render() {
    const isRtl = get(store, "classified.language.rtl", false);
    return (
      <Provider store={store}>
        <RTL>
          <MuiThemeProvider
            theme={
              isRtl
                ? { ...theme, direction: "rtl" }
                : { ...theme, direction: "ltr" }
            }
          >
            <LoadingBar
              style={{
                backgroundColor: colors.primary[500],
                height: themeObject.spacing.unit,
                zIndex: 9999
              }}
            />
            <Routes />
          </MuiThemeProvider>
        </RTL>
      </Provider>
    );
  }
}

export default App;

И это пример моих компонентов (на рисунках выше: CLList):

import React, { Component } from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
// Helpers
import isFunction from "lodash/isFunction";
import cloneDeep from "lodash/cloneDeep";

import styles from "./CLList.styles";

const defaultImg = "IMAGE_URL_HERE";
class CLList extends Component {
  static propTypes = {
    classes: PropTypes.object.isRequired,
    items: PropTypes.arrayOf(
      PropTypes.shape({
        img: PropTypes.string,
        name: PropTypes.string
      })
    ).isRequired,
    onClick: PropTypes.func
  };
  render() {
    const { classes, items, onClick } = this.props;
    return (
      <ul className={classes.list}>
        {items.map((item, key) => (
          <li
            className={classes.item}
            onClick={() => isFunction(onClick) && onClick(cloneDeep(item))}
            key={key}
          >
            <img
              className={classes.image}
              src={item.img || defaultImg}
              alt={item.name}
              title={item.name}
            />
            <span className={classes.label}>{item.name}</span>
          </li>
        ))}
      </ul>
    );
  }
}

export default withStyles(styles)(CLList);

И последний файл - CSS для CLList:

import { colors } from "../..";
const styles = theme => ({
  list: {
    display: "flex",
    flexDirection: "column",
    listStyle: "none",
    padding: 5,
    margin: 0,
    "& > li:not(:last-child)": {
      marginBottom: 10
    }
  },
  item: {
    flex: 1,
    display: "flex",
    cursor: "pointer",
    "&:hover": {
      backgroundColor: colors.primary[50]
    }
  },
  image: {
    flex: "0 0 15%",
    maxWidth: "40px",
    maxHeight: "40px"
  },
  label: {
    flex: "1",
    alignSelf: "center",
    paddingLeft: 20
  }
});

export default styles;

Я ожидаю, что paddingLeft метки будет => paddingRight.Это возможно ?Это особенность из коробки?Или я должен просто использовать RTL-CSS-JS и обернуть все мои объекты стилей, когда тело содержит dir = "RTL" для автоматического изменения стиля?

Я также так запутался междуэти две библиотеки:

  • @ material-ui / core / styles
  • @ material-ui / styles

Должен ли я использовать первый или второйодин ?В чем разница?

Спасибо за ваше время.

РЕДАКТИРОВАТЬ 1:

Я использовал rtlCSSJS в моем объекте CSSи я получаю ожидаемый результат.Но я не уверен, что это лучший способ сделать это.CSS из CLList теперь выглядит следующим образом:

import rtlCSSJS from "rtl-css-js";
import { colors } from "../..";
const defaultDir = document.body.getAttribute("dir");
const styles = theme =>
  defaultDir === 'rtl' ? rtlCSSJS({...CSS_HERE....}) : {...CSS_HERE....};
export default styles;

1 Ответ

0 голосов
/ 28 мая 2019

Я думаю, что нашел решение для своего собственного вопроса, но не стесняйтесь добавлять какие-либо усовершенствования или более качественные решения.

По умолчанию пользовательский интерфейс материалов использует jss-rtl, и этот последний является оболочкой для rtl-CSS-JS.Таким образом, нет необходимости использовать rtl-css-js напрямую, поскольку пользовательский интерфейс материалов выполнит эту работу.

Я изменил свой компонент родительского приложения на:

import React, { PureComponent } from "react";
import Routes from "./Routes";
import RTL from "./RTL";
// Redux
import { Provider } from "react-redux";
import store from "./app/store";

import LoadingBar from "react-redux-loading-bar";

import { themeObject, colors } from "./styling/theme";

class App extends PureComponent {
  render() {
    return (
      <Provider store={store}>
        <RTL>
          <>
            <LoadingBar
              // className="loading"
              style={{
                backgroundColor: colors.primary[500],
                height: themeObject.spacing.unit,
                zIndex: 9999
              }}
            />
            <Routes />
          </>
        </RTL>
      </Provider>
    );
  }
}

export default App;

И добавил компонент RTLкоторый подключится к Redux, чтобы определить правильную тему в правильном направлении.Я сохраняю данные языка в Redux, и в соответствии с этими данными я определю тему, предоставленную для моего приложения.

Это компонент RTL:

import React, { PureComponent } from "react";
import PropTypes from "prop-types";
// Redux
import { connect } from "react-redux";
// CSS
import { MuiThemeProvider, createMuiTheme } from "@material-ui/core/styles";
import { create } from "jss";
import rtl from "jss-rtl";
import JssProvider from "react-jss/lib/JssProvider";
import { createGenerateClassName, jssPreset } from "@material-ui/core/styles";

// Theme
import { themeObject } from "./styling/theme";

// Helpers
import get from "lodash/get";
// Configure JSS
const jss = create({ plugins: [...jssPreset().plugins, rtl()] });
const generateClassName = createGenerateClassName();

const G_isRtl = document.body.getAttribute("dir") === "rtl";

class RTL extends PureComponent {
  static propTypes = {
    children: PropTypes.oneOfType([
      PropTypes.array,
      PropTypes.object,
      PropTypes.node
    ]),
    language: PropTypes.object
  };

  render() {
    const { children, language } = this.props;
    const isRtl = get(language, "rtl", G_isRtl);

    const theme = createMuiTheme({
      ...themeObject,
      direction: isRtl ? "rtl" : "ltr"
    });

    return (
      <JssProvider jss={jss} generateClassName={generateClassName}>
        <MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>
      </JssProvider>
    );
  }
}

const mapStateToProps = ({ classified }) => ({
  language: classified.language
});
export default connect(mapStateToProps)(RTL);

Все дочерние компонентыТеперь мы будем переключаться между RTL и LTR в соответствии с языком, и мы можем сосредоточиться только на одной раскладке, вся работа по изменению сделана благодаря этим плагинам.

Также я хочу сказать следующее в официальных инструкциях документация у меня не работает!Большая часть этого решения, которое я нашел, основано на ответе здесь .

...