Другое

Полное руководство по стилизации плейсхолдеров MUI TextField для RTL

Узнайте, почему MUI TextField вылетает в режиме RTL при стилизации плейсхолдеров и найдите 5+ рабочих альтернатив. Полное руководство с примерами кода для совместимой с RTL стилизации плейсхолдеров.

Почему простой MUI TextField аварийно завершает работу в локали RTL при стилизации placeholder?

Мое приложение работало идеально как на английском, так и на арабском языках, но я столкнулся с аварийным завершением работы при попытке стилизовать компонент TextField специально для RTL (справа налево) компоновки.

Следующий код работает нормально в английской локали, но вызывает сбой в арабской локали:

jsx
<TextField
  placeholder={'Enter your name'}
  sx={{
    "& .MuiInputBase-input::placeholder": {
      color: 'blue',
      opacity: 1,
    },
  }}
/>

Это приводит к следующей ошибке:

Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'push')

Трассировка стека указывает на проблемы в процессоре Stylis CSS-in-JS, связанные с селектором & .MuiInputBase-input::placeholder и псевдоэлементом ::placeholder.

Почему такой подход к стилизации вызывает сбои в локали RTL? Существуют ли альтернативные методы стилизации текста placeholder в MUI TextField, которые надежно работают как в LTR, так и в RTL направлениях?

Сбой возникает из-за системы стилизации RTL Material UI, которая использует stylis-plugin-rtl, имеющий ограничения при обработке сложных CSS-селекторов с псевдоэлементами, такими как ::placeholder. Селектор & .MuiInputBase-input::placeholder создает конфликт парсинга, который нарушает процесс преобразования RTL CSS.


Содержание

Понимание проблемы сбоя RTL

Ошибка TypeError: Cannot read properties of undefined (reading 'push') возникает потому, что плагин stylis-plugin-rtl не может правильно обработать и преобразовать селектор & .MuiInputBase-input::placeholder при обработке стилей RTL. Как показано в проблеме на StackOverflow, это известное ограничение в том, как RTL-плагин обрабатывает селекторы псевдоэлементов, объединенные с ссылками на родительские элементы.

Трассировка стека показывает, что ошибка возникает в:

  • stylis/src/Utility.js (106:0)
  • stylis/src/Tokenizer.js (40:7)

Это указывает на фундаментальную проблему в конвейере парсинга и преобразования CSS, когда применяется направление RTL к сложным селекторам.

Почему стилизация placeholder не работает в RTL

Сложность CSS-селекторов

Псевдоэлемент ::placeholder в сочетании с ссылкой на родительский элемент & создает шаблон селектора, с которым RTL-плагин не может правильно обработать:

jsx
"& .MuiInputBase-input::placeholder" // Этот селектор вызывает сбой

Ограничения RTL-плагина

Согласно проблеме в репозитории Git, stylis-plugin-rtl имеет определенные трудности с:

  1. Селекторами псевдоэлементов (такими как ::placeholder)
  2. Сложными вложенными селекторами со ссылками на родительские элементы
  3. Конвенциями именования классов в стиле BEM, используемых MUI

Проблемы совместимости версий

Проблема часто усугубляется несоответствием версий между:

  • Версиями stylis
  • Версиями stylis-plugin-rtl
  • Версиями Material UI
  • Версиями Emotion/Styled-components

Альтернативные решения для стилизации placeholder

Решение 1: Использование прямого стилизации input

Вместо того, чтобы целенаправленно изменять стиль placeholder, стилизуйте элемент input напрямую:

jsx
<TextField
  placeholder={'Введите ваше имя'}
  sx={{
    "& .MuiInputBase-input": {
      color: 'blue',
    },
  }}
/>

Плюсы: Работает как в LTR, так и в RTL без сбоев
Минусы: Влияет на обычный цвет текста input, а не только на placeholder

Решение 2: Использование стилизации placeholder на уровне темы

Настройте стилизацию placeholder на уровне темы:

jsx
const theme = createTheme({
  direction: 'rtl',
  components: {
    MuiInputBase: {
      styleOverrides: {
        input: {
          '&::placeholder': {
            color: 'blue',
            opacity: 1,
          },
        },
      },
    },
  },
});

Плюсы: Совместимо с RTL и централизованно управляется
Минусы: Глобально влияет на все TextField

Решение 3: Использование CSS-классов с глобальными стилями

Определите глобальные CSS-классы для RTL-специфичной стилизации:

css
/* В вашем глобальном CSS или styled-jsx */
.rtl-placeholder-blue::placeholder {
  color: blue !important;
  opacity: 1 !important;
}
jsx
<TextField
  placeholder={'Введите ваше имя'}
  className={isRtl ? 'rtl-placeholder-blue' : ''}
/>

Плюсы: Полный контроль и совместимость с RTL
Минусы: Требует управления файлами CSS

Решение 4: Использование условных встроенных стилей

Примените стили условно в зависимости от направления:

jsx
const textFieldStyles = isRtl
  ? {
      "& .MuiInputBase-input": {
        color: 'blue',
      },
    }
  : {
      "& .MuiInputBase-input::placeholder": {
        color: 'blue',
        opacity: 1,
      },
    };

<TextField
  placeholder={'Введите ваше имя'}
  sx={textFieldStyles}
/>

Лучшие практики для готовых к TextField стилей RTL

1. Используйте встроенную поддержку RTL в MUI

Правильно настройте RTL с самого начала, как показано в официальном руководстве по RTL MUI:

jsx
import rtlPlugin from 'stylis-plugin-rtl';
import { prefixer } from 'stylis';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';

const cacheRtl = createCache({
  key: 'muirtl',
  stylisPlugins: [prefixer, rtlPlugin],
});

const theme = createTheme({
  direction: 'rtl',
});

2. Избегайте сложных селекторов в RTL

При включенном RTL придерживайтесь более простых шаблонов CSS:

jsx
// Вместо этого (вызывает сбой в RTL):
"& .MuiInputBase-input::placeholder"

// Используйте это (работает в RTL):
"& .MuiInputBase-input"

3. Тестируйте с различными сценариями RTL

Тестируйте стилизацию с:

  • Различными RTL-языками (арабский, иврит, персидский)
  • Динамическим переключением направления
  • Вложенными компонентами с наследованием RTL

4. Используйте инструменты разработки

Включите отладку RTL для выявления проблем со стилизацией:

jsx
// Включите отладку RTL в разработке
if (process.env.NODE_ENV === 'development') {
  console.log('Направление RTL:', theme.direction);
}

Полный пример реализации

Вот полный рабочий пример, который избегает сбоя RTL:

jsx
import React from 'react';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import rtlPlugin from 'stylis-plugin-rtl';
import { prefixer } from 'stylis';
import TextField from '@mui/material/TextField';
import CssBaseline from '@mui/material/CssBaseline';

// Создайте кэш для RTL
const cacheRtl = createCache({
  key: 'muirtl',
  stylisPlugins: [prefixer, rtlPlugin],
});

const theme = createTheme({
  direction: 'rtl',
  components: {
    MuiInputBase: {
      styleOverrides: {
        input: {
          // Резервная стилизация placeholder
          '&::placeholder': {
            opacity: 1,
          },
        },
      },
    },
  },
});

const RTLTextField = ({ placeholder, isRtl, ...props }) => {
  const textFieldStyles = {
    '& .MuiInputBase-input': {
      color: 'blue',
      // Это работает как в LTR, так и в RTL
    },
  };

  return (
    <TextField
      placeholder={placeholder}
      sx={textFieldStyles}
      {...props}
    />
  );
};

function App() {
  const [isRtl, setIsRtl] = React.useState(true);

  return (
    <CacheProvider value={isRtl ? cacheRtl : undefined}>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <div style={{ direction: isRtl ? 'rtl' : 'ltr' }}>
          <RTLTextField
            placeholder={'Введите ваше имя'}
            label={'Имя'}
            variant="outlined"
            fullWidth
          />
          
          <button onClick={() => setIsRtl(!isRtl)}>
            Переключить направление
          </button>
        </div>
      </ThemeProvider>
    </CacheProvider>
  );
}

export default App;

Эта реализация:

  • Использует официальную конфигурацию RTL от MUI
  • Избегает проблемных селекторов ::placeholder в RTL
  • Предоставляет последовательную стилизацию в обоих направлениях
  • Включает функциональность переключения направления
  • Использует резервную стилизацию, которая работает во всех сценариях

Источники

  1. Material-Ui TextField не затрагивается направлением RTL - Stack Overflow
  2. Простой Mui TextField вылетает в локали RTL - Stack Overflow
  3. Проблема stylis-plugin-rtl на GitHub
  4. Как настроить поддержку RTL (справа налево) в Material UI версии 5
  5. Поддержка справа налево - Документация Material UI
  6. Конфигурация Material-Ui TextField RTL - StackForGeeks
Авторы
Проверено модерацией
Модерация