Quantcast
Channel: プログラミング
Viewing all articles
Browse latest Browse all 8191

Free React Template (Dashboard) の Theme を追ってみる (2) - ジャコ Lab

$
0
0

カスタムカラーzako-lab929.hatenablog.com

続きです。

設定値を深堀りしていく

{
  cssVariables: {
    colorSchemeSelector: 'data-mui-color-scheme',
    cssVarPrefix: 'template',
  },
  colorSchemes,
  typography,
  shadows,
  shape,
  components: {
    ...inputsCustomizations,
    ...dataDisplayCustomizations,
    ...feedbackCustomizations,
    ...navigationCustomizations,
    ...surfacesCustomizations,
    ...themeComponents,
  },
}

mui.com

ドキュメントはこの辺ですかねぇ?

cssVariables

テンプレートでは、cssVariablesは、見ての通り、2つのパラメータが設定されています。

shared-theme/AppTheme.tsx#L30-L33

{
  cssVariables: {
    colorSchemeSelector: 'data-mui-color-scheme',
    cssVarPrefix: 'template',
  }
}
実際に設定してみます
  createTheme({
+   cssVariables: {+     cssVarPrefix: 'zako',+   },
  })
  • cssVarPrefixCSS Variable を生成してくれる際の Prefix になる値のようです。(デフォルト: --mui)
  • colorSchemeSelectorは Dark Mode を手動で切り替える際に役立つようです。

zako parameters
zako parameters

こんな感じに CSS Variables が生成されるみたいです。
colorSchemeSelectorは、後述の colorSchemesと一緒に使ったほうがわかりやすいかも?
colorSchemeSelector を colorSchemes と一緒に使ってみる
  createTheme({
    cssVariables: {
+     colorSchemeSelector: 'class',
      cssVarPrefix: 'zako',
    },
+   colorSchemes: { light: true, dark: true },
  })

テンプレートの colorSchemesに比べて簡易的な設定ですが、こうすると Light Mode と Dark Mode が切り替えられるようです。
colorSchemesの設定については後述で試しますので、ここでは boolean 値を指定して終わりです。

zako parameters
zako parameters

Light ModeDark Mode
Dark Mode が設定できるようになった様子

cssVariables の型定義
cssVariables?: boolean | Pick<CssVarsThemeOptions, 'colorSchemeSelector' | 'rootSelector' | 'disableCssColorScheme' | 'cssVarPrefix' | 'shouldSkipGeneratingVar'>;

このようになっているようです。

booleanobject
true | false
{
  "CssVarsThemeOptions": ?,
  "colorSchemeSelector": ?,
  "rootSelector": ?,
  "disableCssColorScheme": ?,
  "cssVarPrefix": ?,
  "shouldSkipGeneratingVar": ?
}
更に深くは追わないですが、だいたいこんな感じですかね

colorSchemes

colorSchemesは非常にたくさんの設定がされています。

shared-theme/themePrimitives.ts#L241-L341

テンプレートテーマの colorSchems の設定 (長いので折りたたみ)

export const colorSchemes = {
  light: {
    palette: {
      primary: {
        light: brand[200],
        main: brand[400],
        dark: brand[700],
        contrastText: brand[50],
      },
      info: {
        light: brand[100],
        main: brand[300],
        dark: brand[600],
        contrastText: gray[50],
      },
      warning: {
        light: orange[300],
        main: orange[400],
        dark: orange[800],
      },
      error: {
        light: red[300],
        main: red[400],
        dark: red[800],
      },
      success: {
        light: green[300],
        main: green[400],
        dark: green[800],
      },
      grey: {
        ...gray,
      },
      divider: alpha(gray[300], 0.4),
      background: {
        default: 'hsl(0, 0%, 99%)',
        paper: 'hsl(220, 35%, 97%)',
      },
      text: {
        primary: gray[800],
        secondary: gray[600],
        warning: orange[400],
      },
      action: {
        hover: alpha(gray[200], 0.2),
        selected: `${alpha(gray[200], 0.3)}`,
      },
      baseShadow:
        'hsla(220, 30%, 5%, 0.07) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.07) 0px 8px 16px -5px',
    },
  },
  dark: {
    palette: {
      primary: {
        contrastText: brand[50],
        light: brand[300],
        main: brand[400],
        dark: brand[700],
      },
      info: {
        contrastText: brand[300],
        light: brand[500],
        main: brand[700],
        dark: brand[900],
      },
      warning: {
        light: orange[400],
        main: orange[500],
        dark: orange[700],
      },
      error: {
        light: red[400],
        main: red[500],
        dark: red[700],
      },
      success: {
        light: green[400],
        main: green[500],
        dark: green[700],
      },
      grey: {
        ...gray,
      },
      divider: alpha(gray[700], 0.6),
      background: {
        default: gray[900],
        paper: 'hsl(220, 30%, 7%)',
      },
      text: {
        primary: 'hsl(0, 0%, 100%)',
        secondary: gray[400],
      },
      action: {
        hover: alpha(gray[600], 0.2),
        selected: alpha(gray[600], 0.3),
      },
      baseShadow:
        'hsla(220, 30%, 5%, 0.7) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.8) 0px 8px 16px -5px',
    },
  },
};

設定自体は各種カラーの共通定義を作っているようでわかりやすいですね
具体的な型定義
colorSchemes?: Partial<Record<DefaultColorScheme, boolean | ColorSystemOptions>> &
  (ExtendedColorScheme extends string ? Record<ExtendedColorScheme, ColorSystemOptions> : {});
これを見てもわからん。少し深堀りせねば...
type DefaultColorScheme = 'light' | 'dark';
interface ColorSystemOptions {
  palette?: PaletteOptions & {
    background?: Partial<PaletteBackgroundChannel>;
    common?: Partial<PaletteCommonChannel>;
    primary?: Partial<PaletteColorChannel>;
    secondary?: Partial<PaletteColorChannel>;
    error?: Partial<PaletteColorChannel>;
    info?: Partial<PaletteColorChannel>;
    success?: Partial<PaletteColorChannel>;
    text?: Partial<PaletteTextChannel>;
    dividerChannel?: Partial<string>;
    action?: Partial<PaletteActionChannel>;
    Alert?: Partial<PaletteAlert>;
    AppBar?: Partial<PaletteAppBar>;
    Avatar?: Partial<PaletteAvatar>;
    Button?: Partial<PaletteButton>;
    Chip?: Partial<PaletteChip>;
    FilledInput?: Partial<PaletteFilledInput>;
    LinearProgress?: Partial<PaletteLinearProgress>;
    Skeleton?: Partial<PaletteSkeleton>;
    Slider?: Partial<PaletteSlider>;
    SnackbarContent?: Partial<PaletteSnackbarContent>;
    SpeedDialAction?: Partial<PaletteSpeedDialAction>;
    StepConnector?: Partial<PaletteStepConnector>;
    StepContent?: Partial<PaletteStepContent>;
    Switch?: Partial<PaletteSwitch>;
    TableCell?: Partial<PaletteTableCell>;
    Tooltip?: Partial<PaletteTooltip>;
  };
  opacity?: Partial<Opacity>;
  overlays?: Overlays;
}

という定義のようなので、噛み砕くとだいたい以下のような感じみたいですね。

{
  "light"?: boolean | ColorSystemOptions,
  "dark"?: boolean | ColorSystemOptions,
}
これなら理解できる!
とりあえず設定して使ってみる

未設定なものはデフォルト値が使われるようになっているようです。

すごい適当ですが、こんな感じにしてみます!
background.default background.paper
light ほぼ白 明るい赤
dark ほぼ黒 暗い赤
  const theme = createTheme({
    cssVariables: {
      colorSchemeSelector: 'class',
      cssVarPrefix: 'zako',
    },
    colorSchemes: {
+     light: {+       palette: {+         background: {+           default: '#eee',+           paper: '#fdd',+         },+       },+     },+     dark: {+       palette: {+         background: {+           default: '#111',+           paper: '#322',+         },+       },+     },
    },
  })

Light ModeDark Mode
とりあえず colorSchemes を設定してみた状態

めちゃめちゃ良いじゃない。とても手軽で便利な設定

typography

mui.com

shared-theme/themePrimitives.ts#L343-L391

テンプレートテーマの typography の設定 (長いので折りたたみ)

export const typography = {
  fontFamily: ['"Inter", "sans-serif"'].join(','),
  h1: {
    fontSize: defaultTheme.typography.pxToRem(48),
    fontWeight: 600,
    lineHeight: 1.2,
    letterSpacing: -0.5,
  },
  h2: {
    fontSize: defaultTheme.typography.pxToRem(36),
    fontWeight: 600,
    lineHeight: 1.2,
  },
  h3: {
    fontSize: defaultTheme.typography.pxToRem(30),
    lineHeight: 1.2,
  },
  h4: {
    fontSize: defaultTheme.typography.pxToRem(24),
    fontWeight: 600,
    lineHeight: 1.5,
  },
  h5: {
    fontSize: defaultTheme.typography.pxToRem(20),
    fontWeight: 600,
  },
  h6: {
    fontSize: defaultTheme.typography.pxToRem(18),
    fontWeight: 600,
  },
  subtitle1: {
    fontSize: defaultTheme.typography.pxToRem(18),
  },
  subtitle2: {
    fontSize: defaultTheme.typography.pxToRem(14),
    fontWeight: 500,
  },
  body1: {
    fontSize: defaultTheme.typography.pxToRem(14),
  },
  body2: {
    fontSize: defaultTheme.typography.pxToRem(14),
    fontWeight: 400,
  },
  caption: {
    fontSize: defaultTheme.typography.pxToRem(12),
    fontWeight: 400,
  },
};

各種フォントサイズなどの共通定義を作っているようで、カラー同様わかりやすいです
具体的な型定義
export interface TypographyOptions
  extends Partial<Record<Variant, TypographyStyleOptions> & FontStyleOptions> {}

colorSchemes よりは複雑ではないですね。追ってみると以下のようになっているみたいですね。

export type Variant =
  | 'h1'
  | 'h2'
  | 'h3'
  | 'h4'
  | 'h5'
  | 'h6'
  | 'subtitle1'
  | 'subtitle2'
  | 'body1'
  | 'body2'
  | 'caption'
  | 'button'
  | 'overline';
export type TypographyStyle = CSSProperties;
export interface TypographyStyleOptions extends TypographyStyle {}

つまり Partial<Record<Variant, TypographyStyleOptions>>は以下のようになるはずです

{
  'h1'?: CSSProperties,
  'h2'?: CSSProperties,
  'h3'?: CSSProperties,
  'h4'?: CSSProperties,
  'h5'?: CSSProperties,
  'h6'?: CSSProperties,
  'subtitle1'?: CSSProperties,
  'subtitle2'?: CSSProperties,
  'body1'?: CSSProperties,
  'body2'?: CSSProperties,
  'caption'?: CSSProperties,
  'button'?: CSSProperties,
  'overline'?: CSSProperties,
}

更に font-familyの設定ができるはずです

h1 がデカすぎるなど好みのサイズがあると思うので Material UI のデフォルトサイズが気に入らなければ設定したほうが良さそうですね

shadows

shared-theme/themePrimitives.ts#L398-L399

const defaultShadows: Shadows = ['var(--mui-palette-baseShadow)', ...defaultTheme.shadows.slice(1)];
export const shadows = defaultShadows;
shadows に関しては、ほぼデフォルト状態と言っても良いでしょうか
具体的な型定義
export type Shadows = [
  'none',
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
  string,
];
あ・・・わからんやつ。とりあえず影向けの値がいっぱい設定されることだけはわかります

shape

shared-theme/themePrimitives.ts#L393-L395

export const shape = {
  borderRadius: 8,
};
borderRadius しか設定してない!わかりやすい!
具体的な型定義
export interface Shape {
  borderRadius: number;
}
型定義も borderRadius だけだ!

前回の記事で、細かい違いとして 角丸の強さが異なるなぁという感想がありましたが、原因はここですね。

components

mui.com

恐らく、カスタムテーマの真骨頂の部分でしょう。

Material UI の Component に対して、共通の定義を行える場所です。
例えば、上記で「ほぼ黒」と「暗い赤」を設定しましたが、テーブルの部分だけ「暗い赤」になっていません。

今回は、そこを「暗い赤」にすることを目標に、components の設定をしてみます。

実際に設定してみる
export const CustomTheme: React.FC<CustomThemeProps> = ({ children }) => {
  const theme = createTheme({
    cssVariables: {
      colorSchemeSelector: 'class',
      cssVarPrefix: 'zako',
    },
    colorSchemes: {
      light: {
        palette: {
          background: {
            default: '#eee',
            paper: '#fdd',
          },
        },
      },
      dark: {
        palette: {
          background: {
            default: '#111',
            paper: '#322',
          },
        },
      },
    },
+   components: {+     MuiDataGrid: {+       styleOverrides: {+         root: ({ theme }) => ({+           backgroundColor: theme.palette.background.paper,+           [`& .${gridClasses.columnHeader}`]: {+             backgroundColor: theme.palette.background.paper,+           },+         }),+       },+     },+   },
  })

MuiDataGrid のテーマを設定した様子
MuiDataGrid のテーマを設定した様子

やったね!

まとめ

都度、コンポーネントに対してスタイルを設定するでも良いですが、一箇所に「テーマ」として設定できるのは非常に良いと思います。逆に「テーマ」に設定されているせいで思うようなスタイルにならないもあると思いますのでなかなか難しいところではあると思います。

Viewing all articles
Browse latest Browse all 8191

Trending Articles