{"version":3,"file":"cookie-theme-provider.mjs","sources":["../../../packages/theme/cookie-theme-provider.tsx"],"sourcesContent":["import {\n  createContext,\n  FC,\n  memo,\n  PropsWithChildren,\n  useContext,\n  useEffect,\n  useMemo,\n  useState,\n} from 'react'\nimport { ThemeProvider as StyledThemeProvider } from '../utils/styled-components-wrapper.js'\nimport {\n  DEFAULT_THEME_NAME,\n  prefersDarkThemeMediaQuery,\n  ThemeName,\n} from './constants.js'\nimport { themeMap } from './themes.js'\nimport { getThemeNameFromCookies } from './utils/cookies.js'\nimport { initColors } from './document-head-contents/index.js'\nimport {\n  getThemeNameFromUrl,\n  updateGlobalTheme,\n} from './document-head-contents/element-theme-script.js'\nimport { ThemeContext } from './types.js'\n\nconst defaultThemeContext = {} as ThemeContext\nexport const ThemeToggleContext =\n  createContext<ThemeContext>(defaultThemeContext)\n\n// we need to initialize this before react component code if we're using this provider or ThemeProvider\ninitColors()\n\n/**\n * This is really complicated logic here. Comments will be added on specific lines\n *\n * Cookie theme provider acts differently from common theme provider.\n * 1. it can be nested, BUT it should re-use value provided by itself for optimisation purposes\n * 2. if it is top-level, it is not altering itself, but instead altering theme behavior on HTMLElement level\n * 3. it does not support custom themes, preferring pre-defined themes instead\n * */\n\nexport const CookieThemeProvider: FC<\n  PropsWithChildren<{\n    // Use themeNameParent if you need get cookie in SSR\n    initialThemeName?: ThemeName\n    overrideThemeName?: ThemeName\n  }>\n> = memo(\n  ({\n    children,\n    initialThemeName,\n    // overrideThemeName is mainly used for storybook\n    overrideThemeName,\n  }) => {\n    const parentTheme = useContext(ThemeToggleContext)\n    // we do not want to do nested injections, and we're checking\n    // if context we inject in this component is already provided\n    const isTopLevelProvider = Object.keys(parentTheme).length === 0\n    // we always start with default theme, or, if server wants to provide\n    // specific default theme, with server-provided theme to avoid hydration errors\n    const [internalThemeName, setThemeName] = useState<ThemeName>(\n      initialThemeName || DEFAULT_THEME_NAME,\n    )\n    // since we're using this component to provide cookie-theme,\n    // we eventually want to respect theme provided in cookie, not general theme,\n    // so we're picking `parentTheme.themeName` if we have one.\n    // If user needs custom theme, not \"cookie theme\", he should use ThemeProvider instead.\n    const themeName = parentTheme.themeName || internalThemeName\n\n    const theme = themeMap[themeName]\n\n    // This logic is really hydrating everything, since we started with server-rendered default prop.\n    // It also follows cookie value change.\n    useEffect(() => {\n      // This logic is useless if we're nested - it is already done in top-level provider\n      if (!isTopLevelProvider) {\n        return\n      }\n\n      const setTheme = () => {\n        const systemThemeName = prefersDarkThemeMediaQuery?.matches\n          ? ThemeName.dark\n          : ThemeName.light\n        const themeNameUrl = getThemeNameFromUrl()\n        const themeNameCookie = getThemeNameFromCookies()\n        const newThemeName =\n          // first, if we have some override (e.g. in Storybook), we respect it\n          overrideThemeName ||\n          // url query has higher priority than cookie\n          themeNameUrl ||\n          // then, if we have cookie theme, we use theme from cookie\n          themeNameCookie ||\n          // else, we follow theme we were provided in initialization from server,\n          // which means server explicitly wants specific theme by default, not \"follow-system\"\n          initialThemeName ||\n          // then, we use media query theme, if available (not all browsers may still support it)\n          systemThemeName ||\n          // and, finally, falling back to default\n          DEFAULT_THEME_NAME\n        setThemeName(newThemeName)\n        // and when theme is switched, we're setting global-level CSS variable data-attribute\n        // to modify CSS vars provided on a top-level\n        document.documentElement.dataset.lidoTheme = newThemeName\n      }\n\n      // Users may have auto-theme (switching on sunset or schedule or whatever) so we need to listen for this event\n      prefersDarkThemeMediaQuery?.addEventListener('change', setTheme)\n      setTheme()\n\n      // This code check that the theme cookie was changed on other tab or site (the same second-level domain)\n      const checkCookieThemeWasChanged = () => {\n        const themeNameCookie = getThemeNameFromCookies()\n\n        if (\n          themeNameCookie &&\n          (themeNameCookie === ThemeName.dark ||\n            themeNameCookie === ThemeName.light)\n        ) {\n          setThemeName(themeNameCookie)\n        }\n      }\n      window.addEventListener('focus', checkCookieThemeWasChanged)\n\n      return () => {\n        window.removeEventListener('focus', checkCookieThemeWasChanged)\n      }\n    }, [\n      initialThemeName,\n      isTopLevelProvider,\n      overrideThemeName,\n      parentTheme,\n      theme,\n    ])\n\n    const value = useMemo(\n      () => ({\n        themeName,\n        toggleTheme() {\n          setThemeName((themeName) => {\n            const newThemeName =\n              themeName === ThemeName.light ? ThemeName.dark : ThemeName.light\n            // note that we're writing cookie theme only on explicit calls,\n            // not on \"internal theme state\" change\n            updateGlobalTheme(newThemeName)\n            // we do not need to run setTheme here, as effect is triggered\n            return newThemeName\n          })\n        },\n      }),\n      [themeName],\n    )\n\n    if (isTopLevelProvider) {\n      // if this provider is top-level we rely on element-theme-script.tsx logic\n      // which defines data-lido-theme injection\n      return (\n        <ThemeToggleContext.Provider value={value}>\n          <StyledThemeProvider theme={theme}>{children}</StyledThemeProvider>\n        </ThemeToggleContext.Provider>\n      )\n    } else if (overrideThemeName) {\n      return (\n        <div style={{ display: 'contents' }} data-lido-theme={themeName}>\n          <StyledThemeProvider theme={theme}>{children}</StyledThemeProvider>\n        </div>\n      )\n    } else {\n      return <>{children}</>\n    }\n  },\n)\n\nCookieThemeProvider.displayName = 'CookieThemeProvider'\n"],"names":["defaultThemeContext","ThemeToggleContext","createContext","initColors","CookieThemeProvider","memo","_ref","children","initialThemeName","overrideThemeName","parentTheme","useContext","isTopLevelProvider","Object","keys","length","internalThemeName","setThemeName","useState","DEFAULT_THEME_NAME","themeName","theme","themeMap","useEffect","setTheme","systemThemeName","prefersDarkThemeMediaQuery","matches","ThemeName","dark","light","themeNameUrl","getThemeNameFromUrl","themeNameCookie","getThemeNameFromCookies","newThemeName","document","documentElement","dataset","lidoTheme","addEventListener","checkCookieThemeWasChanged","window","removeEventListener","value","useMemo","toggleTheme","updateGlobalTheme","_jsx","Provider","StyledThemeProvider","style","display","_Fragment","displayName"],"mappings":"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"}