@cloud-ru/ds-theme 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/LICENSE +201 -0
- package/README.md +365 -0
- package/dist/cjs/components/ChildThemeProvider/ChildThemeProvider.d.ts +24 -0
- package/dist/cjs/components/ChildThemeProvider/ChildThemeProvider.js +25 -0
- package/dist/cjs/components/ChildThemeProvider/index.d.ts +1 -0
- package/dist/cjs/components/ChildThemeProvider/index.js +17 -0
- package/dist/cjs/components/RootThemeProvider/RootThemeProvider.d.ts +49 -0
- package/dist/cjs/components/RootThemeProvider/RootThemeProvider.js +30 -0
- package/dist/cjs/components/RootThemeProvider/index.d.ts +1 -0
- package/dist/cjs/components/RootThemeProvider/index.js +17 -0
- package/dist/cjs/components/ThemeProvider/ThemeProvider.d.ts +28 -0
- package/dist/cjs/components/ThemeProvider/ThemeProvider.js +16 -0
- package/dist/cjs/components/ThemeProvider/index.d.ts +1 -0
- package/dist/cjs/components/ThemeProvider/index.js +17 -0
- package/dist/cjs/components/ThemeScope/ThemeScope.d.ts +32 -0
- package/dist/cjs/components/ThemeScope/ThemeScope.js +65 -0
- package/dist/cjs/components/ThemeScope/index.d.ts +1 -0
- package/dist/cjs/components/ThemeScope/index.js +17 -0
- package/dist/cjs/components/index.d.ts +3 -0
- package/dist/cjs/components/index.js +19 -0
- package/dist/cjs/constants/appearance.d.ts +22 -0
- package/dist/cjs/constants/appearance.js +27 -0
- package/dist/cjs/constants/colorScheme.d.ts +17 -0
- package/dist/cjs/constants/colorScheme.js +23 -0
- package/dist/cjs/constants/index.d.ts +2 -0
- package/dist/cjs/constants/index.js +18 -0
- package/dist/cjs/context/appearanceContext.d.ts +20 -0
- package/dist/cjs/context/appearanceContext.js +22 -0
- package/dist/cjs/context/index.d.ts +4 -0
- package/dist/cjs/context/index.js +7 -0
- package/dist/cjs/context/themeContext.d.ts +12 -0
- package/dist/cjs/context/themeContext.js +15 -0
- package/dist/cjs/hooks/index.d.ts +4 -0
- package/dist/cjs/hooks/index.js +20 -0
- package/dist/cjs/hooks/useApplyCustomTheme.d.ts +27 -0
- package/dist/cjs/hooks/useApplyCustomTheme.js +39 -0
- package/dist/cjs/hooks/useColorScheme.d.ts +37 -0
- package/dist/cjs/hooks/useColorScheme.js +80 -0
- package/dist/cjs/hooks/useIsomorphicLayoutEffect.d.ts +7 -0
- package/dist/cjs/hooks/useIsomorphicLayoutEffect.js +16 -0
- package/dist/cjs/hooks/useThemeClassnames.d.ts +11 -0
- package/dist/cjs/hooks/useThemeClassnames.js +18 -0
- package/dist/cjs/hooks/useThemeConfig.d.ts +24 -0
- package/dist/cjs/hooks/useThemeConfig.js +15 -0
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.js +23 -0
- package/dist/cjs/keys.d.ts +4 -0
- package/dist/cjs/keys.js +19 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/ssr.d.ts +15 -0
- package/dist/cjs/ssr.js +38 -0
- package/dist/cjs/store/globalStore.d.ts +29 -0
- package/dist/cjs/store/globalStore.js +72 -0
- package/dist/cjs/store/index.d.ts +1 -0
- package/dist/cjs/store/index.js +17 -0
- package/dist/cjs/types/appearance.d.ts +23 -0
- package/dist/cjs/types/appearance.js +3 -0
- package/dist/cjs/types/colorScheme.d.ts +5 -0
- package/dist/cjs/types/colorScheme.js +2 -0
- package/dist/cjs/types/index.d.ts +2 -0
- package/dist/cjs/types/index.js +18 -0
- package/dist/cjs/utils/colorSchemeFromHeaders.d.ts +22 -0
- package/dist/cjs/utils/colorSchemeFromHeaders.js +44 -0
- package/dist/cjs/utils/colorSchemeStorage.d.ts +35 -0
- package/dist/cjs/utils/colorSchemeStorage.js +85 -0
- package/dist/cjs/utils/customTheme/buildBrandPaletteCss.d.ts +11 -0
- package/dist/cjs/utils/customTheme/buildBrandPaletteCss.js +35 -0
- package/dist/cjs/utils/customTheme/buildBrandPaletteVars.d.ts +11 -0
- package/dist/cjs/utils/customTheme/buildBrandPaletteVars.js +42 -0
- package/dist/cjs/utils/customTheme/color/apca.d.ts +4 -0
- package/dist/cjs/utils/customTheme/color/apca.js +62 -0
- package/dist/cjs/utils/customTheme/color/colorSpace.d.ts +5 -0
- package/dist/cjs/utils/customTheme/color/colorSpace.js +72 -0
- package/dist/cjs/utils/customTheme/color/conversions.d.ts +17 -0
- package/dist/cjs/utils/customTheme/color/conversions.js +101 -0
- package/dist/cjs/utils/customTheme/color/hex.d.ts +10 -0
- package/dist/cjs/utils/customTheme/color/hex.js +34 -0
- package/dist/cjs/utils/customTheme/color/index.d.ts +4 -0
- package/dist/cjs/utils/customTheme/color/index.js +20 -0
- package/dist/cjs/utils/customTheme/color/oklch.d.ts +3 -0
- package/dist/cjs/utils/customTheme/color/oklch.js +21 -0
- package/dist/cjs/utils/customTheme/color/types.d.ts +40 -0
- package/dist/cjs/utils/customTheme/color/types.js +2 -0
- package/dist/cjs/utils/customTheme/constants.d.ts +31 -0
- package/dist/cjs/utils/customTheme/constants.js +49 -0
- package/dist/cjs/utils/customTheme/generateBrandPalette.d.ts +10 -0
- package/dist/cjs/utils/customTheme/generateBrandPalette.js +25 -0
- package/dist/cjs/utils/customTheme/index.d.ts +4 -0
- package/dist/cjs/utils/customTheme/index.js +20 -0
- package/dist/cjs/utils/getThemeClassnames.d.ts +17 -0
- package/dist/cjs/utils/getThemeClassnames.js +38 -0
- package/dist/cjs/utils/index.d.ts +7 -0
- package/dist/cjs/utils/index.js +23 -0
- package/dist/cjs/utils/mergeAppearance.d.ts +7 -0
- package/dist/cjs/utils/mergeAppearance.js +17 -0
- package/dist/cjs/utils/resolveColorScheme.d.ts +7 -0
- package/dist/cjs/utils/resolveColorScheme.js +15 -0
- package/dist/cjs/utils/themeBootstrap.d.ts +12 -0
- package/dist/cjs/utils/themeBootstrap.js +19 -0
- package/dist/esm/components/ChildThemeProvider/ChildThemeProvider.d.ts +24 -0
- package/dist/esm/components/ChildThemeProvider/ChildThemeProvider.js +22 -0
- package/dist/esm/components/ChildThemeProvider/index.d.ts +1 -0
- package/dist/esm/components/ChildThemeProvider/index.js +1 -0
- package/dist/esm/components/RootThemeProvider/RootThemeProvider.d.ts +49 -0
- package/dist/esm/components/RootThemeProvider/RootThemeProvider.js +27 -0
- package/dist/esm/components/RootThemeProvider/index.d.ts +1 -0
- package/dist/esm/components/RootThemeProvider/index.js +1 -0
- package/dist/esm/components/ThemeProvider/ThemeProvider.d.ts +28 -0
- package/dist/esm/components/ThemeProvider/ThemeProvider.js +13 -0
- package/dist/esm/components/ThemeProvider/index.d.ts +1 -0
- package/dist/esm/components/ThemeProvider/index.js +1 -0
- package/dist/esm/components/ThemeScope/ThemeScope.d.ts +32 -0
- package/dist/esm/components/ThemeScope/ThemeScope.js +59 -0
- package/dist/esm/components/ThemeScope/index.d.ts +1 -0
- package/dist/esm/components/ThemeScope/index.js +1 -0
- package/dist/esm/components/index.d.ts +3 -0
- package/dist/esm/components/index.js +3 -0
- package/dist/esm/constants/appearance.d.ts +22 -0
- package/dist/esm/constants/appearance.js +24 -0
- package/dist/esm/constants/colorScheme.d.ts +17 -0
- package/dist/esm/constants/colorScheme.js +20 -0
- package/dist/esm/constants/index.d.ts +2 -0
- package/dist/esm/constants/index.js +2 -0
- package/dist/esm/context/appearanceContext.d.ts +20 -0
- package/dist/esm/context/appearanceContext.js +18 -0
- package/dist/esm/context/index.d.ts +4 -0
- package/dist/esm/context/index.js +2 -0
- package/dist/esm/context/themeContext.d.ts +12 -0
- package/dist/esm/context/themeContext.js +11 -0
- package/dist/esm/hooks/index.d.ts +4 -0
- package/dist/esm/hooks/index.js +4 -0
- package/dist/esm/hooks/useApplyCustomTheme.d.ts +27 -0
- package/dist/esm/hooks/useApplyCustomTheme.js +36 -0
- package/dist/esm/hooks/useColorScheme.d.ts +37 -0
- package/dist/esm/hooks/useColorScheme.js +76 -0
- package/dist/esm/hooks/useIsomorphicLayoutEffect.d.ts +7 -0
- package/dist/esm/hooks/useIsomorphicLayoutEffect.js +13 -0
- package/dist/esm/hooks/useThemeClassnames.d.ts +11 -0
- package/dist/esm/hooks/useThemeClassnames.js +15 -0
- package/dist/esm/hooks/useThemeConfig.d.ts +24 -0
- package/dist/esm/hooks/useThemeConfig.js +12 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/keys.d.ts +4 -0
- package/dist/esm/keys.js +16 -0
- package/dist/esm/ssr.d.ts +15 -0
- package/dist/esm/ssr.js +15 -0
- package/dist/esm/store/globalStore.d.ts +29 -0
- package/dist/esm/store/globalStore.js +69 -0
- package/dist/esm/store/index.d.ts +1 -0
- package/dist/esm/store/index.js +1 -0
- package/dist/esm/types/appearance.d.ts +23 -0
- package/dist/esm/types/appearance.js +2 -0
- package/dist/esm/types/colorScheme.d.ts +5 -0
- package/dist/esm/types/colorScheme.js +1 -0
- package/dist/esm/types/index.d.ts +2 -0
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/utils/colorSchemeFromHeaders.d.ts +22 -0
- package/dist/esm/utils/colorSchemeFromHeaders.js +40 -0
- package/dist/esm/utils/colorSchemeStorage.d.ts +35 -0
- package/dist/esm/utils/colorSchemeStorage.js +81 -0
- package/dist/esm/utils/customTheme/buildBrandPaletteCss.d.ts +11 -0
- package/dist/esm/utils/customTheme/buildBrandPaletteCss.js +32 -0
- package/dist/esm/utils/customTheme/buildBrandPaletteVars.d.ts +11 -0
- package/dist/esm/utils/customTheme/buildBrandPaletteVars.js +39 -0
- package/dist/esm/utils/customTheme/color/apca.d.ts +4 -0
- package/dist/esm/utils/customTheme/color/apca.js +59 -0
- package/dist/esm/utils/customTheme/color/colorSpace.d.ts +5 -0
- package/dist/esm/utils/customTheme/color/colorSpace.js +68 -0
- package/dist/esm/utils/customTheme/color/conversions.d.ts +17 -0
- package/dist/esm/utils/customTheme/color/conversions.js +91 -0
- package/dist/esm/utils/customTheme/color/hex.d.ts +10 -0
- package/dist/esm/utils/customTheme/color/hex.js +29 -0
- package/dist/esm/utils/customTheme/color/index.d.ts +4 -0
- package/dist/esm/utils/customTheme/color/index.js +4 -0
- package/dist/esm/utils/customTheme/color/oklch.d.ts +3 -0
- package/dist/esm/utils/customTheme/color/oklch.js +18 -0
- package/dist/esm/utils/customTheme/color/types.d.ts +40 -0
- package/dist/esm/utils/customTheme/color/types.js +1 -0
- package/dist/esm/utils/customTheme/constants.d.ts +31 -0
- package/dist/esm/utils/customTheme/constants.js +46 -0
- package/dist/esm/utils/customTheme/generateBrandPalette.d.ts +10 -0
- package/dist/esm/utils/customTheme/generateBrandPalette.js +22 -0
- package/dist/esm/utils/customTheme/index.d.ts +4 -0
- package/dist/esm/utils/customTheme/index.js +4 -0
- package/dist/esm/utils/getThemeClassnames.d.ts +17 -0
- package/dist/esm/utils/getThemeClassnames.js +34 -0
- package/dist/esm/utils/index.d.ts +7 -0
- package/dist/esm/utils/index.js +7 -0
- package/dist/esm/utils/mergeAppearance.d.ts +7 -0
- package/dist/esm/utils/mergeAppearance.js +14 -0
- package/dist/esm/utils/resolveColorScheme.d.ts +7 -0
- package/dist/esm/utils/resolveColorScheme.js +12 -0
- package/dist/esm/utils/themeBootstrap.d.ts +12 -0
- package/dist/esm/utils/themeBootstrap.js +16 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +45 -0
- package/src/components/ChildThemeProvider/ChildThemeProvider.tsx +54 -0
- package/src/components/ChildThemeProvider/index.ts +1 -0
- package/src/components/RootThemeProvider/RootThemeProvider.tsx +87 -0
- package/src/components/RootThemeProvider/index.ts +1 -0
- package/src/components/ThemeProvider/ThemeProvider.tsx +41 -0
- package/src/components/ThemeProvider/index.ts +1 -0
- package/src/components/ThemeScope/ThemeScope.tsx +106 -0
- package/src/components/ThemeScope/index.ts +1 -0
- package/src/components/index.ts +3 -0
- package/src/constants/appearance.ts +27 -0
- package/src/constants/colorScheme.ts +23 -0
- package/src/constants/index.ts +2 -0
- package/src/context/appearanceContext.tsx +39 -0
- package/src/context/index.ts +4 -0
- package/src/context/themeContext.ts +18 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useApplyCustomTheme.ts +56 -0
- package/src/hooks/useColorScheme.ts +131 -0
- package/src/hooks/useIsomorphicLayoutEffect.ts +17 -0
- package/src/hooks/useThemeClassnames.ts +18 -0
- package/src/hooks/useThemeConfig.tsx +44 -0
- package/src/index.ts +7 -0
- package/src/keys.ts +18 -0
- package/src/ssr.ts +25 -0
- package/src/store/globalStore.ts +93 -0
- package/src/store/index.ts +1 -0
- package/src/types/appearance.ts +29 -0
- package/src/types/colorScheme.ts +7 -0
- package/src/types/index.ts +2 -0
- package/src/utils/colorSchemeFromHeaders.ts +57 -0
- package/src/utils/colorSchemeStorage.ts +117 -0
- package/src/utils/customTheme/buildBrandPaletteCss.ts +37 -0
- package/src/utils/customTheme/buildBrandPaletteVars.ts +56 -0
- package/src/utils/customTheme/color/apca.ts +74 -0
- package/src/utils/customTheme/color/colorSpace.ts +82 -0
- package/src/utils/customTheme/color/conversions.ts +113 -0
- package/src/utils/customTheme/color/hex.ts +39 -0
- package/src/utils/customTheme/color/index.ts +4 -0
- package/src/utils/customTheme/color/oklch.ts +22 -0
- package/src/utils/customTheme/color/types.ts +32 -0
- package/src/utils/customTheme/constants.ts +57 -0
- package/src/utils/customTheme/generateBrandPalette.ts +30 -0
- package/src/utils/customTheme/index.ts +4 -0
- package/src/utils/getThemeClassnames.ts +40 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/mergeAppearance.ts +16 -0
- package/src/utils/resolveColorScheme.ts +15 -0
- package/src/utils/themeBootstrap.ts +18 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Плотность раскладки. Класс `sn-comfort` / `sn-compact` / `sn-spacious`. */
|
|
2
|
+
export declare const DENSITY: {
|
|
3
|
+
readonly Comfort: "comfort";
|
|
4
|
+
readonly Compact: "compact";
|
|
5
|
+
readonly Spacious: "spacious";
|
|
6
|
+
};
|
|
7
|
+
/** Бренд. Класс `sn-brandA` / `sn-brandB` / `sn-brandC` / `sn-brandD` / `sn-brandE`. */
|
|
8
|
+
export declare const BRAND: {
|
|
9
|
+
readonly A: "brandA";
|
|
10
|
+
readonly B: "brandB";
|
|
11
|
+
readonly C: "brandC";
|
|
12
|
+
readonly D: "brandD";
|
|
13
|
+
readonly E: "brandE";
|
|
14
|
+
};
|
|
15
|
+
/** Роль бренда (палитра). Класс `sn-main` / `sn-alter` … */
|
|
16
|
+
export declare const BRAND_ROLE: {
|
|
17
|
+
readonly Main: "main";
|
|
18
|
+
readonly Alter: "alter";
|
|
19
|
+
readonly Alter2: "alter2";
|
|
20
|
+
readonly Alter3: "alter3";
|
|
21
|
+
readonly Alter4: "alter4";
|
|
22
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Оси оформления дизайн-системы, спроецированные на классы `sn-*` из `@cloud-ru/figma-variables`.
|
|
2
|
+
// Чистый модуль (без React/DOM) — реэкспортируется из `@cloud-ru/ds-theme/ssr` (RSC-safe).
|
|
3
|
+
/** Плотность раскладки. Класс `sn-comfort` / `sn-compact` / `sn-spacious`. */
|
|
4
|
+
export const DENSITY = {
|
|
5
|
+
Comfort: 'comfort',
|
|
6
|
+
Compact: 'compact',
|
|
7
|
+
Spacious: 'spacious',
|
|
8
|
+
};
|
|
9
|
+
/** Бренд. Класс `sn-brandA` / `sn-brandB` / `sn-brandC` / `sn-brandD` / `sn-brandE`. */
|
|
10
|
+
export const BRAND = {
|
|
11
|
+
A: 'brandA',
|
|
12
|
+
B: 'brandB',
|
|
13
|
+
C: 'brandC',
|
|
14
|
+
D: 'brandD',
|
|
15
|
+
E: 'brandE',
|
|
16
|
+
};
|
|
17
|
+
/** Роль бренда (палитра). Класс `sn-main` / `sn-alter` … */
|
|
18
|
+
export const BRAND_ROLE = {
|
|
19
|
+
Main: 'main',
|
|
20
|
+
Alter: 'alter',
|
|
21
|
+
Alter2: 'alter2',
|
|
22
|
+
Alter3: 'alter3',
|
|
23
|
+
Alter4: 'alter4',
|
|
24
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Разрешённая цветовая схема (то, что реально применяется на корень). */
|
|
2
|
+
export declare const COLOR_SCHEME: {
|
|
3
|
+
readonly Light: "light";
|
|
4
|
+
readonly Dark: "dark";
|
|
5
|
+
};
|
|
6
|
+
/** Пользовательский выбор: фиксированная схема или `system` (следовать `prefers-color-scheme`). */
|
|
7
|
+
export declare const THEME_OVERRIDE: {
|
|
8
|
+
readonly Light: "light";
|
|
9
|
+
readonly Dark: "dark";
|
|
10
|
+
readonly System: "system";
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Дефолтное имя ключа персиста override для опциональных адаптеров (cookie/localStorage) и
|
|
14
|
+
* SSR/bootstrap-хелперов. Namespace'нут под DS, чтобы не пересекаться с ключами хост-приложения.
|
|
15
|
+
* Конкретный адаптер может переопределить его через `storageKey`.
|
|
16
|
+
*/
|
|
17
|
+
export declare const THEME_OVERRIDE_STORAGE_KEY = "snack-uikit-theme";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Цветовая схема = класс `sn-light`/`sn-dark` на корне. Чистый модуль (RSC-safe), реэкспорт из `@cloud-ru/ds-theme/ssr`.
|
|
2
|
+
// Персиста по умолчанию нет: `useColorScheme` держит выбор in-memory, а cookie/localStorage подключает
|
|
3
|
+
// потребитель явным адаптером. Этот ключ — дефолтное имя для опциональных адаптеров и SSR/bootstrap-хелперов.
|
|
4
|
+
/** Разрешённая цветовая схема (то, что реально применяется на корень). */
|
|
5
|
+
export const COLOR_SCHEME = {
|
|
6
|
+
Light: 'light',
|
|
7
|
+
Dark: 'dark',
|
|
8
|
+
};
|
|
9
|
+
/** Пользовательский выбор: фиксированная схема или `system` (следовать `prefers-color-scheme`). */
|
|
10
|
+
export const THEME_OVERRIDE = {
|
|
11
|
+
Light: 'light',
|
|
12
|
+
Dark: 'dark',
|
|
13
|
+
System: 'system',
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Дефолтное имя ключа персиста override для опциональных адаптеров (cookie/localStorage) и
|
|
17
|
+
* SSR/bootstrap-хелперов. Namespace'нут под DS, чтобы не пересекаться с ключами хост-приложения.
|
|
18
|
+
* Конкретный адаптер может переопределить его через `storageKey`.
|
|
19
|
+
*/
|
|
20
|
+
export const THEME_OVERRIDE_STORAGE_KEY = 'snack-uikit-theme';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ExternalStore } from '@cloud-ru/ds-context-kit';
|
|
2
|
+
import { ThemeAppearance } from '../types/appearance.js';
|
|
3
|
+
/**
|
|
4
|
+
* Значение контекста оформления: слитые оси (`appearance`) + опциональный сеттер. Сеттер задаёт
|
|
5
|
+
* только корневой провайдер (`RootThemeProvider`) — у `ChildThemeProvider` он `undefined` (детям
|
|
6
|
+
* менять глобальное значение нельзя, они только локально переопределяют оси).
|
|
7
|
+
*/
|
|
8
|
+
export type ThemeAppearanceContextValue = {
|
|
9
|
+
appearance: ThemeAppearance;
|
|
10
|
+
setAppearance?: (patch: Partial<ThemeAppearance>) => void;
|
|
11
|
+
};
|
|
12
|
+
/** Внешний стор оформления (формат `useSyncExternalStore`). Mutable-global — см. `getGlobalThemeStore`. */
|
|
13
|
+
export type ThemeAppearanceStore = ExternalStore<ThemeAppearanceContextValue>;
|
|
14
|
+
declare const StoreProvider: ({ store, children }: {
|
|
15
|
+
store: ExternalStore<ThemeAppearanceContextValue>;
|
|
16
|
+
children: import("react").ReactNode;
|
|
17
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export { StoreProvider as ThemeAppearanceStoreProvider };
|
|
19
|
+
/** Возвращает ближайшее (уже слитое по цепочке провайдеров) значение оформления. Реактивно к стору. */
|
|
20
|
+
export declare function useThemeAppearance(): ThemeAppearanceContextValue;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createSharedStoreContext } from '@cloud-ru/ds-context-kit';
|
|
2
|
+
import { THEME_KEYS } from '../keys.js';
|
|
3
|
+
import { getGlobalThemeStore } from '../store/globalStore.js';
|
|
4
|
+
// Отдельный домен `theme-appearance` — НЕ пересекается с `providerKey('theme', 1)` старого
|
|
5
|
+
// `ThemeContext` (themeMap/changeTheme). Объект контекста — `Symbol.for`-синглтон, общий для всех
|
|
6
|
+
// версий пакета, поэтому потребитель в микрофронте читает ближайший провайдер независимо от версии.
|
|
7
|
+
//
|
|
8
|
+
// Дефолт контекста = глобальный singleton-стор оформления. Поэтому компонент, вызывающий
|
|
9
|
+
// `useThemeClassnames` (мобильная обёртка, `ChildThemeProvider`, портал вне `<body>`) БЕЗ
|
|
10
|
+
// `RootThemeProvider` в своём корне, реэмитит полный набор `sn-*` не с пустым оформлением
|
|
11
|
+
// (теряя `colorScheme`/`density`), а с тем, что shell выставил в `getGlobalThemeStore` из источника
|
|
12
|
+
// истины. Так микрофронту не нужен провайдер. Явный `RootThemeProvider` затеняет дефолт (back-compat).
|
|
13
|
+
const { StoreProvider, useStoreValue } = createSharedStoreContext(THEME_KEYS.context, getGlobalThemeStore().store);
|
|
14
|
+
export { StoreProvider as ThemeAppearanceStoreProvider };
|
|
15
|
+
/** Возвращает ближайшее (уже слитое по цепочке провайдеров) значение оформления. Реактивно к стору. */
|
|
16
|
+
export function useThemeAppearance() {
|
|
17
|
+
return useStoreValue();
|
|
18
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { useThemeAppearance } from './appearanceContext.js';
|
|
2
|
+
export type { ThemeAppearanceContextValue, ThemeAppearanceStore } from './appearanceContext.js';
|
|
3
|
+
export { useThemeContext } from './themeContext.js';
|
|
4
|
+
export type { ThemeContextType } from './themeContext.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type ThemeContextType = {
|
|
2
|
+
theme: string | undefined;
|
|
3
|
+
themeClassName: string | undefined;
|
|
4
|
+
changeTheme: ((theme: string) => void) | undefined;
|
|
5
|
+
};
|
|
6
|
+
export declare const ThemeValueProvider: {
|
|
7
|
+
({ value, children }: {
|
|
8
|
+
value: ThemeContextType;
|
|
9
|
+
children: import("react").ReactNode;
|
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
displayName: string;
|
|
12
|
+
}, useThemeContext: () => ThemeContextType;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createSharedContext, providerKey } from '@cloud-ru/ds-context-kit';
|
|
2
|
+
// Общий контекст темы через @cloud-ru/ds-context-kit (Symbol.for-синглтон, SSR-safe). `ThemeValueProvider`
|
|
3
|
+
// внутренний — публично доступны `ThemeProvider` (обёртка) и `useThemeContext`.
|
|
4
|
+
export const { Provider: ThemeValueProvider, useValue: useThemeContext } = createSharedContext({
|
|
5
|
+
key: providerKey('theme', 1),
|
|
6
|
+
defaultValue: {
|
|
7
|
+
theme: undefined,
|
|
8
|
+
themeClassName: undefined,
|
|
9
|
+
changeTheme: undefined,
|
|
10
|
+
},
|
|
11
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type UseApplyCustomThemeProps = {
|
|
2
|
+
/** Бренд-цвет потребителя (hex `#rrggbb`). Из него генерируется бренд-палитра. */
|
|
3
|
+
color: string;
|
|
4
|
+
/** Применять ли кастомную палитру. При `false` `<style>` не инжектится (а ранее добавленный снимается). */
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* CSS-скоуп — селектор корня поддерева (напр. `#app`, `[data-x]`). Без него правило глобальное:
|
|
8
|
+
* переопределяет бренд-классы на всей странице (white-label в корне приложения — покрывает и порталы,
|
|
9
|
+
* и переэмиченные внутренние обёртки). Со скоупом область ограничена его поддеревом.
|
|
10
|
+
*/
|
|
11
|
+
scope?: string;
|
|
12
|
+
/** CSP-`nonce` для инжектируемого `<style>`. */
|
|
13
|
+
nonce?: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Применяет кастомный бренд-цвет: генерирует из `color` бренд-палитру и инжектит `<style>`,
|
|
17
|
+
* переопределяющий её на бренд-классах (`.sn-brandA/B/C/D/E`), а не inline на одном элементе — поэтому
|
|
18
|
+
* цвет переживает переэмиты `sn-*` вложенными компонентами и доходит до порталов. Семантический слой
|
|
19
|
+
* каскадит из палитры, красятся обе схемы.
|
|
20
|
+
*
|
|
21
|
+
* Императивная (обычно app-root) альтернатива декларативному пропу `brandColor` у `RootThemeProvider`.
|
|
22
|
+
*
|
|
23
|
+
* ```tsx
|
|
24
|
+
* useApplyCustomTheme({ color: brand.primaryColor, enabled: Boolean(brand), nonce });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function useApplyCustomTheme({ color, enabled, scope, nonce }: UseApplyCustomThemeProps): void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { buildBrandPaletteCss } from '../utils/customTheme/index.js';
|
|
3
|
+
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect.js';
|
|
4
|
+
/**
|
|
5
|
+
* Применяет кастомный бренд-цвет: генерирует из `color` бренд-палитру и инжектит `<style>`,
|
|
6
|
+
* переопределяющий её на бренд-классах (`.sn-brandA/B/C/D/E`), а не inline на одном элементе — поэтому
|
|
7
|
+
* цвет переживает переэмиты `sn-*` вложенными компонентами и доходит до порталов. Семантический слой
|
|
8
|
+
* каскадит из палитры, красятся обе схемы.
|
|
9
|
+
*
|
|
10
|
+
* Императивная (обычно app-root) альтернатива декларативному пропу `brandColor` у `RootThemeProvider`.
|
|
11
|
+
*
|
|
12
|
+
* ```tsx
|
|
13
|
+
* useApplyCustomTheme({ color: brand.primaryColor, enabled: Boolean(brand), nonce });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function useApplyCustomTheme({ color, enabled = true, scope, nonce }) {
|
|
17
|
+
const css = useMemo(() => buildBrandPaletteCss(color, scope), [color, scope]);
|
|
18
|
+
// Layout-эффект (не `useEffect`): `<style>` добавляем в `head` синхронно до пейнта, иначе первый кадр
|
|
19
|
+
// успевает отрисоваться с дефолтным акцентом и виден проблеск старого цвета при смене бренд-цвета.
|
|
20
|
+
/* eslint-disable @cloud-ru/ssr-safe-react/domApi -- DOM трогаем только в layout-эффекте под guard `typeof document` */
|
|
21
|
+
useIsomorphicLayoutEffect(() => {
|
|
22
|
+
if (!enabled || !css || typeof document === 'undefined') {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
const styleElement = document.createElement('style');
|
|
26
|
+
if (nonce) {
|
|
27
|
+
styleElement.setAttribute('nonce', nonce);
|
|
28
|
+
}
|
|
29
|
+
styleElement.textContent = css;
|
|
30
|
+
document.head.appendChild(styleElement);
|
|
31
|
+
return () => {
|
|
32
|
+
styleElement.remove();
|
|
33
|
+
};
|
|
34
|
+
}, [css, enabled, nonce]);
|
|
35
|
+
/* eslint-enable @cloud-ru/ssr-safe-react/domApi */
|
|
36
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ColorScheme, ThemeOverride } from '../types/colorScheme.js';
|
|
2
|
+
import { ColorSchemeStorage } from '../utils/colorSchemeStorage.js';
|
|
3
|
+
export type UseColorSchemeOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* Server-resolved начальный override (например, `getThemeOverrideFromHeaders(headers)` из cookie
|
|
6
|
+
* или из бэкенд-сессии). Делает первый рендер детерминированным и совпадающим с SSR — без
|
|
7
|
+
* hydration mismatch и без прыжка подсветки переключателя. Если не задан — старт с `system`.
|
|
8
|
+
*/
|
|
9
|
+
initialOverride?: ThemeOverride;
|
|
10
|
+
/**
|
|
11
|
+
* Адаптер персиста. По умолчанию — in-memory (без персиста между перезагрузками): DS не пишет в
|
|
12
|
+
* cookie/localStorage сам. Подключите явно: `createCookieColorSchemeStorage()` (no-flash SSR) или
|
|
13
|
+
* собственный адаптер (localStorage / бэкенд-сессия).
|
|
14
|
+
*/
|
|
15
|
+
storage?: ColorSchemeStorage;
|
|
16
|
+
/** Корень, на который вешается `sn-light`/`sn-dark`. По умолчанию `<html>`. */
|
|
17
|
+
target?: HTMLElement;
|
|
18
|
+
};
|
|
19
|
+
export type UseColorSchemeResult = {
|
|
20
|
+
/** Итоговая применённая схема (override ?? система). */
|
|
21
|
+
colorScheme: ColorScheme;
|
|
22
|
+
/** Текущий выбор пользователя: `light` / `dark` / `system`. */
|
|
23
|
+
override: ThemeOverride;
|
|
24
|
+
/** Системная тема (`prefers-color-scheme: dark`). */
|
|
25
|
+
systemPrefersDark: boolean;
|
|
26
|
+
/** Сменить выбор: персистит через `storage.write` (cookie / бэкенд). */
|
|
27
|
+
setOverride(next: ThemeOverride): void;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Управляет цветовой схемой DS: резолвит `override ?? prefers-color-scheme`, вешает `sn-light`/`sn-dark`
|
|
31
|
+
* на корень, реагирует на живое переключение темы ОС (`matchMedia`) и внешние изменения override
|
|
32
|
+
* (`storage.subscribe` — кросс-таб / бэкенд push). No-flash на reload обеспечивает inline
|
|
33
|
+
* `getThemeBootstrapScript` в `<head>` (а на SSR — корректный класс из `getColorSchemeFromHeaders`);
|
|
34
|
+
* хук синхронизирует состояние и переключатель override.
|
|
35
|
+
* @function React hook
|
|
36
|
+
*/
|
|
37
|
+
export declare function useColorScheme(options?: UseColorSchemeOptions): UseColorSchemeResult;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { COLOR_SCHEME, THEME_OVERRIDE } from '../constants/colorScheme.js';
|
|
4
|
+
import { createInMemoryColorSchemeStorage } from '../utils/colorSchemeStorage.js';
|
|
5
|
+
import { resolveColorScheme } from '../utils/resolveColorScheme.js';
|
|
6
|
+
/* eslint-disable @cloud-ru/ssr-safe-react/domApi -- guarded by isBrowser(); хук помечен 'use client' */
|
|
7
|
+
function isBrowser() {
|
|
8
|
+
return Boolean(typeof window !== 'undefined' && window.document && window.document.createElement);
|
|
9
|
+
}
|
|
10
|
+
const SYSTEM_DARK_QUERY = '(prefers-color-scheme: dark)';
|
|
11
|
+
function getSystemPrefersDark() {
|
|
12
|
+
return isBrowser() && window.matchMedia(SYSTEM_DARK_QUERY).matches;
|
|
13
|
+
}
|
|
14
|
+
function applyColorScheme(target, colorScheme) {
|
|
15
|
+
target.classList.toggle('sn-dark', colorScheme === COLOR_SCHEME.Dark);
|
|
16
|
+
target.classList.toggle('sn-light', colorScheme === COLOR_SCHEME.Light);
|
|
17
|
+
}
|
|
18
|
+
// Общий синглтон in-memory-адаптера: несколько `useColorScheme` без своего `storage` смотрят в один
|
|
19
|
+
// источник, поэтому переключатели в разных поддеревьях синхронны в пределах сессии.
|
|
20
|
+
const defaultColorSchemeStorage = createInMemoryColorSchemeStorage();
|
|
21
|
+
/**
|
|
22
|
+
* Управляет цветовой схемой DS: резолвит `override ?? prefers-color-scheme`, вешает `sn-light`/`sn-dark`
|
|
23
|
+
* на корень, реагирует на живое переключение темы ОС (`matchMedia`) и внешние изменения override
|
|
24
|
+
* (`storage.subscribe` — кросс-таб / бэкенд push). No-flash на reload обеспечивает inline
|
|
25
|
+
* `getThemeBootstrapScript` в `<head>` (а на SSR — корректный класс из `getColorSchemeFromHeaders`);
|
|
26
|
+
* хук синхронизирует состояние и переключатель override.
|
|
27
|
+
* @function React hook
|
|
28
|
+
*/
|
|
29
|
+
export function useColorScheme(options) {
|
|
30
|
+
const { initialOverride, target } = options ?? {};
|
|
31
|
+
const providedStorage = options?.storage;
|
|
32
|
+
// Дефолт — общий in-memory-адаптер: DS не пишет в cookie/localStorage без явного `storage`.
|
|
33
|
+
const storage = useMemo(() => providedStorage ?? defaultColorSchemeStorage, [providedStorage]);
|
|
34
|
+
// override инициализируется СИНХРОННО из источника правды, чтобы SegmentControl не «прыгал» с
|
|
35
|
+
// System на реальный выбор после mount: `initialOverride` (server-resolved — бэкенд-сессия / SSR
|
|
36
|
+
// cookie, authoritative) → синхронное чтение store (`storage.read`) → `system`.
|
|
37
|
+
// SSR-консистентность: на сервере `storage.read()` обязан вернуть undefined (in-memory- и cookie-
|
|
38
|
+
// адаптеры так и делают), поэтому и сервер, и первый клиентский рендер берут одно значение — мисматча
|
|
39
|
+
// нет. В чистом клиенте с персист-адаптером (cookie/localStorage) `read()` отдаёт сохранённый выбор
|
|
40
|
+
// сразу при первом рендере, без прыжка; дефолтный in-memory стартует с `system`.
|
|
41
|
+
const [override, setOverrideState] = useState(() => initialOverride ?? storage.read() ?? THEME_OVERRIDE.System);
|
|
42
|
+
const [systemPrefersDark, setSystemPrefersDark] = useState(false);
|
|
43
|
+
const [mounted, setMounted] = useState(false);
|
|
44
|
+
// matchMedia нельзя читать в initializer (на SSR-хосте рассинхронит colorScheme-readout) — системную
|
|
45
|
+
// тему добираем после mount. override уже корректен из initializer, его здесь перечитывать не нужно.
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
setSystemPrefersDark(getSystemPrefersDark());
|
|
48
|
+
setMounted(true);
|
|
49
|
+
}, []);
|
|
50
|
+
const colorScheme = resolveColorScheme(override, systemPrefersDark);
|
|
51
|
+
// Применяем класс к корню ТОЛЬКО после mount: до этого корректный класс уже стоит из SSR/bootstrap,
|
|
52
|
+
// и детерминированный первый рендер не должен его перетереть (иначе моргание).
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!mounted || !isBrowser()) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
applyColorScheme(target ?? document.documentElement, colorScheme);
|
|
58
|
+
}, [mounted, colorScheme, target]);
|
|
59
|
+
// Живое переключение темы ОС.
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (!isBrowser()) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const mql = window.matchMedia(SYSTEM_DARK_QUERY);
|
|
65
|
+
const onChange = (event) => setSystemPrefersDark(event.matches);
|
|
66
|
+
mql.addEventListener('change', onChange);
|
|
67
|
+
return () => mql.removeEventListener('change', onChange);
|
|
68
|
+
}, []);
|
|
69
|
+
// Внешняя синхронизация override (кросс-таб через BroadcastChannel / бэкенд push).
|
|
70
|
+
useEffect(() => storage.subscribe(() => setOverrideState(storage.read() ?? THEME_OVERRIDE.System)), [storage]);
|
|
71
|
+
const setOverride = useCallback((next) => {
|
|
72
|
+
setOverrideState(next);
|
|
73
|
+
storage.write(next);
|
|
74
|
+
}, [storage]);
|
|
75
|
+
return { colorScheme, override, systemPrefersDark, setOverride };
|
|
76
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { useLayoutEffect } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* `useLayoutEffect`, безопасный для SSR: на клиенте — настоящий `useLayoutEffect` (применяет эффект
|
|
4
|
+
* синхронно до пейнта, поэтому инъекция бренд-`<style>` не даёт кадра с дефолтным акцентом — «моргания»),
|
|
5
|
+
* на сервере — `useEffect` (сырой `useLayoutEffect` на сервере варнит и всё равно не выполняется).
|
|
6
|
+
*/
|
|
7
|
+
export declare const useIsomorphicLayoutEffect: typeof useLayoutEffect;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// eslint-disable-next-line no-restricted-imports -- единственная точка, где берём сырой useLayoutEffect
|
|
2
|
+
import { useEffect, useLayoutEffect } from 'react';
|
|
3
|
+
/* eslint-disable @cloud-ru/ssr-safe-react/domApi -- это и есть SSR-guard, DOM читается только для детекта браузера */
|
|
4
|
+
function isBrowser() {
|
|
5
|
+
return Boolean(typeof window !== 'undefined' && window.document && window.document.createElement);
|
|
6
|
+
}
|
|
7
|
+
/* eslint-enable @cloud-ru/ssr-safe-react/domApi */
|
|
8
|
+
/**
|
|
9
|
+
* `useLayoutEffect`, безопасный для SSR: на клиенте — настоящий `useLayoutEffect` (применяет эффект
|
|
10
|
+
* синхронно до пейнта, поэтому инъекция бренд-`<style>` не даёт кадра с дефолтным акцентом — «моргания»),
|
|
11
|
+
* на сервере — `useEffect` (сырой `useLayoutEffect` на сервере варнит и всё равно не выполняется).
|
|
12
|
+
*/
|
|
13
|
+
export const useIsomorphicLayoutEffect = isBrowser() ? useLayoutEffect : useEffect;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ThemeAppearance } from '../types/appearance.js';
|
|
2
|
+
/**
|
|
3
|
+
* Возвращает полный набор `sn-*` классов = ближайшее оформление из контекста (`RootThemeProvider` +
|
|
4
|
+
* цепочка `ChildThemeProvider`) ⊕ переданные `overrides`. Навешивается на DOM-границу компонента,
|
|
5
|
+
* который хочет переопределить ось (например, мобильная обёртка с `density: 'comfort'`).
|
|
6
|
+
*
|
|
7
|
+
* Поскольку набор включает текущий `colorScheme`/`brand`/`brandRole` из контекста, такая обёртка —
|
|
8
|
+
* самосогласованный scope и трекает переключение темы. Без провайдера в дереве оформление пустое,
|
|
9
|
+
* и поведение совпадает со старым `getThemeClassnames({ density })`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useThemeClassnames(overrides?: Partial<ThemeAppearance>): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useThemeAppearance } from '../context/appearanceContext.js';
|
|
2
|
+
import { getThemeClassnames } from '../utils/getThemeClassnames.js';
|
|
3
|
+
/**
|
|
4
|
+
* Возвращает полный набор `sn-*` классов = ближайшее оформление из контекста (`RootThemeProvider` +
|
|
5
|
+
* цепочка `ChildThemeProvider`) ⊕ переданные `overrides`. Навешивается на DOM-границу компонента,
|
|
6
|
+
* который хочет переопределить ось (например, мобильная обёртка с `density: 'comfort'`).
|
|
7
|
+
*
|
|
8
|
+
* Поскольку набор включает текущий `colorScheme`/`brand`/`brandRole` из контекста, такая обёртка —
|
|
9
|
+
* самосогласованный scope и трекает переключение темы. Без провайдера в дереве оформление пустое,
|
|
10
|
+
* и поведение совпадает со старым `getThemeClassnames({ density })`.
|
|
11
|
+
*/
|
|
12
|
+
export function useThemeClassnames(overrides) {
|
|
13
|
+
const { appearance } = useThemeAppearance();
|
|
14
|
+
return getThemeClassnames({ ...appearance, ...overrides });
|
|
15
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type UseThemePropsWithDefaultTheme<T extends string> = {
|
|
2
|
+
themeMap: Record<T, string>;
|
|
3
|
+
defaultTheme: T;
|
|
4
|
+
};
|
|
5
|
+
type UseThemeProps<T extends string> = {
|
|
6
|
+
/**
|
|
7
|
+
* Объект с указанием соответсвия темы и css-класса
|
|
8
|
+
*/
|
|
9
|
+
themeMap: Record<T, string>;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Хук для работы с темами
|
|
13
|
+
*/
|
|
14
|
+
export declare function useThemeConfig<T extends string>(props: UseThemeProps<T>): {
|
|
15
|
+
theme: T | undefined;
|
|
16
|
+
themeClassName: string | undefined;
|
|
17
|
+
changeTheme(theme: T): void;
|
|
18
|
+
};
|
|
19
|
+
export declare function useThemeConfig<T extends string>(props: UseThemePropsWithDefaultTheme<T>): {
|
|
20
|
+
theme: T;
|
|
21
|
+
themeClassName: string;
|
|
22
|
+
changeTheme(theme: T): void;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
function hasDefaultTheme(props) {
|
|
3
|
+
return Boolean(props.defaultTheme);
|
|
4
|
+
}
|
|
5
|
+
export function useThemeConfig(props) {
|
|
6
|
+
const [theme, setTheme] = useState(hasDefaultTheme(props) ? props.defaultTheme : undefined);
|
|
7
|
+
return {
|
|
8
|
+
theme,
|
|
9
|
+
themeClassName: theme ? props.themeMap[theme] : undefined,
|
|
10
|
+
changeTheme: setTheme,
|
|
11
|
+
};
|
|
12
|
+
}
|
package/dist/esm/keys.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { providerKey } from '@cloud-ru/ds-context-kit';
|
|
2
|
+
/**
|
|
3
|
+
* `Symbol.for`-ключи домена theme-appearance — обе системы синглтонов в одном месте:
|
|
4
|
+
* - `context` — объект React-контекста оформления (через `providerKey` → dev-warn о смешанных версиях);
|
|
5
|
+
* - `store` — глобальный мутабельный стор оформления (кросс-root мост хост→MFE).
|
|
6
|
+
*
|
|
7
|
+
* Одна контракт-версия на домен бампается ТОЛЬКО при несовместимом сломе формы значения и двигает
|
|
8
|
+
* ОБА ключа вместе. Ортогонально мажору ПАКЕТА. Строки менять НЕЛЬЗЯ (форк синглтона = случайный
|
|
9
|
+
* `:v2`). НЕ путать с доменом `theme` старого `ThemeContext` (themeMap/changeTheme). См.
|
|
10
|
+
* providers-standard.md.
|
|
11
|
+
*/
|
|
12
|
+
const CONTRACT_VERSION = 1;
|
|
13
|
+
export const THEME_KEYS = {
|
|
14
|
+
context: providerKey('theme-appearance', CONTRACT_VERSION),
|
|
15
|
+
store: `@cloud-ru/ds:global-theme-store:v${CONTRACT_VERSION}`,
|
|
16
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { BRAND, BRAND_ROLE, DENSITY } from './constants/appearance.js';
|
|
2
|
+
export { COLOR_SCHEME, THEME_OVERRIDE, THEME_OVERRIDE_STORAGE_KEY } from './constants/colorScheme.js';
|
|
3
|
+
export type { Brand, BrandRole, Density, ThemeAppearance } from './types/appearance.js';
|
|
4
|
+
export type { ColorScheme, ThemeOverride } from './types/colorScheme.js';
|
|
5
|
+
export { mergeAppearance } from './utils/mergeAppearance.js';
|
|
6
|
+
export { getThemeClassnameList, getThemeClassnames } from './utils/getThemeClassnames.js';
|
|
7
|
+
export { resolveColorScheme } from './utils/resolveColorScheme.js';
|
|
8
|
+
export { getColorSchemeFromHeaders, getThemeOverrideFromHeaders } from './utils/colorSchemeFromHeaders.js';
|
|
9
|
+
export { getThemeBootstrapScript } from './utils/themeBootstrap.js';
|
|
10
|
+
export { generateBrandPalette } from './utils/customTheme/generateBrandPalette.js';
|
|
11
|
+
export type { BrandPalette } from './utils/customTheme/generateBrandPalette.js';
|
|
12
|
+
export { buildBrandPaletteVars } from './utils/customTheme/buildBrandPaletteVars.js';
|
|
13
|
+
export { buildBrandPaletteCss } from './utils/customTheme/buildBrandPaletteCss.js';
|
|
14
|
+
export { BASE_BRAND_PALETTE, BRAND_PRIMARY_TONES, BRAND_PRIMARY_VAR_PREFIX, PRIMARY_ACCENT_TONE, } from './utils/customTheme/constants.js';
|
|
15
|
+
export type { BrandPrimaryTone } from './utils/customTheme/constants.js';
|
package/dist/esm/ssr.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// SSR-безопасный субпуть `@cloud-ru/ds-theme/ssr`: только чистые символы (без React-контекста/хуков),
|
|
2
|
+
// чтобы импорт в React Server Components не тянул `createContext`. Зеркало `@cloud-ru/ds-adaptive/ssr`.
|
|
3
|
+
export { BRAND, BRAND_ROLE, DENSITY } from './constants/appearance.js';
|
|
4
|
+
export { COLOR_SCHEME, THEME_OVERRIDE, THEME_OVERRIDE_STORAGE_KEY } from './constants/colorScheme.js';
|
|
5
|
+
export { mergeAppearance } from './utils/mergeAppearance.js';
|
|
6
|
+
export { getThemeClassnameList, getThemeClassnames } from './utils/getThemeClassnames.js';
|
|
7
|
+
export { resolveColorScheme } from './utils/resolveColorScheme.js';
|
|
8
|
+
export { getColorSchemeFromHeaders, getThemeOverrideFromHeaders } from './utils/colorSchemeFromHeaders.js';
|
|
9
|
+
export { getThemeBootstrapScript } from './utils/themeBootstrap.js';
|
|
10
|
+
// Кастомный бренд-цвет — чистые (без React/DOM) генератор палитры и сборщик CSS-переменных, чтобы
|
|
11
|
+
// SSR/RSC мог инжектить `--sn-brand-color-primary-*` строкой и убрать мигание до гидрации.
|
|
12
|
+
export { generateBrandPalette } from './utils/customTheme/generateBrandPalette.js';
|
|
13
|
+
export { buildBrandPaletteVars } from './utils/customTheme/buildBrandPaletteVars.js';
|
|
14
|
+
export { buildBrandPaletteCss } from './utils/customTheme/buildBrandPaletteCss.js';
|
|
15
|
+
export { BASE_BRAND_PALETTE, BRAND_PRIMARY_TONES, BRAND_PRIMARY_VAR_PREFIX, PRIMARY_ACCENT_TONE, } from './utils/customTheme/constants.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ThemeAppearanceStore } from '../context/appearanceContext.js';
|
|
2
|
+
import { ThemeAppearance } from '../types/appearance.js';
|
|
3
|
+
export type GlobalThemeStore = {
|
|
4
|
+
/** Стор для `<RootThemeProvider store={...} />`. */
|
|
5
|
+
store: ThemeAppearanceStore;
|
|
6
|
+
/** Текущее оформление. */
|
|
7
|
+
getAppearance(): ThemeAppearance;
|
|
8
|
+
/** Слить патч в оформление и уведомить все подписанные провайдеры. */
|
|
9
|
+
setAppearance(patch: Partial<ThemeAppearance>): void;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Глобальный singleton-стор оформления, общий для всех React-корней процесса: микрофронтов
|
|
13
|
+
* single-spa, островков Astro и любых сценариев, где один `RootThemeProvider` нельзя поставить
|
|
14
|
+
* общим предком в одном дереве. Хранится в `globalThis` через `Symbol.for`, поэтому любой модуль
|
|
15
|
+
* получает один экземпляр без проброса по импортам и переживает несколько копий пакета.
|
|
16
|
+
*
|
|
17
|
+
* Shell контейнера меняет оформление через `setAppearance({ colorScheme, density, ... })` — все
|
|
18
|
+
* подписанные `RootThemeProvider` реэмитят полный набор `sn-*` классов. Когда у приложения один
|
|
19
|
+
* React-корень — используйте `<RootThemeProvider value={…} />`, этот хелпер нужен только для multi-root.
|
|
20
|
+
*
|
|
21
|
+
* ```tsx
|
|
22
|
+
* // там, где меняется тема (один раз):
|
|
23
|
+
* getGlobalThemeStore().setAppearance({ colorScheme });
|
|
24
|
+
*
|
|
25
|
+
* // в каждом независимом корне:
|
|
26
|
+
* <RootThemeProvider store={getGlobalThemeStore().store} rootRef={htmlRef}>{root}</RootThemeProvider>;
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function getGlobalThemeStore(): GlobalThemeStore;
|