diff --git a/packages/harmony/src/foundations/theme/ThemeProvider.tsx b/packages/harmony/src/foundations/theme/ThemeProvider.tsx index fc3465efde2..a19eef5e914 100644 --- a/packages/harmony/src/foundations/theme/ThemeProvider.tsx +++ b/packages/harmony/src/foundations/theme/ThemeProvider.tsx @@ -1,4 +1,4 @@ -import { useEffect, type ReactNode } from 'react' +import { useEffect, useRef, type ReactNode } from 'react' import { ThemeProvider as EmotionThemeProvider } from '@emotion/react' @@ -13,14 +13,51 @@ type ThemeProviderProps = { children: ReactNode } +type ThemeProviderInstance = { + id: number + theme: Theme +} + +let instanceId = 0 +let providerStack: ThemeProviderInstance[] = [] + +const syncDocumentTheme = () => { + if (typeof document === 'undefined') return + + const activeProvider = providerStack[providerStack.length - 1] + if (activeProvider) { + document.documentElement.setAttribute('data-theme', activeProvider.theme) + } else { + document.documentElement.removeAttribute('data-theme') + } +} + export const ThemeProvider = (props: ThemeProviderProps) => { const { children, theme } = props + const providerIdRef = useRef(null) + if (providerIdRef.current == null) { + providerIdRef.current = ++instanceId + } + const providerId = providerIdRef.current useEffect(() => { - if (typeof document !== 'undefined') { - document.documentElement.setAttribute('data-theme', theme) + providerStack = [...providerStack, { id: providerId, theme }] + syncDocumentTheme() + + return () => { + providerStack = providerStack.filter( + (provider) => provider.id !== providerId + ) + syncDocumentTheme() } - }, [theme]) + }, [providerId]) + + useEffect(() => { + providerStack = providerStack.map((provider) => + provider.id === providerId ? { ...provider, theme } : provider + ) + syncDocumentTheme() + }, [providerId, theme]) return (