From ba08c66d83dac2d8ff9d44c27f2739f192d68e92 Mon Sep 17 00:00:00 2001 From: Andrey Morozov Date: Mon, 10 Jun 2024 18:44:34 +0300 Subject: [PATCH] fix(theme): bring back root classname helper and fix docs (#1633) --- README.md | 34 ++++++++--------------- package.json | 8 ++++++ src/components/theme/dom-helpers.ts | 13 +++++++++ src/components/theme/getDarkMediaMatch.ts | 3 -- src/components/theme/getRootClassName.ts | 14 ++++++++++ src/components/theme/getSystemTheme.ts | 9 ------ src/components/theme/useSystemTheme.ts | 3 +- src/server.ts | 1 + 8 files changed, 48 insertions(+), 37 deletions(-) delete mode 100644 src/components/theme/getDarkMediaMatch.ts create mode 100644 src/components/theme/getRootClassName.ts delete mode 100644 src/components/theme/getSystemTheme.ts create mode 100644 src/server.ts diff --git a/README.md b/README.md index b98a290d04..3efb2071ce 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,7 @@ import '@gravity-ui/uikit/styles/styles.css'; // ... ``` -UIKit supports different themes: light, dark and their contrast variants. The theme must be applied. To do that either -wrap your app in `ThemeProvider`: +UIKit supports different themes: light, dark and their contrast variants. Your app must be rendered inside `ThemeProvider`: ```js import {createRoot} from 'react-dom/client'; @@ -63,32 +62,21 @@ root.render( ); ``` -or add specific CSS-classes to the root node: +It is possible to generate initial root CSS-classes during SSR to avoid theme flashing: -```html - +```js +import {getRootClassName} from '@gravity-ui/uikit/server'; + +const theme = 'dark'; +const rootClassName = getRootClassName({theme}); + +const html = ` -
+
-``` - -it is possible to generate initial CSS-classes during SSR: - -```js -import {getInitialRootClassName} from '@gravity-ui/uikit'; - -const theme = 'light'; -const rootClassName = getInitialRootClassName({theme}); -``` - -```js -// index.js -import {createRoot} from 'react-dom/client'; - -const root = createRoot(document.getElementById('root')); -root.render(); +`; ``` Also, there is a SCSS [mixins](styles/mixins.scss) file with useful helpers to use in your app. diff --git a/package.json b/package.json index 3b4d889150..d78fa69cf1 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,11 @@ "require": "./build/cjs/unstable.js", "import": "./build/esm/unstable.js" }, + "./server": { + "types": "./build/esm/server.d.ts", + "require": "./build/cjs/server.js", + "import": "./build/esm/server.js" + }, "./styles/*": "./styles/*" }, "main": "./build/cjs/index.js", @@ -60,6 +65,9 @@ ], "unstable": [ "./build/esm/unstable.d.ts" + ], + "server": [ + "./build/esm/server.d.ts" ] } }, diff --git a/src/components/theme/dom-helpers.ts b/src/components/theme/dom-helpers.ts index adab86e45d..a6e2246cfa 100644 --- a/src/components/theme/dom-helpers.ts +++ b/src/components/theme/dom-helpers.ts @@ -66,3 +66,16 @@ export function updateBodyDirection(direction: Direction) { bodyEl.setAttribute('dir', direction); } } + +export const supportsMatchMedia = + typeof window !== 'undefined' && typeof window.matchMedia === 'function'; + +export const getDarkMediaMatch = () => window.matchMedia('(prefers-color-scheme: dark)'); + +export function getSystemTheme() { + if (supportsMatchMedia) { + return getDarkMediaMatch().matches ? 'dark' : 'light'; + } else { + return 'light'; + } +} diff --git a/src/components/theme/getDarkMediaMatch.ts b/src/components/theme/getDarkMediaMatch.ts deleted file mode 100644 index 9099dc4aa2..0000000000 --- a/src/components/theme/getDarkMediaMatch.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const supportsMatchMedia = - typeof window !== 'undefined' && typeof window.matchMedia === 'function'; -export const getDarkMediaMatch = () => window.matchMedia('(prefers-color-scheme: dark)'); diff --git a/src/components/theme/getRootClassName.ts b/src/components/theme/getRootClassName.ts new file mode 100644 index 0000000000..92b621a263 --- /dev/null +++ b/src/components/theme/getRootClassName.ts @@ -0,0 +1,14 @@ +import {block} from '../utils/cn'; + +import {ROOT_CLASSNAME} from './constants'; +import type {RealTheme} from './types'; + +const b = block(ROOT_CLASSNAME); + +interface RootMods { + theme?: RealTheme; +} + +export function getRootClassName({theme}: RootMods = {}, className?: string) { + return b({theme}, className); +} diff --git a/src/components/theme/getSystemTheme.ts b/src/components/theme/getSystemTheme.ts deleted file mode 100644 index 19c35ce446..0000000000 --- a/src/components/theme/getSystemTheme.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {getDarkMediaMatch, supportsMatchMedia} from './getDarkMediaMatch'; - -export function getSystemTheme() { - if (supportsMatchMedia) { - return getDarkMediaMatch().matches ? 'dark' : 'light'; - } else { - return 'light'; - } -} diff --git a/src/components/theme/useSystemTheme.ts b/src/components/theme/useSystemTheme.ts index 8deca3e2bf..d0e6c57ff2 100644 --- a/src/components/theme/useSystemTheme.ts +++ b/src/components/theme/useSystemTheme.ts @@ -1,7 +1,6 @@ import React from 'react'; -import {getDarkMediaMatch, supportsMatchMedia} from './getDarkMediaMatch'; -import {getSystemTheme} from './getSystemTheme'; +import {getDarkMediaMatch, getSystemTheme, supportsMatchMedia} from './dom-helpers'; import type {ThemeType} from './types'; function addListener( diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000000..e82f20d949 --- /dev/null +++ b/src/server.ts @@ -0,0 +1 @@ +export {getRootClassName} from './components/theme/getRootClassName';