themeAndStyleProvider.tsx 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  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. // Compat disables :nth-child warning
  20. cache.compat = true;
  21. /**
  22. * Wraps children with emotions ThemeProvider reactively set a theme.
  23. *
  24. * Also injects the sentry GlobalStyles .
  25. */
  26. function ThemeAndStyleProvider({children}: Props) {
  27. useEffect(() => void loadPreferencesState(), []);
  28. const config = useLegacyStore(ConfigStore);
  29. const theme = config.theme === 'dark' ? darkTheme : lightTheme;
  30. return (
  31. <ThemeProvider theme={theme}>
  32. <GlobalStyles isDark={config.theme === 'dark'} theme={theme} />
  33. <CacheProvider value={cache}>{children}</CacheProvider>
  34. {createPortal(
  35. <Fragment>
  36. <meta name="color-scheme" content={config.theme} />
  37. <meta name="theme-color" content={theme.sidebar.background} />
  38. </Fragment>,
  39. document.head
  40. )}
  41. </ThemeProvider>
  42. );
  43. }
  44. export default ThemeAndStyleProvider;