🦅

Storybookの「ColorPalette」を使って、デザイントークンを埋め込んだカラーパレットを型安全に作る方法

2024/10/07に公開
2

こんにちは。トビ(@0b1tk)です。初めてZennに投稿します!
サイボウズの自社製品「kintone」のデザインシステムを開発・運用するチームで、デザインテクノロジストとしてお仕事をしています。

私たちのチームでは、デザイントークンを「Tokens Studio for Figma」というFigmaプラグインで管理しています。また、デザイントークンやコンポーネントなどをStorybookでドキュメント化しており、カラーにまつわるデザイントークンをまとめたページを社内向けに公開しています。

今回は、StorybookのDoc blocksの「ColorPalette」を使って、デザイントークンを型安全に埋め込んだカラーパレットを作る方法をご紹介します!

カラーパレットの完成形

完成したカラーパレットは、HEX 値を直接入力するのではなく、Tokens Studioで管理しているデザイントークンの値をJSONファイルから取得しています。

そのため、もしデザイントークンの値に変更があっても、カラーパレットは自動的に同期・更新されます。つまり、手動で値を変更する手間が省けるため、ドキュメントの保守性が高まります。

Gray, Red, Blue, Yellow, Greenのカラーパレットが並ぶスクリーンショット

ColorPaletteとは?

Storybookには「Doc blocks」というドキュメント機能のためのコンポーネントがあり、そのうちの一つにデザイントークンを一覧表示することでカラーパレットを作成できる「ColorPalette」があります。

私たちのチームはこれを使って、型安全性を高めつつ、カラーにまつわるデザイントークンを視覚的に確認できるドキュメントを作成しています。

カラーパレットが1, 3色の場合のサンプルが載った公式HPのキャプチャ

ColorPaletteの実装手順

まず、ColorPalette を実装してみましょう。<ColorItem><ColorPalette> で内包して使用します。

<ColorPalette>
  <ColorItem>
    title="グレー"
    subtitle="color.gray"
    colors={{
      "0" : '#FFFFFF',
      "100": '#F8F8F8',
      "200": '#EBEBEB',
      "300": '#DEDEDE',
      "400": '#C6C6C6',
      "500": '#A0A0A0',
      "600": '#808080',
      "700": '#666666',
      "800": '#484848',
      "900": '#333333',
      "1000": '#171717',
      "1100": '#000000'
    }}
  />
</ColorPalette>

上記コードでは、「グレー」の各レベルに対応した色をまとめたカラーパレットを表示します。

Nameの下には<ColorItem> のtitleとsubtitleが表示されていて、Swatchesの下には<ColorItem> のcolorsに渡した {"0" : '#FFFFFF'} といったオブジェクトが表示されています。
Swatchesのカラーパレットは、"0", "100" ..."1100"のように渡したレベル順で反映されているのも確認できました。

しかし、HEX値を直接入力してしまうと、トークン更新を同期的に対応できません。
このままだとデザイントークンの値が変更されても、そのままではStorybookのカラーパレットに反映されないため、手動更新が必要になり、メンテナンスコストが増えてしまいます。

自前のGlobalTokensをカラーパレットに持ってくるには?

さて、ここからが本題です。
デザイントークンのJSONファイルから色のデータを自動的に取得し、変更が即時反映されるカラーパレットを作成するためには、次の手順を進めます。

手順1. コンポーネントとしてtsxファイルを作る
手順2. mdxで表示する

mdxで値を取ることも可能ですが、型安全にするために、ColorPaletteに色を注入したコンポーネントを作ります。そしてそれをmdxファイルに持っていきます。

手順1. コンポーネントとしてtsxファイルを作る

まず、tsconfig.json (TypeScriptの設定ファイル)で、 resolveJsonModuletrue にします。

これにより、TypeScriptファイル内でJSONファイルをインポートできるようになります。つまり、JSON ファイルから色のデータを取得してコンポーネントに渡すことが可能です。

tsconfig.json
{
  "compilerOptions": {
    ...
+   "resolveJsonModule": true
  }
}

次に、colors.tsx ファイルを作成します。

colors.tsx
import { ColorPalette, ColorItem } from '@storybook/addon-docs';
import tokens from '../designTokens/tokens.json';

type JsonValue = {
  value: string;
  type: string; // TokensStudioが出力するjsonは、型がcolorではなくstringなことに注意
  description: string;
};
type ColorList = Record<
  string, // grayなどの色名
  Record<string , JsonValue> // <レベル, 値> (ex. "0", '#FFFFFF')
>;

const colorList: ColorList = tokens.global.color; // JSONファイルから色のリストを取得

const ColorPaletteComponent = () => {
  return (
    <ColorPalette>
      {Object.keys(colorList).map((colorName) => {
        const color = colorList[colorName];
        const colors = Object.keys(color).reduce((prev: Record<string, string>, level) => {
          prev[level] = color[level].value;
          return prev;
        }, {});

        return (
          <ColorItem
            key={colorName}
            title={colorName}
            subtitle={`colors.${colorName}`}
            colors={colors}
          />
        );
      })}
    </ColorPalette>
  );
};


export const Colors = ColorPaletteComponent;

JSONファイルからデータを読み込むため、デザイントークンの変更がカラーパレットに即時反映されるのが大きなメリットです。さらに、TypeScriptを使うことで、mdxファイル単体で実装するよりも型安全性が担保されます。

手順2. mdxで表示する

作成した Colors コンポーネントをmdxファイルに挿入することで、デザイントークンを反映したカラーパレットが表示できるようになり、ドキュメント管理が効率的になりました。

colors.tsx
import { Colors } from '../colors'

<Meta title="designTokens/Color" />
...
<Colors /> // カラーパレットを入れたい任意の箇所に入れる

これで、カラーパレットが正しく表示されるようになり、GlobalTokens を使って色の管理とドキュメント作成がスムーズに行えます。

まとめ

今回ご紹介した方法を使えば、Storybookでカラーパレットを自動的に同期し、メンテナンスの手間を減らすことができます。デザインシステムにおけるカラー管理をより効率的に行うために、ぜひお試しください!

Discussion