themeAndStyleProvider.tsx 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. import {Fragment, useEffect} from 'react';
  2. import {createPortal} from 'react-dom';
  3. import createCache from '@emotion/cache';
  4. import {CacheProvider, ThemeProvider} from '@emotion/react';
  5. import {loadPreferencesState} from 'sentry/actionCreators/preferences';
  6. import ConfigStore from 'sentry/stores/configStore';
  7. import {useLegacyStore} from 'sentry/stores/useLegacyStore';
  8. import GlobalStyles from 'sentry/styles/global';
  9. import {darkTheme, lightTheme} from 'sentry/utils/theme';
  10. type Props = {
  11. children: React.ReactNode;
  12. };
  13. // XXX(epurkhiser): We create our own emotion cache object to disable the
  14. // stylis prefixer plugin. This plugin does NOT use browserlist to determine
  15. // what needs prefixed, just applies ALL prefixes.
  16. //
  17. // In 2022 prefixes are almost ubiquitously unnecessary
  18. const cache = createCache({key: 'app', stylisPlugins: []});
  19. /**
  20. * Wraps children with emotions ThemeProvider reactively set a theme.
  21. *
  22. * Also injects the sentry GlobalStyles .
  23. */
  24. function ThemeAndStyleProvider({children}: Props) {
  25. useEffect(() => void loadPreferencesState(), []);
  26. const config = useLegacyStore(ConfigStore);
  27. const theme = config.theme === 'dark' ? darkTheme : lightTheme;
  28. return (
  29. <ThemeProvider theme={theme}>
  30. <GlobalStyles isDark={config.theme === 'dark'} theme={theme} />
  31. <CacheProvider value={cache}>{children}</CacheProvider>
  32. {createPortal(
  33. <Fragment>
  34. <meta name="color-scheme" content={config.theme} />
  35. <meta name="theme-color" content={theme.sidebar.background} />
  36. </Fragment>,
  37. document.head
  38. )}
  39. </ThemeProvider>
  40. );
  41. }
  42. export default ThemeAndStyleProvider;