diff --git a/README.md b/README.md index 8fb5ba6ba1..d2edd26615 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,15 @@ or add specific CSS-classes to the root node: ``` +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'; diff --git a/src/components/theme/ThemeProvider.tsx b/src/components/theme/ThemeProvider.tsx index 6714b7ac53..506c4cde01 100644 --- a/src/components/theme/ThemeProvider.tsx +++ b/src/components/theme/ThemeProvider.tsx @@ -1,17 +1,13 @@ import React from 'react'; -import {block, blockNew} from '../utils/cn'; - import {ThemeContext} from './ThemeContext'; import {ThemeSettingsContext} from './ThemeSettingsContext'; -import {DEFAULT_DARK_THEME, DEFAULT_LIGHT_THEME, DEFAULT_THEME, ROOT_CLASS_NAME} from './constants'; +import {DEFAULT_DARK_THEME, DEFAULT_LIGHT_THEME, DEFAULT_THEME} from './constants'; +import {getDeprecatedRootClassName, getRootClassName} from './getBodyClassName'; import type {RealTheme, Theme} from './types'; import {updateBodyClassName} from './updateBodyClassName'; import {useSystemTheme} from './useSystemTheme'; -const b = block(ROOT_CLASS_NAME); -const bNew = blockNew(ROOT_CLASS_NAME); - interface ThemeProviderExternalProps {} interface ThemeProviderDefaultProps { @@ -66,10 +62,16 @@ export function ThemeProvider({ {scoped ? (
{children}
diff --git a/src/components/theme/constants.ts b/src/components/theme/constants.ts index 89db77e2a5..bfff80768d 100644 --- a/src/components/theme/constants.ts +++ b/src/components/theme/constants.ts @@ -5,5 +5,3 @@ export const DEFAULT_DARK_THEME = 'dark'; export const LIGHT_THEMES = ['light', 'light-hc']; export const DARK_THEMES = ['dark', 'dark-hc']; export const THEMES = [...LIGHT_THEMES, ...DARK_THEMES]; - -export const ROOT_CLASS_NAME = 'root'; diff --git a/src/components/theme/getBodyClassName.ts b/src/components/theme/getBodyClassName.ts new file mode 100644 index 0000000000..5c658a49f7 --- /dev/null +++ b/src/components/theme/getBodyClassName.ts @@ -0,0 +1,26 @@ +import {block, blockNew} from '../utils/cn'; + +import type {RealTheme} from './types'; +import type {BodyClassNameModifiers} from './updateBodyClassName'; + +const ROOT_CLASS_NAME = 'root'; + +const bNew = blockNew(ROOT_CLASS_NAME); +const b = block(ROOT_CLASS_NAME); + +export function getDeprecatedRootClassName( + modifier?: Partial, +) { + return b(modifier); +} +export function getRootClassName( + modifier?: Partial, + addition?: string[], +) { + return bNew(modifier, addition); +} + +export function getInitialRootClassName(props: {theme?: RealTheme} = {}) { + const {theme} = props; + return getRootClassName({theme}); +} diff --git a/src/components/theme/index.ts b/src/components/theme/index.ts index 63ad45175b..baa894abfd 100644 --- a/src/components/theme/index.ts +++ b/src/components/theme/index.ts @@ -8,4 +8,5 @@ export * from './useThemeType'; export * from './withTheme'; export * from './withThemeValue'; export * from './getThemeType'; +export {getInitialRootClassName} from './getBodyClassName'; export type {Theme, RealTheme, ThemeType} from './types'; diff --git a/src/components/theme/updateBodyClassName.ts b/src/components/theme/updateBodyClassName.ts index 46a1597a98..02d3ffbf3f 100644 --- a/src/components/theme/updateBodyClassName.ts +++ b/src/components/theme/updateBodyClassName.ts @@ -1,12 +1,10 @@ -import {block, blockNew, modsClassName} from '../utils/cn'; +import {modsClassName} from '../utils/cn'; -import {ROOT_CLASS_NAME} from './constants'; +import {getDeprecatedRootClassName, getRootClassName} from './getBodyClassName'; import type {RealTheme} from './types'; -const b = block(ROOT_CLASS_NAME); -const bNew = blockNew(ROOT_CLASS_NAME); -const rootClassName = b(); -const rootNewClassName = bNew(); +const rootClassName = getDeprecatedRootClassName(); +const rootNewClassName = getRootClassName(); export type BodyClassNameModifiers = { 'native-scrollbar': boolean; @@ -41,19 +39,19 @@ export function updateBodyClassName( } [...bodyEl.classList].forEach((cls) => { - if (cls.startsWith(modsClassName(b({theme: true})))) { + if (cls.startsWith(modsClassName(getDeprecatedRootClassName({theme: true})))) { bodyEl.classList.remove(cls); } - if (cls.startsWith(modsClassName(bNew({theme: true})))) { + if (cls.startsWith(modsClassName(getRootClassName({theme: true})))) { bodyEl.classList.remove(cls); } }); - bodyEl.classList.add(modsClassName(b({theme: newTheme}))); - bodyEl.classList.add(modsClassName(bNew({theme: newTheme}))); + bodyEl.classList.add(modsClassName(getDeprecatedRootClassName({theme: newTheme}))); + bodyEl.classList.add(modsClassName(getRootClassName({theme: newTheme}))); for (const [key, value] of Object.entries({...defaultModifiers, ...modifiers})) { - bodyEl.classList.toggle(modsClassName(b({[key]: true})), value); - bodyEl.classList.toggle(modsClassName(bNew({[key]: true})), value); + bodyEl.classList.toggle(modsClassName(getDeprecatedRootClassName({[key]: true})), value); + bodyEl.classList.toggle(modsClassName(getRootClassName({[key]: true})), value); } }