From 1a8ef652e6e7f383ce9b1294b90270e51535a3c2 Mon Sep 17 00:00:00 2001 From: Siddharth Kshetrapal Date: Tue, 7 Oct 2025 13:36:46 +0200 Subject: [PATCH 01/16] tmp --- examples/nextjs/src/app/layout.tsx | 3 +- packages/react/src/ThemeProvider.tsx | 3 + packages/react/src/index.ts | 2 + .../src/components/ThemeProvider.tsx | 243 ++++++++++++++++++ 4 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 packages/styled-react/src/components/ThemeProvider.tsx diff --git a/examples/nextjs/src/app/layout.tsx b/examples/nextjs/src/app/layout.tsx index ec8ff0f19a7..d193b551f09 100644 --- a/examples/nextjs/src/app/layout.tsx +++ b/examples/nextjs/src/app/layout.tsx @@ -1,5 +1,6 @@ import './global.css' -import {BaseStyles, ThemeProvider} from '@primer/react' +import {ThemeProvider} from '@primer/styled-react' +import {BaseStyles} from '@primer/react' import {StyledComponentsRegistry} from './registry' export const metadata = { diff --git a/packages/react/src/ThemeProvider.tsx b/packages/react/src/ThemeProvider.tsx index 416e317a540..91d045b2168 100644 --- a/packages/react/src/ThemeProvider.tsx +++ b/packages/react/src/ThemeProvider.tsx @@ -105,6 +105,8 @@ export const ThemeProvider: React.FC [colorMode, systemColorMode, setColorMode], ) + console.log({resolvedTheme}) + return ( > + setDayScheme: React.Dispatch> + setNightScheme: React.Dispatch> +}>({ + setColorMode: () => null, + setDayScheme: () => null, + setNightScheme: () => null, +}) + +// inspired from __NEXT_DATA__, we use application/json to avoid CSRF policy with inline scripts +const getServerHandoff = (id: string) => { + try { + const serverData = document.getElementById(`__PRIMER_DATA_${id}__`)?.textContent + if (serverData) return JSON.parse(serverData) + } catch (_error) { + // if document/element does not exist or JSON is invalid, supress error + } + return {} +} + +export const ThemeProvider: React.FC> = ({children, ...props}) => { + // Get fallback values from parent ThemeProvider (if exists) + const { + theme: fallbackTheme, + colorMode: fallbackColorMode, + dayScheme: fallbackDayScheme, + nightScheme: fallbackNightScheme, + } = useTheme() + + // Initialize state + const theme = props.theme ?? fallbackTheme ?? defaultTheme + + const uniqueDataId = useId() + const {resolvedServerColorMode} = getServerHandoff(uniqueDataId) + const resolvedColorModePassthrough = React.useRef(resolvedServerColorMode) + + const [colorMode, setColorMode] = useSyncedState(props.colorMode ?? fallbackColorMode ?? defaultColorMode) + const [dayScheme, setDayScheme] = useSyncedState(props.dayScheme ?? fallbackDayScheme ?? defaultDayScheme) + const [nightScheme, setNightScheme] = useSyncedState(props.nightScheme ?? fallbackNightScheme ?? defaultNightScheme) + const systemColorMode = useSystemColorMode() + const resolvedColorMode = resolvedColorModePassthrough.current || resolveColorMode(colorMode, systemColorMode) + const colorScheme = chooseColorScheme(resolvedColorMode, dayScheme, nightScheme) + const {resolvedTheme, resolvedColorScheme} = React.useMemo( + () => applyColorScheme(theme, colorScheme), + [theme, colorScheme], + ) + + // this effect will only run on client + React.useEffect( + function updateColorModeAfterServerPassthrough() { + const resolvedColorModeOnClient = resolveColorMode(colorMode, systemColorMode) + + if (resolvedColorModePassthrough.current) { + // if the resolved color mode passed on from the server is not the resolved color mode on client, change it! + if (resolvedColorModePassthrough.current !== resolvedColorModeOnClient) { + window.setTimeout(() => { + // use ReactDOM.flushSync to prevent automatic batching of state updates since React 18 + // ref: https://github.com/reactwg/react-18/discussions/21 + ReactDOM.flushSync(() => { + // override colorMode to whatever is resolved on the client to get a re-render + setColorMode(resolvedColorModeOnClient) + }) + + // immediately after that, set the colorMode to what the user passed to respond to system color mode changes + setColorMode(colorMode) + }) + } + + resolvedColorModePassthrough.current = null + } + }, + [colorMode, systemColorMode, setColorMode], + ) + + return ( + + + {children} + {props.preventSSRMismatch ? ( +