Skip to content
On this page

ingred-ui 改善点

ingred-ui のデザインシステムの見直しを行うためのメモ。
社内共有用。(だけど OSS だから別に外部に書いてもいいやということでたくりんとんの技術メモに書く)
前提として、ガイドラインやコード規約を整備するのが先なのはわかっている。コードベースで解決できるものや、壁打ちとして使えそうなものなど、自分の頭の中を可視化する。

現状の問題点

現状、課題として認識してるものがざっと 7 つくらいある。
おそらく実装に取り掛かったらもっと出てくる。

補足として、重要度は 4 までと 5 以降でキッパリ分かれている。4 までは今すぐにでも取り掛かるべきだと考えている。

  1. ユーザー指定の色が primary だけ
  2. 色の指定に統一感がない
  3. box-shadow の値がマジックナンバー
  4. Button などのコンポーネントで背景色と文字色が競合する
  5. スマホ対応
  6. light/dark モード
  7. Unstyled

WIP: 倒し方

あくまでまだ提案や検討の段階。
全部一気にやるのは無理なのと、作戦を練ること自体自己判断だけではどうにもならない。

色が primary だけ

secondary を足す。

export const palette: Palette = {
  primary: {
    deepDark: colors.blue[700],
    dark: colors.blue[600],
    main: colors.blue[500],
    light: colors.blue[200],
    highlight: colors.blue[100],
  },
  secondary: {
    deepDark: colors.basic[700],
    dark: colors.basic[600],
    main: colors.basic[500],
    light: colors.basic[200],
    highlight: colors.basic[100],
  },
  ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

secondary を追加して、例えば Button コンポーネントの secondary は以下のように書き変わる。



 
 








 
 



 
 





secondary: {
  normal: {
    // background: theme.palette.background.default,
    background: theme.palette.secondary.main,
    color: theme.palette.black,
    boxShadow: `0px -2px ${hexToRgba(
      theme.palette.black,
      0.16,
    )} inset, 0px 2px ${hexToRgba(theme.palette.black, 0.08)}`,
    border: `1px solid ${theme.palette.divider}`,
  },
  hover: {
    // background: theme.palette.gray.highlight,
    background: theme.palette.secondary.dark,
    border: `1px solid ${theme.palette.divider}`,
  },
  active: {
    // background: theme.palette.gray.highlight,
    background: theme.palette.secondary.dark,
    boxShadow: `inset 0 2px ${hexToRgba(theme.palette.black, 0.16)}`,
    border: `1px solid ${theme.palette.divider}`,
  },
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

色の指定に統一感がない

全体的に、色の指定に統一感がない。
具体的には、theme を通じて参照できる色が、名前や用途が無視され、ただの「色」として認識されてしまってるのが原因。
例えば、gray という色が定義されているが、それが文字にも背景にもボーダーにも使われている。
それをやるくらいなら、直接 colors.ts に定義してある basic[500] という方法で参照したほうがいくらかマシになる。

WARNING

gray という色がどういう用途で使うことを想定されているのかを中の人に確認取ってないので、もしかしたらグローバルに使う想定だったかもしれない、その時はごめんなさい。

gray が誤用されてる前提で進めると、例外を除き、gray という色をただ色として使うのではなく、変数や定数の名前と指定したい色が一致するような状態を作りたい。
また、例外の場合は issue やドキュメントなどに書き、エディタ上からすぐ理由が参照できるような状態を作る。

これらの解決方法として、palette に action を追加するといいのではないかなと考える。
例として、適当に以下のようなありがちなプロパティを定義してみた。

const palette: Palette = {
  ... // 他のプロパティ
  action: {
    active: "rgba(0, 0, 0, 0.54)",
    activeBackground: colors.basic[300],
    hover: "rgba(0, 0, 0, 0.04)",
    hoverOpacity: 0.04,
    hoverBackground: colors.basic[200],
    selected: "rgba(0, 0, 0, 0.08)",
    selectedOpacity: 0.08,
    disabled: "rgba(0, 0, 0, 0.26)",
    disabledBackground: colors.basic[200],
    focus: "rgba(0, 0, 0, 0.12)",
    focusOpacity: 0.12,
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

使い方として、以下のような感じを想定している。

  • hover の時に背景を gray にしたい
const style = styled.div`
  &:hover {
    background: ${({ theme }) => theme.palette.active.hoverBackground};
  }
`;
1
2
3
4
5
  • hover の時に背景を primary の薄い色として使いたい
const style = styled.div`
  &:hover {
    background: ${({ theme }) =>
      hexToRgba(theme.palette.primary.main, theme.palette.active.hoverOpacity)};
  }
`;
1
2
3
4
5
6

こうすることで、ただの gray という色と、背景色用の gray、また背景に任意の色を指定したい際の色の区別がつくようになる。
disabled や active についても同様に対処できると考える。

box-shadow

色同様、box-shadow にも統一感がない。
さまざまな指定方法を指定て乱立してるので、統一したい。

具体的な解決方法として、createTheme 関数に shadows を指定できるようにする。

shadows の中身については迷っているが、1 つは以下のような関数を生成して、その結果をリストとして持ちながら実装をする方法。
この方法では、shadowsmaterial-components-web にある定義を参考にして生成する。

const shadowBaselineColor = "0,0,0";
const shadowKeyUmbraOpacity = 0.2;
const shadowKeyPenumbraOpacity = 0.14;
const shadowAmbientShadowOpacity = 0.12;

function createShadow(...px: number[]) {
  return [
    `${px[0]}px ${px[1]}px ${px[2]}px ${px[3]}px rgba(${shadowBaselineColor},${shadowKeyUmbraOpacity})`,
    `${px[4]}px ${px[5]}px ${px[6]}px ${px[7]}px rgba(${shadowBaselineColor},${shadowKeyPenumbraOpacity})`,
    `${px[8]}px ${px[9]}px ${px[10]}px ${px[11]}px rgba(${shadowBaselineColor},${shadowAmbientShadowOpacity})`,
  ].join(",");
}

const shadows = [
  'none',
  createShadow(0, 2, 1, -1, 0, 1, 1, 0, 0, 1, 3, 0),
  ...
  // material-components-web にあるプロパティを全部書く
];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

もう片方は、ひたすら既存の実装を網羅するように box-shadow の value を列挙する方法。

const shadows = [
  'none',
  `0 4px ${hexToRgba(gray[500], 0.24)}`,
  `0px -2px ${hexToRgba(basic[900], 0.16)} inset, 0px 2px ${hexToRgba(basic[900], 0.08)}`,
  ...
  // 既存の実装に存在する box-shadow 全部書く
];
1
2
3
4
5
6
7

どちらの方法を使っても、上で定義した  shadows を theme を通して定数として参照可能にする。






 












export function createTheme(options: ThemeOptions = {}): Theme {
  const {
    palette: paletteInput = {},
    spacing: spacingInput,
    radius: radiusInput,
    shadows: shadowInput, // shadows
    ...other
  } = options;

  const palette = createPalette(paletteInput);
  const spacing = spacingInput || Space;
  const radius = radiusInput || Radius;
  const shadows = shadowInput || Shadows;

  const theme = deepmerge({ palette, spacing, depth, radius, shadows }, other);
  return { ...theme };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

shadows 自体は MUI の createTheme 関数の shadows プロパティ を参考にした。

実際に利用する際には、theme.shadows[0] のような形で参照する。

const style = {
  boxShadow: theme.shadows[0],
  ...
};
1
2
3
4

Button などのコンポーネントで背景色と文字色が競合する

ingred-ui contrast で書いた手法で倒す。

primary, secondary の際には、以下のように getContrastText 関数を使って指定するようにする。




 








primary: {
  normal: {
    background: theme.palette.primary.main,
    color: getContrastText(theme.palette.primary.main), // ここで背景色からテキストカラーを導いてレンダリングする
    boxShadow: `0px -2px ${hexToRgba(
      theme.palette.black,
      0.16
    )} inset, 0px 2px ${hexToRgba(theme.palette.black, 0.08)}`,
    border: `1px solid ${theme.palette.primary.dark}`,
  },
...
1
2
3
4
5
6
7
8
9
10
11

スマホ対応

やるべきだけど、少し後回しにする予定。具体的な実装方法などは考えていない。
ロジックや手法は既存の UI ライブラリと同様に行うつもり。

light/dark モード

上に同じ。

Unstyled

超構想中ではあるが、@mui-base@chakra-ui/** のように、コアパッケージ的なものを作りたい。

考え中

WIP です。まだまだボロボロ出てきそう。
やるぞ〜٩( ᐛ )و