From 79c6ac5e2cf5a7778da5b4ac1229897234531f25 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 7 Apr 2024 09:56:18 -0700 Subject: Theme and styles RTL support --- package-lock.json | 43 ++++++++++++++++++++++---- package.json | 2 ++ src/AppThemeProvider.jsx | 27 +++++++++++++--- src/common/components/LocalizationProvider.jsx | 7 +++-- src/common/theme/index.js | 5 +-- 5 files changed, 69 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index 96e8daae..5c8126d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,8 @@ "react-window": "^1.8.10", "recharts": "^2.12.4", "redux": "^5.0.1", + "stylis": "^4.3.1", + "stylis-plugin-rtl": "^2.1.1", "vite": "^5.2.8", "vite-plugin-pwa": "^0.19.8", "vite-plugin-svgr": "^4.2.0", @@ -1687,6 +1689,11 @@ "stylis": "4.2.0" } }, + "node_modules/@emotion/babel-plugin/node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/@emotion/cache": { "version": "11.11.0", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", @@ -1699,6 +1706,11 @@ "stylis": "4.2.0" } }, + "node_modules/@emotion/cache/node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/@emotion/hash": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", @@ -5198,9 +5210,9 @@ "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==" }, "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" }, "node_modules/@types/pbf": { "version": "3.0.5", @@ -6129,6 +6141,14 @@ "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==" }, + "node_modules/cssjanus": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cssjanus/-/cssjanus-2.1.0.tgz", + "integrity": "sha512-kAijbny3GmdOi9k+QT6DGIXqFvL96aksNlGr4Rhk9qXDZYWUojU4bRc3IHWxdaLNOqgEZHuXoe5Wl2l7dxLW5g==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -10820,9 +10840,20 @@ } }, "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz", + "integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==" + }, + "node_modules/stylis-plugin-rtl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/stylis-plugin-rtl/-/stylis-plugin-rtl-2.1.1.tgz", + "integrity": "sha512-q6xIkri6fBufIO/sV55md2CbgS5c6gg9EhSVATtHHCdOnbN/jcI0u3lYhNVeuI65c4lQPo67g8xmq5jrREvzlg==", + "dependencies": { + "cssjanus": "^2.0.1" + }, + "peerDependencies": { + "stylis": "4.x" + } }, "node_modules/subtag": { "version": "0.5.0", diff --git a/package.json b/package.json index 82d35be0..7d898781 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,8 @@ "react-window": "^1.8.10", "recharts": "^2.12.4", "redux": "^5.0.1", + "stylis": "^4.3.1", + "stylis-plugin-rtl": "^2.1.1", "vite": "^5.2.8", "vite-plugin-pwa": "^0.19.8", "vite-plugin-svgr": "^4.2.0", diff --git a/src/AppThemeProvider.jsx b/src/AppThemeProvider.jsx index 109d25c4..8f64b931 100644 --- a/src/AppThemeProvider.jsx +++ b/src/AppThemeProvider.jsx @@ -1,21 +1,40 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { ThemeProvider, useMediaQuery } from '@mui/material'; +import { CacheProvider } from '@emotion/react'; +import createCache from '@emotion/cache'; +import { prefixer } from 'stylis'; +import rtlPlugin from 'stylis-plugin-rtl'; import theme from './common/theme'; +import { useLocalization } from './common/components/LocalizationProvider'; + +const cache = { + ltr: createCache({ + key: 'muiltr', + stylisPlugins: [prefixer], + }), + rtl: createCache({ + key: 'muirtl', + stylisPlugins: [prefixer, rtlPlugin], + }), +}; const AppThemeProvider = ({ children }) => { const server = useSelector((state) => state.session.server); + const { direction } = useLocalization(); const serverDarkMode = server?.attributes?.darkMode; const preferDarkMode = useMediaQuery('(prefers-color-scheme: dark)'); const darkMode = serverDarkMode !== undefined ? serverDarkMode : preferDarkMode; - const themeInstance = theme(server, darkMode); + const themeInstance = theme(server, darkMode, direction); return ( - - {children} - + + + {children} + + ); }; diff --git a/src/common/components/LocalizationProvider.jsx b/src/common/components/LocalizationProvider.jsx index f69feabf..3af97cf0 100644 --- a/src/common/components/LocalizationProvider.jsx +++ b/src/common/components/LocalizationProvider.jsx @@ -152,8 +152,9 @@ const LocalizationContext = createContext({ export const LocalizationProvider = ({ children }) => { const [language, setLanguage] = usePersistedState('language', getDefaultLanguage()); + const direction = /^(ar|he|fa)$/.test(language) ? 'rtl' : 'ltr'; - const value = useMemo(() => ({ languages, language, setLanguage }), [languages, language, setLanguage]); + const value = useMemo(() => ({ languages, language, setLanguage, direction }), [languages, language, setLanguage, direction]); useEffect(() => { let selected; @@ -163,8 +164,8 @@ export const LocalizationProvider = ({ children }) => { selected = language; } dayjs.locale(selected); - document.dir = /^(ar|he|fa)$/.test(language) ? 'rtl' : 'ltr'; - }, [language]); + document.dir = direction; + }, [language, direction]); return ( diff --git a/src/common/theme/index.js b/src/common/theme/index.js index e8ce698b..00958497 100644 --- a/src/common/theme/index.js +++ b/src/common/theme/index.js @@ -4,8 +4,9 @@ import palette from './palette'; import dimensions from './dimensions'; import components from './components'; -export default (server, darkMode) => useMemo(() => createTheme({ +export default (server, darkMode, direction) => useMemo(() => createTheme({ palette: palette(server, darkMode), + direction, dimensions, components, -}), [server, darkMode]); +}), [server, darkMode, direction]); -- cgit v1.2.3