🔖
StorybookでIconカタログを作成する
はじめに
storybookを使ってデザイナーとコンポーネント管理する中で、アイコンのように挙動が同じだが見た目が違う大量のコンポーネントを、各々コンポーネントとして登録し、1ページ1アイコンで表示するのは把握、確認がとても不便でした。
そこで一覧で表現し、挙動はもう一つのページでも確認できるようにします。
カタログ
先に結果の表示をお見せします。実際のstorybookはこちら
カタログ部分
使用方法の説明とともに、全てのアイコンを展開します。
挙動確認部分
アイコンや色、大きさを切り替えてすべてのコンポーネントの挙動を確認できます。
作成手順
ここでは、storybookの環境設定はできているものとし、src/
配下に登録したい全てのアイコンがある想定で作成していきます。
@storybook/addon-docs
と@storybook/addon-controls
を使用します。
1. manifest作成スクリプト作成
create-manifest.js
const fs = require('fs');
const path = require('path');
// indexファイルはアイコンでないので除外する
const exclusionList = ['index.ts'];
// 対象dirを読む
const files = fs.readdirSync(path.resolve(process.cwd(), `./src`));
// (必要であれば)種類ごとにfieldを分けてdataを作成します。
const data = {
Icons: files
.filter((file) => !exclusionList.includes(file))
.map((file) => file.replace('.tsx', '')),
};
// jsonに書き出します。
fs.writeFileSync('./docs/manifest.json', JSON.stringify(data, null, ' '));
2. スクリプトを実行する
package.json
"build:manifest": "node ./scripts/createManifest.js",
"storybook": "yarn build:manifest && start-storybook -p 6006",
storyの更新が忘れられないようにgithub actionも作成しておきます
check-manifest-update.yml
- name: Generate story
run: yarn build:manifest
- name: '`yarn build:manifest` changes committed?'
run: git diff --exit-code
3. mdxファイルを作成する
アイコンの使用方法や、注意点などがあれば、ここに記載していきます。
<Icons />
部分はアイコンを一覧表示するコンポーネントです
Icons.stories.mdx
import { Meta } from '@storybook/addon-docs/blocks';
import Icons from './Icons';
<Meta title="Icons" />
# Feather Icons
[Feather Svg Icons](https://github.com/feathericons/feather) converted to [Material-UI](https://github.com/mui-org/material-ui) React components. You can install the package by running the following command in your project:
'''sh
# With yarn:
yarn add mui-feather
# With npm:
npm install mui-feather
'''
<Icons />
4. カタログを作成する
作成したmanifest使用して、種類ごとにタイトル区切りをしつつ、アイコンとそのコンポーネント名を同時に展開、表示します。
Icons.tsx
import * as React from 'react';
import * as iconComponents from '../src';
import manifest from './manifest.json';
const Icons = () => {
return Object.keys(manifest).map((key) => {
const files = manifest[key];
if (!Array.isArray(files)) return null;
return (
<div key={key}>
<h3>{key}</h3>
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
{files.map((file) => {
const Icon = iconComponents[`${file}`];
if (!Icon) {
console.log(`could not find icon...: ${file}`);
return null;
}
return (
<div
key={file}
style={{
width: '7.5rem',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
backgroundColor: '#d8d8d8',
color: 'black',
borderRadius: '4px',
marginRight: '8px',
marginBottom: '8px',
padding: '16px',
}}
>
<Icon />
<label htmlFor="id" style={{ marginTop: '8px' }}>
{file}
</label>
</div>
);
})}
</div>
</div>
);
});
};
export default Icons;
5. 挙動確認可能なstoryを作成する
Icons.stories.tsx
import { SvgIconProps } from '@material-ui/core/SvgIcon';
import * as React from 'react';
import * as iconComponents from '../src';
import manifest from './manifest.json';
// manifestから全コンポーネント名を取り出す
const allIcons = Object.values(manifest)
.map((value) => value)
.reduce((a, b) => a.concat(b), []);
// controlできるfieldを設定します。
// @storybook/addon-controlsが必要
export default {
title: 'Icon/Basic',
argTypes: {
component: { control: { type: 'select', options: allIcons } },
fontSize: { control: { type: 'select', options: ['default', 'small', 'large'] } },
color: {
control: {
type: 'select',
options: ['inherit', 'primary', 'secondary', 'disabled', 'error'],
},
},
},
};
interface Props extends SvgIconProps {
component: string;
}
export const Control = (args: Props) => {
const Component = iconComponents[args.component];
return <Component fontSize={args.fontSize} color={args.color} />;
};
Control.args = { component: 'User', fontSize: 'default', color: 'inherit' };
おわりに
簡易なスクリプトとmdxファイルを組み合わせて、アイコンカタログを作成してみました。
デザイン/開発者のコミュニケーションがし易くしつつも、コストをかけ過ぎず、うまくstorybook運用したいですね🤔
Discussion