🥰

Storybook + Chakra UIでカラーサンプルを作る

3 min read 1

1. はじめに

久しぶりのZenn投稿です。最近、Storybookを使い始めたら、その便利さに感動しました。
今回は、Storybook + Chakra UI のテーマでカスタムカラーをたくさん使っていると混乱してくるため、一覧でみることができるStoryを作成したいと思います。

2. Chakra UIにカスタムカラーを設定

(Chakra UIのテーマ作成方法ですが、今回の趣旨とは少し離れてしまうため、公式サイトの方でご確認ください...😞)

カスタムカラーをテーマに設定するとき、下のような入れ子の構造を作ることもできます。テキストの色をカラーモードごとに変更したい場合や、透過率をカスタムしたい時に便利ですね。✨

theme/foundations/colors.ts
const colors = {
  text: {
    light: 'rgba(31, 31, 31)',
    dark: 'rgba(241, 241, 241)',
  },
  pink: {
    1000: 'rgba(252, 157, 157, 1)',
    700: 'rgba(252, 157, 157, 0.7)',
    500: 'rgba(252, 157, 157, 0.5)',
  },
  deepGreen: 'rgba(55, 171, 157)',
};

export default colors;

3. テーマに設定した色をプレビューするStoryを作成

● カラーをプレビューするコンポーネントの作成

先ほど作成したカスタムカラーですが、使う際には、color="text.light",color="deepGreen" のように呼び出すことができます。

まずは、手始めに入力された色を表示するためのコンポーネントを作成します。

const ColorGrid: React.FC<{
  color: string;
}> = ({ color }) => {
  const { onCopy } = useClipboard(color);

  return (
    <WrapItem onClick={onCopy}>
      <Tooltip label={color} aria-label={color}>
        <Box bgColor={color} boxSize="120px"></Box>
      </Tooltip>
    </WrapItem>
  );
};

Boxを作り、その背景に指定した色を反映するようにしました。Boxがホバーされると、そのカラーを呼び出すための文字列が表示されます。また、効率化も考えて、クリックで名前をコピーできるようにしました。

● テーマのColorsから色の配列を作成

連想配列からキーを取り出してcolorNamesリストを作成します。

import colors from 'theme/foundations/colors';

const colorNames = [];
Object.keys(colors).map((data) => {
  if (typeof colors[data] === 'string') {
    colorNames.push(data);
  } else {
    Object.keys(colors[data]).map((name) => {
      colorNames.push(data + '.' + name);
    });
  }
});

あまりいい実装を知らないので私のものよりクールな実装があれば教えていただけると幸いです...。🥺

● カラーリストをRenderする

最後に、先ほど作成したcolorNamesからColorGridに色を渡して表示させます。

return (
  <Container p={16}>
    <Wrap spacing={0}>
      {colorNames.map(
        (name: string): JSX.Element => (
          <Box key={name}>
            <ColorGrid color={name} />
          </Box>
        ),
      )}
    </Wrap>
  </Container>
);

4. 完成したStoryのコード

Colors.stories.ts
import React from 'react';
import { useClipboard, Container, Wrap, WrapItem, Tooltip, Box } from '@chakra-ui/react';
import colors from 'theme/foundations/colors';

export default {
  title: 'Theme/Colors',
};

const ColorGrid: React.FC<{
  color: string;
}> = ({ color }) => {
  const { onCopy } = useClipboard(color);

  return (
    <WrapItem onClick={onCopy}>
      <Tooltip label={color} aria-label={color}>
        <Box bgColor={color} boxSize="120px"></Box>
      </Tooltip>
    </WrapItem>
  );
};

export const List = (): JSX.Element => {
  const colorNames = [];

  Object.keys(colors).map((data) => {
    if (typeof colors[data] === 'string') {
      colorNames.push(data);
    } else {
      Object.keys(colors[data]).map((name) => {
        colorNames.push(data + '.' + name);
      });
    }
  });

  return (
    <Container p={16}>
      <Wrap spacing={0}>
        {colorNames.map(
          (name: string): JSX.Element => (
            <Box key={name}>
              <ColorGrid color={name} />
            </Box>
          ),
        )}
      </Wrap>
    </Container>
  );
};

5. まとめ

Storybookはやはり便利なので全人類が使うべきだと思います。
今回は以上です。
他にも書きたい記事のストックがあるので、時間があるときに書いていこうと思います!ではまた。

Discussion

const colorNames = [];
Object.keys(colors).map((data) => {
  if (typeof colors[data] === 'string') {
    colorNames.push(data);
  } else {
    Object.keys(colors[data]).map((name) => {
      colorNames.push(data + '.' + name);
    });
  }
});

ここの実装は、こっちのほうが若干スマートになるかなと思いました!

const colorNames = Object.keys(colors)
  .map((data) => {
    if (typeof colors[data] === 'string') return data;
    return Object.keys(colors[data]).map((name) => `${data}.${name}`);
  })
  .flat();
ログインするとコメントできます