From 01a8a59349eeede031f3ae0b01f160614edcd84b Mon Sep 17 00:00:00 2001 From: CC Worker Date: Sun, 31 May 2026 22:56:31 +0000 Subject: [PATCH 1/2] feat: bridge --cc-* tokens to tldraw --color-* variable layer; fix first-render theme fallback --- src/App.tsx | 2 +- src/utils/tldraw/tldraw.css | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 969d435..b07119e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -20,7 +20,7 @@ const App = React.memo(() => { const appTheme = useMemo(() => { let mode: 'light' | 'dark'; - if (tldrawPreferences?.colorScheme === 'system') { + if (tldrawPreferences?.colorScheme === 'system' || tldrawPreferences == null) { mode = prefersDarkMode ? 'dark' : 'light'; } else { mode = tldrawPreferences?.colorScheme === 'dark' ? 'dark' : 'light'; diff --git a/src/utils/tldraw/tldraw.css b/src/utils/tldraw/tldraw.css index c32e4b4..f69ea8f 100644 --- a/src/utils/tldraw/tldraw.css +++ b/src/utils/tldraw/tldraw.css @@ -1,2 +1,12 @@ @import url("@tldraw/tldraw/tldraw.css"); @import url('./cc-design-system.css'); + +.tl-container { + --color-panel: var(--cc-bg-panel); + --color-text: var(--cc-text-primary); + --color-muted: var(--cc-border); + --color-muted-1: var(--cc-border-strong); + --color-background: var(--cc-bg-canvas); + --color-selected: var(--cc-selected); + --color-accent: var(--cc-action-primary); +} From 489c2208c564ddf31859285643a8e19688150f51 Mon Sep 17 00:00:00 2001 From: CC Worker Date: Mon, 1 Jun 2026 00:47:24 +0000 Subject: [PATCH 2/2] 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(() => { +