Files
flxn-app/src/lib/mantine/color-scheme-provider.tsx
T
2026-08-23 17:17:04 -07:00

62 lines
1.8 KiB
TypeScript

import { useAuth } from "@/contexts/auth-context";
import { useMantineColorScheme } from "@mantine/core";
import { useEffect, useRef } from "react";
import { getTheme } from "@/themes/registry";
import { resolveChromeColors } from "@/themes/chrome";
import { setBaseThemeColor } from "./theme-colors";
const ColorSchemeProvider = ({ children }: { children: React.ReactNode }) => {
const {
metadata: { colorScheme, theme },
} = useAuth();
const { colorScheme: currentScheme, setColorScheme } =
useMantineColorScheme();
// Mantine recreates setColorScheme every render; calling it redundantly
// triggers its global transition-suppression flash, so ref it and only
// call on an actual value change.
const setColorSchemeRef = useRef(setColorScheme);
setColorSchemeRef.current = setColorScheme;
const manifest = getTheme(theme);
const forcedScheme =
manifest.colorSchemes === "both" ? undefined : manifest.colorSchemes;
useEffect(() => {
const chrome = resolveChromeColors(manifest);
if (forcedScheme) {
setBaseThemeColor(chrome[forcedScheme].base);
return;
}
if (!colorScheme) return;
if (colorScheme !== currentScheme) {
setColorSchemeRef.current(colorScheme);
}
const media = window.matchMedia("(prefers-color-scheme: dark)");
const applyThemeColor = () => {
const resolved =
colorScheme === "auto"
? media.matches
? "dark"
: "light"
: colorScheme;
setBaseThemeColor(chrome[resolved].base);
};
applyThemeColor();
if (colorScheme === "auto") {
media.addEventListener("change", applyThemeColor);
return () => media.removeEventListener("change", applyThemeColor);
}
}, [colorScheme, currentScheme, manifest, forcedScheme]);
return children;
};
export default ColorSchemeProvider;