1import { HTML_RENDER_DEFAULT_FONTS, htmlRenderTheme } from "@t3tools/shared/htmlRender";
2import { useSyncExternalStore } from "react";
3
4import { appearanceFontStack } from "../appearanceFonts";
5import {
6 getStandardThemeColors,
7 getThemeColorsForMode,
8 getThemeDefinition,
9 resolveThemeHalf,
10 subscribeToCustomThemes,
11 themeColorToHex,
12 type ThemeAppearance,
13 type ThemeHalves,
14 type ThemePreference,
15} from "../themePalette";
16import { useClientSettings } from "./useSettings";
17import { useTheme } from "./useTheme";
18
19function resolveActiveThemeColors(
20 theme: ThemePreference,
21 halves: ThemeHalves | null,
22 appearance: ThemeAppearance,
23) {
24 const definition = getThemeDefinition(resolveThemeHalf(theme, halves, appearance));
25 return definition === null
26 ? getStandardThemeColors(appearance)
27 : (getThemeColorsForMode(definition, appearance) ?? definition.colors);
28}
29
30export function useHtmlRenderTheme() {
31 const { theme, resolvedTheme, themeHalves } = useTheme();
32 // Custom and published palettes can be edited in place, under an unchanged preference.
33 const colors = useSyncExternalStore(
34 subscribeToCustomThemes,
35 () => resolveActiveThemeColors(theme, themeHalves, resolvedTheme),
36 () => getStandardThemeColors(resolvedTheme),
37 );
38 const sans = useClientSettings((settings) => settings.fontFamilySans);
39 const mono = useClientSettings((settings) => settings.fontFamilyCode);
40 return htmlRenderTheme(
41 Object.fromEntries(
42 Object.entries(colors).map(([role, color]) => [role, themeColorToHex(color) ?? color]),
43 ) as typeof colors,
44 resolvedTheme,
45 {
46 sans: appearanceFontStack(sans, HTML_RENDER_DEFAULT_FONTS.sans),
47 mono: appearanceFontStack(mono, HTML_RENDER_DEFAULT_FONTS.mono),
48 },
49 );
50}