Back to Design Systems for Developers
React
Chapters
  • イントロダクション
  • 設計
  • 構築
  • レビュー
  • テスト
  • ドキュメント
  • 配布
  • ワークフロー
  • 結論

UIコンポーネントを構築する

Storybook をセットアップしデザインシステムコンポーネントを構築してカタログ化する
このコミュニティの翻訳は、最新の Storybook バージョンに対応していません。英語ガイドの最新の変更を適用して、この日本語ガイドの更新にご協力ください。 Pull requests を大歓迎します。.

第 3 章では、まずは、最も普及しているコンポーネントエクスプローラーである Storybook から、デザインシステムに必要な道具をセットアップを行います。当ガイドのゴールは専門的なチームがデザインシステムをどのように構築しているかを披露し、またコードの簡潔化、時間を節約する Storybook のアドオン、ディレクトリ構造のような洗練された具体例に焦点を当てます。

Where Storybook fits in

清潔に保つためのコードフォーマットと静的解析

デザインシステムは協働的です、そのため構文を統制し書式を標準化するツールが貢献の質を向上させるために役立ちます。ツールでコードの一貫性を強制することは手作業でコードをきれいにするより労力をかけず、やりくり上手なデザインシステムの作成者にとって有益です。

当チュートリアルで、私たちはエディタに VSCode を使いますが、AtomSublimeIntelliJ のような他のモダンエディタにも同様の方針を適用できます。

プロジェクトに Prettier を加えエディタを適切にセットアップすれば、あまり考えることなく一貫したフォーマットを手に入れるでしょう:

Copy
yarn add --dev prettier

初めて Prettier を使うなら、エディタ向けにセットアップする必要があるかもしれません。VSCode で、Prettier アドオンをインストールしてください:

Prettier addon for VSCode

まだ実施していなければ VSCode の設定で「Format On Save」(editor.formatOnSave)を有効にしてください。Prettier をインストールすると、ファイルを保存する度にコードが自動フォーマットされるのが分かります。

Storybook をインストール

Storybook は UI コンポーネントを独立して開発するための業界標準のコンポーネントエクスプローラです。デザインシステムは UI コンポーネントに焦点を当てているため、Storybook はそのユースケースに理想のツールです。以下の特徴があります:

  • 📕UI コンポーネントの一覧化
  • 📄 ストーリーとしてコンポーネントのバリエーションを保存
  • ⚡️ ホットモジュールリロードのような開発者体験のツール化
  • 🛠React を含む、多くのビューレイヤーをサポート

Storybook をインストールし実行します。

Copy
# Installs Storybook
npx sb init

# Starts Storybook in development mode
yarn storybook

こちらの画面が見えるでしょう:

Initial Storybook UI

いいですね、コンポーネントエクスプローラをセットアップしました!

アプリケーションに Storybook をインストールするたびに、stories フォルダ内にいくつかのサンプルが追加されます。興味があれば、それを探索してみてください。しかし私たちのデザインシステムには必要ないでしょうから、stories ディレクトリを削除しても問題ありません。

さてあなたの Storybook は次のようになっているでしょう (フォントスタイルがやや小さくなっているのに気づきます、例として、「Avatar: Initials」ストーリーを見てください):

グローバルスタイルを追加する

私たちのデザインシステムにはコンポーネントを正しく描画するためにドキュメントに適用するグローバルスタイル (CSS リセット) が必要です。Styled Components のグローバルスタイルタグで簡単に追加できます。次のように src/shared/global.js ファイルを更新します:

Copy
src/shared/global.js
import { createGlobalStyle, css } from 'styled-components';

import { color, typography } from './styles';

+ export const fontUrl = 'https://fonts.googleapis.com/css?family=Nunito+Sans:400,700,800,900';

export const bodyStyles = css`
  /* Same as before */
`;

export const GlobalStyle = createGlobalStyle`
 body {
   ${bodyStyles}
 }`;

Storybook で GlobalStyle「コンポーネント」を使うために、デコレーター (コンポーネントのラッパー) を使うことができます。アプリでは、トップレベルのアプリレイアウトにそれを配置するでしょうが、Storybook では、プレビューコンフィグファイル .storybook/preview.js を使って全てのストーリーをラップします。

Copy
.storybook/preview.js
+ import React from 'react';

+ import { GlobalStyle } from '../src/shared/global';

/*
 * Global decorator to apply the styles to all stories
 * Read more about them at:
 * https://storybook.js.org/docs/react/writing-stories/decorators#global-decorators
 */
+ export const decorators = [
+   Story => (
+     <>
+       <GlobalStyle />
+       <Story />
+     </>
+   ),
+ ];

/*
 * Read more about global parameters at:
 * https://storybook.js.org/docs/react/writing-stories/parameters#global-parameters
 */
export const parameters = {
  actions: { argTypesRegex: '^on[A-Z].*' },
};

デコレーターはどんなストーリーを選択しても GlobalStyle の描画を保証します。

💡 デコレーターの<>は打ち間違えではありません。これは React Fragment というもので不必要な別のHTMLタグのアウトプットを避けるためここで使用しています。

フォントタグを追加する

私たちのデザインシステムはまたアプリにロードした Nunito Sans フォントに依存しています。その実現方法はアプリのフレームワーク (それについてここで読めます) によりますが、Storybook で最も簡単な方法は、ファイル .storybook/preview-head.html を作成し、ページの<head>タグに直接<link>タグを追加することです:

Copy
.storybook/preview-head.html
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Nunito+Sans:400,700,800,900" />

Storybook では次のように見えるはずです。グローバルフォントスタイルを追加しましたので「T」が sans-serif になっているのが分かります。

Storybook with global styles loaded

アドオンで Storybook を強化する

Storybook は大規模コミュニティにより作られた強力なアドオンのエコシステムを含んでいます。実践的な開発者にとって、カスタムツールを私たち自身で作成 (それは時間がかかるでしょう) するよりそのエコシステムを使ってワークフローを組み立てる方が簡単です。

インタラクティビティを検証する Actions アドオン

Actions アドオンはボタンやリンクのようなインタラクティブな要素でアクションが振る舞われると Storybook で UI フィードバックを提供してくれます。アクションはデフォルトで Storybook にインストールされており、コンポーネントにコールバックプロパティとして「アクション」を渡すだけで使えます。

私たちのボタン要素で使い方を見てみましょう、それはクリックに反応するラッパーコンポーネントを任意で取ります。そのラッパーにアクションを渡すストーリーを用意しています:

Copy
src/Button.stories.js
import React from 'react';

import styled from 'styled-components';

// When the user clicks a button, it will trigger the `action()`,
// ultimately showing up in Storybook's addon panel.
function ButtonWrapper(props) {
  return <CustomButton {...props} />;
}

export const buttonWrapper = (args) => (
  return <CustomButton {...props}/>;
// … etc ..
)

コンポーネントをストレステストするための Controls アドオン

インストールしたばかりの Storybook には Controls アドオンがすでにすぐ使えるように設定されています。

Controls アドオンは Storybook の UI でコンポーネントのインプット (props) を動的にインタラクションできるようにします。あなたは arguments (args) を介してコンポーネントに複数の値を提供し UI に適用できます。argument の値を適用してデザインシステムの作成者がコンポーネントのインプット (props) をストレステストする手助けをします。またデザインシステムの利用者が各インプット (props) がコンポーネントにどう影響するのか組み込む前に理解するのを試す機能を提供します。

src/Avatar.stories.js にある Avatar コンポーネントに新しいストーリーを加えるとどうなるか見てみましょう:

Copy
src/Avatar.stories.js
import React from 'react';

import { Avatar } from './Avatar';

export default {
  title: 'Design System/Avatar',
  component: Avatar,
  /*
   * More on Storybook argTypes at:
   * https://storybook.js.org/docs/react/api/argtypes
   */
  argTypes: {
    size: {
      control: {
        type: 'select',
      },
      options: ['tiny', 'small', 'medium', 'large'],
    },
  },
};

// Other Avatar stories

/*
 * New story using Controls
 * Read more about Storybook templates at:
 * https://storybook.js.org/docs/react/writing-stories/introduction#using-args
 */
const Template = args => <Avatar {...args} />;

export const Controls = Template.bind({});
/*
 * More on args at:
 * https://storybook.js.org/docs/react/writing-stories/args
 */
Controls.args = {
  loading: false,
  size: 'tiny',
  username: 'Dominic Nguyen',
  src: 'https://avatars2.githubusercontent.com/u/263385',
};

アドオンパネルの Controls タブを見てください。Controls はプロパティを適用するグラフィカル UI を自動生成します。例えば、「size」セレクト要素が提供されている Avatar のサイズ tinysmallmediumlarge を通しで確認できます。残りのコンポーネントプロパティ (「loading」、「username」、「src」) も同様に、コンポーネントのストレステストにユーザーフレンドリーな方法を提供してくれます。

かと言って、Controls アドオンはストーリーの代わりにはなりません。Controls アドオンでの操作はコンポーネントのエッジケースを探すのに優れており、ストーリーは想定された状態を陳列する (見せる) ことに優れています。

addon-interactionsを使った対話型のストーリー

私たちは Controls のアドオンを使ってどのように Storybook のアドオンがエッジケースを探す手助けをし Actions アドオンを使ってコンポーネントがインタラクションした時にどのように振る舞うのかを見てきました。それでも、ストーリーを追加した各バリエーションで、手動で確認してデザインシステムが壊れないかを見なければなりません。@storybook/addon-interactions アドオンを追加してどのようにこれを自動化するか見てみましょう、それからPlayファンクションを使いコンポーネントとインタラクションします:

次のコマンドを実行してアドオンと依存関係をインストールします:

Copy
yarn add --dev @storybook/addon-interactions @storybook/testing-library

次に、Storybook の設定ファイル (この場合は、.storybook/main.js ) に登録します:

Copy
./storybook/main.js
module.exports = {
  stories: [
     '../src/**/*.stories.mdx',
     '../src/**/*.stories.@(js|jsx|ts|tsx)',
  ],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/preset-create-react-app',
+   '@storybook/addon-interactions',
  ],
  framework: "@storybook/react",
  staticDirs: ["../public"],
};

では、Button に新しいストーリーを追加してどう動くか見てみましょう:

Copy
src/Button.stories.js
import React from 'react';
import styled from 'styled-components';
+ import { userEvent, within } from '@storybook/testing-library';
import { Button } from './Button';
import { StoryLinkWrapper } from './StoryLinkWrapper';
export default {
  title: 'Design System/Button',
  component: Button,
};

// Other Button stories

+ // New story using the play function
+ export const WithInteractions = () => (
+   <Button
+     ButtonWrapper={StoryLinkWrapper}
+     appearance="primary"
+     href="http://storybook.js.org">
+       Button
+    </Button>
+ );
+ WithInteractions.play = async ({ canvasElement }) => {
+   // Assigns canvas to the component root element
+   const canvas = within(canvasElement);
+   await userEvent.click(canvas.getByRole("link"));
+ };

+ WithInteractions.storyName = "button with interactions";
💡 Play ファンクションは小さなコードスニペットで、ストーリーが描画を完了すると、addon-interactionsによる助けを借りて、人の手を介しないと不可能なシナリオをテストできます。詳しくは公式ドキュメントを参照ください。

作成したストーリーを選択すれば、コンポーネントがどう振る舞っているか、一貫性を保っているかどうかを確認する方法がわかります。ちょっとした手間をかけることで、人間の操作に頼らずに、デザインシステムを強靭でバグのないものにすることができます。

後の章で Accessibility と Docs のアドオンについて確認します。

“Storybook はチームがビジネスロジックと複雑なシステムにつまづくことなく UI コンポーネントをデザインし、構築し、組織化 (それもフルスクリーンで!) できる強力なフロントエンド作業環境だ。” – Brad Frost、Atomic Design の著者

メンテナンス自動化の方法を学ぶ

さあこれで私たちのデザインシステムコンポーネントが Storybook に入りました。業界標準のデザインシステムを作るためにもう一歩足を踏み出したのです。今がリモートリポジトリに成果をコミットする素晴らしい瞬間です。そして継続的なメンテナンスを合理化する自動化ツールについて考えることができます。

全てのソフトウェアのように、デザインシステムも発展するものです。デザインシステムが成長するに従い、UI コンポーネントが意図したとおりの外観と操作性を維持できることが課題です。

第 4 章では、継続的インテグレーションをセットアップし、協働のためにデザインシステムをオンラインで自動配信する方法を学びます。

Keep your code in sync with this chapter. View c5f4c8d on GitHub.
Is this free guide helping you? Tweet to give kudos and help other devs find it.
Next Chapter
レビュー
継続的インテグレーションとビジュアルレビューで協働する
✍️ Edit on GitHub – PRs welcome!
Join the community
6,623 developers and counting
WhyWhy StorybookComponent-driven UI
Open source software
Storybook

Maintained by
Chromatic
Special thanks to Netlify and CircleCI