Storybookの「ColorPalette」を使って、デザイントークンを埋め込んだカラーパレットを型安全に作る方法
こんにちは。トビ(@0b1tk)です。初めてZennに投稿します!
サイボウズの自社製品「kintone」のデザインシステムを開発・運用するチームで、デザインテクノロジストとしてお仕事をしています。
私たちのチームでは、デザイントークンを「Tokens Studio for Figma」というFigmaプラグインで管理しています。また、デザイントークンやコンポーネントなどをStorybookでドキュメント化しており、カラーにまつわるデザイントークンをまとめたページを社内向けに公開しています。
今回は、StorybookのDoc blocksの「ColorPalette」を使って、デザイントークンを型安全に埋め込んだカラーパレットを作る方法をご紹介します!
カラーパレットの完成形
完成したカラーパレットは、HEX 値を直接入力するのではなく、Tokens Studioで管理しているデザイントークンの値をJSONファイルから取得しています。
そのため、もしデザイントークンの値に変更があっても、カラーパレットは自動的に同期・更新されます。つまり、手動で値を変更する手間が省けるため、ドキュメントの保守性が高まります。
ColorPaletteとは?
Storybookには「Doc blocks」というドキュメント機能のためのコンポーネントがあり、そのうちの一つにデザイントークンを一覧表示することでカラーパレットを作成できる「ColorPalette」があります。
私たちのチームはこれを使って、型安全性を高めつつ、カラーにまつわるデザイントークンを視覚的に確認できるドキュメントを作成しています。
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の設定ファイル)で、 resolveJsonModule
を true
にします。
これにより、TypeScriptファイル内でJSONファイルをインポートできるようになります。つまり、JSON ファイルから色のデータを取得してコンポーネントに渡すことが可能です。
{
"compilerOptions": {
...
+ "resolveJsonModule": true
}
}
次に、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ファイルに挿入することで、デザイントークンを反映したカラーパレットが表示できるようになり、ドキュメント管理が効率的になりました。
import { Colors } from '../colors'
<Meta title="designTokens/Color" />
...
<Colors /> // カラーパレットを入れたい任意の箇所に入れる
これで、カラーパレットが正しく表示されるようになり、GlobalTokens を使って色の管理とドキュメント作成がスムーズに行えます。
まとめ
今回ご紹介した方法を使えば、Storybookでカラーパレットを自動的に同期し、メンテナンスの手間を減らすことができます。デザインシステムにおけるカラー管理をより効率的に行うために、ぜひお試しください!
Discussion
タグと本文中の何箇所かで
ColorPalatte
になっているようですタイポ修正しました!ご指摘いただきありがとうございます!