暗いモードをEmotionに設定


Emotionで黒モードを設定しました.まだTypeScriptに慣れていないので、Typeを指定するのに時間がかかり、文法を再学習しそうです.
まず,この部分はブラックモードの実現に集中する.

結果



theme.ts

import { DarkTheme, LightTheme } from '@emotion/react';

export const lightTheme: LightTheme = {
  mode: {
    text: '#000',
    background: '#fff',
    buttonText: '#000',
    buttonTextHover: '#fff',
    buttonBorder: '#000',
    buttonBg: 'rgba(0, 0, 0, 0)',
    buttonBgHover: 'rgba(0, 0, 0, 1)',
  },
};

export const darkTheme: DarkTheme = {
  mode: {
    text: '#fff',
    background: '#121212',
    buttonText: '#fff',
    buttonTextHover: '#000',
    buttonBorder: '#fff',
    buttonBg: 'rgba(255, 255, 255, 0)',
    buttonBgHover: 'rgba(255, 255, 255, 1)',
  },
};
LightThemeとdarkthemeに分けて色を指定します.

theme.d.ts

import '@emotion/react';

declare module '@emotion/react' {
  export interface LightTheme {
    mode: {
      text: string;
      background: string;
      buttonText: string;
      buttonTextHover: string;
      buttonBorder: string;
      buttonBg: string;
      buttonBgHover: string;
    };
  }

  export interface DarkTheme {
    mode: {
      text: string;
      background: string;
      buttonText: string;
      buttonTextHover: string;
      buttonBorder: string;
      buttonBg: string;
      buttonBgHover: string;
    };
  }
}
themeを使用する場合は、タイプを指定する必要があります.

global.tsx

import React from 'react';
import { Global, css, LightTheme, DarkTheme } from '@emotion/react';

const style = (theme: any) => css`
  * {
    margin: 0;
    padding: 0;
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    box-sizing: border-box;
  }

  body {
    color: ${theme.mode.text};
    background: ${theme.mode.background};
  }
`;

const GlobalStyle = () => {
  return <Global styles={style} />;
};

export default GlobalStyle;
この部分を実現した残念な点は,themeを変数として入力する場合にanyとして指定することである.
type ColorMode = LightTheme | DarkTheme; 変数として指定します.
anyの代わりにColorModeでTypeを宣言しようとしたが、次のstyleでエラーメッセージが起動し、この部分でGoogleでエラーメッセージが見つからなかったので、まずanyでTypeを指定した.
後で修正するつもりです.
type ColorMode = LightTheme | DarkTheme;

const style = (theme: ColorMode) => css`
	...
`;

const GlobalStyle = () => {
  return <Global styles={style} />;
};

export default GlobalStyle;

トラブルシューティング


改めて見ると、タイプ宣言では、インタフェースをLightThemeとDarkThemeの2種類に分けていますが、これは間違いの根本的な原因です.つまり,同じ内容のインタフェースを別々に宣言しなければならない.🤦‍♀️
誰にでも代わってタイプをThemeに指定できる…!

const style = (theme: Theme) => css`
	...
`;

const GlobalStyle = () => {
  return <Global styles={style} />;
};

export default GlobalStyle;
エラー解決Commit履歴

App.tsx

import React, { useState } from 'react';
import { BrowserRouter } from 'react-router-dom';

import { ThemeProvider } from '@emotion/react';

import GlobalStyle from '@src/styles/global';
import Routes from '@src/Routes';
import { darkTheme, lightTheme } from '@src/styles/theme';

const App = () => {
  const [isDark, setIsDark] = useState(false);

  return (
    <BrowserRouter>
      <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
        <GlobalStyle />
        <Routes isDark={isDark} setIsDark={setIsDark} />
      </ThemeProvider>
    </BrowserRouter>
  );
};

export default App;

Routes.tsx

/** @jsx jsx */
import { css, jsx } from '@emotion/react';
import React, { Dispatch, SetStateAction } from 'react';
import { Route } from 'react-router-dom';
import Home from './pages/Home';

interface RoutesProps {
  isDark: boolean;
  setIsDark: Dispatch<SetStateAction<boolean>>;
}

const Routes: React.FC<RoutesProps> = ({ isDark, setIsDark }) => {
  return (
    <div>
      <button
        css={css`
          color: ${isDark ? 'white' : 'black'};
        `}
        onClick={() => {
          setIsDark(!isDark);
        }}
      >
        {isDark ? 'dark' : 'light'}버튼 입니다.
      </button>
      <Route exact path="/" component={Home} />
    </div>
  );
};

export default Routes;