From 489c2208c564ddf31859285643a8e19688150f51 Mon Sep 17 00:00:00 2001 From: CC Worker Date: Mon, 1 Jun 2026 00:47:24 +0000 Subject: [PATCH] fix: add DarkModeSync to propagate tldraw dark mode to document root tldraw v3.6 sets tl-theme__dark class on .tl-container, not data-color-mode on document.documentElement. DarkModeSync lives inside TLDrawProvider and mirrors the active color scheme to [data-color-mode] on , activating --cc-* token overrides in cc-design-system.css globally. --- src/App.tsx | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index b07119e..6c1d22a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import { BrowserRouter } from 'react-router-dom'; -import { useMemo } from 'react'; +import { useMemo, useEffect } from 'react'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import { useTLDraw } from './contexts/TLDrawContext'; import { theme } from './services/themeService'; @@ -10,26 +10,40 @@ import AppRoutes from './AppRoutes'; import { ErrorBoundary } from './components/ErrorBoundary'; import React from 'react'; -const App = React.memo(() => { +/** + * Syncs tldraw's color scheme to data-color-mode on . + * Must live inside TLDrawProvider so useTLDraw() reads live preferences. + * This activates the [data-color-mode="dark"] overrides in cc-design-system.css. + * tldraw itself uses tl-theme__dark class on .tl-container — we mirror that + * to the document root so --cc-* token overrides apply globally. + */ +const DarkModeSync: React.FC = () => { const { tldrawPreferences } = useTLDraw(); + const prefersDarkMode = + typeof window !== 'undefined' && + window.matchMedia('(prefers-color-scheme: dark)').matches; + useEffect(() => { + const scheme = tldrawPreferences?.colorScheme ?? 'system'; + const isDark = scheme === 'dark' || (scheme === 'system' && prefersDarkMode); + document.documentElement.setAttribute('data-color-mode', isDark ? 'dark' : 'light'); + }, [tldrawPreferences?.colorScheme, prefersDarkMode]); + + return null; +}; + +const App = React.memo(() => { const prefersDarkMode = typeof window !== 'undefined' && window.matchMedia('(prefers-color-scheme: dark)').matches; const appTheme = useMemo(() => { - let mode: 'light' | 'dark'; - - if (tldrawPreferences?.colorScheme === 'system' || tldrawPreferences == null) { - mode = prefersDarkMode ? 'dark' : 'light'; - } else { - mode = tldrawPreferences?.colorScheme === 'dark' ? 'dark' : 'light'; - } - - return createTheme({ - palette: { mode }, - }); - }, [tldrawPreferences?.colorScheme, prefersDarkMode]); + // App is outside TLDrawProvider so tldrawPreferences is always null here. + // Theme defaults to OS preference; DarkModeSync (inside TLDrawProvider) handles + // updating data-color-mode once tldraw preferences are loaded. + const mode = prefersDarkMode ? 'dark' : 'light'; + return createTheme({ palette: { mode } }); + }, [prefersDarkMode]); return ( @@ -37,6 +51,7 @@ const App = React.memo(() => { +