かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

React+Tailwind CSS+Storybook のプロジェクトを作成する(Typescript 版)

概要

記事一覧はこちらです。

React+Tailwind CSS+Storybook のプロジェクトを作成する の Typescript 版を作成します。React+Tailwind CSS+Storybook のプロジェクトを作成する からの差分だけ記述します。

GitHub はこちら
https://github.com/ksby/react-ts-taiwindcss-storybook-sample

参照したサイト・書籍

  1. Storybook - TypeScript
    https://storybook.js.org/docs/react/configure/typescript

  2. React Typescript storybook implement customized Input component with onChange callBack then setState value backTo Input
    https://stackoverflow.com/questions/64719744/react-typescript-storybook-implement-customized-input-component-with-onchange-ca

    • .stories.tsx の書き方はこの QA を参考にしました。

目次

  1. create-react-app ... --template typescript で react-ts-taiwindcss-storybook-sample プロジェクトを作成する
  2. 「Tailwind CSS をインストールする」~「src/index.css を変更する」は同じ
  3. src/App.tsx を変更する
  4. 「npx sb init コマンドを実行して Storybook をインストールする」~「src/stories を削除する」は同じ
  5. Typescript で component のサンプルを作成して Storybook 上に表示する+Storybook 用の .stories.tsx も Typescript で記述する

手順

create-react-app で react-ts-taiwindcss-storybook-sample プロジェクトを作成する

以下のコマンドを実行し react-ts-taiwindcss-storybook-sample プロジェクトを作成します。

  • npx create-react-app react-ts-taiwindcss-storybook-sample --template typescript

「Tailwind CSS をインストールする」~「src/index.css を変更する」は同じ

以下の手順は同じです。

src/App.tsx を変更する

src/App.tsx を以下のように変更します。

import { FC } from 'react';

import './App.css';

const App: FC = () => (
  <div className="pt-4 pl-4 text-red-600 text-4xl font-extrabold">
    React+Tailwind CSS
  </div>
);

export default App;

「npx sb init コマンドを実行して Storybook をインストールする」~「src/stories を削除する」は同じ

以下の手順は同じです。

Typescript で component のサンプルを作成して Storybook 上に表示する+Storybook 用の .stories.tsx も Typescript で記述する

Storybook - TypeScript を読むと Storybook は built-in で Typescript をサポートしており、特に追加で設定する必要はない模様。

React Typescript storybook implement customized Input component with onChange callBack then setState value backTo Input を参考に component のサンプルを実装します。

まずは src/components/sample/ListItem.tsx から。

import { FC } from 'react';

export type ListItemProps = {
  image: string;
  title: string;
  author: string;
};

const ListItem: FC<ListItemProps> = ({ image, title, author }) => (
  <article className="p-2 flex space-x-4">
    <img className="flex-none w-16 h-16 rounded-lg" src={image} alt="" />
    <div>
      <dl>
        <div>
          <dt className="sr-only">Title</dt>
          <dd className="text-2xl font-bold">{title}</dd>
        </div>
        <div className="mt-0.5">
          <dt className="sr-only">Author</dt>
          <dd className="text-sm font-semibold text-indigo-500">By {author}</dd>
        </div>
      </dl>
    </div>
  </article>
);

export default ListItem;

src/components/sample/ListItem.stories.tsx は以下の内容を記述します。

import React from 'react';
import { Story } from '@storybook/react';

import ListItem, { ListItemProps } from './ListItem';
import dog from './dog.jpg';

export default {
  title: 'sample/ListItem',
  component: ListItem,
};

const Template: Story<ListItemProps> = (args: ListItemProps) => (
  <ListItem image={args.image} title={args.title} author={args.author} />
);

export const Default: Story<ListItemProps> = Template.bind({});
Default.args = {
  image: dog,
  title: 'サンプルブック1',
  author: '作者は犬',
};

次は src/components/sample/List.tsx

import React, { FC } from 'react';

import ListItem, { ListItemProps } from './ListItem';

export type ListProps = {
  items: ListItemProps[];
};

const List: FC<ListProps> = ({ items }) => (
  <ul className="divide-y divide-gray-600">
    {items.map((item) => (
      <ListItem
        key={item.title}
        image={item.image}
        title={item.title}
        author={item.author}
      />
    ))}
  </ul>
);

export default List;

src/components/sample/List.stories.tsx は以下の内容を記述します。

import React from 'react';
import { Story } from '@storybook/react';

import List, { ListProps } from './List';
import dog from './dog.jpg';
import cat from './cat.jpg';
import tiger from './tiger.jpg';

export default {
  title: 'sample/List',
  component: List,
};

const Template: Story<ListProps> = (args: ListProps) => (
  <List items={args.items} />
);

export const Default: Story<ListProps> = Template.bind({});
Default.args = {
  items: [
    {
      image: dog,
      title: 'サンプルブック1',
      author: '作者は犬',
    },
    {
      image: cat,
      title: 'サンプルブック2',
      author: '作者は猫',
    },
    {
      image: tiger,
      title: 'サンプルブック3',
      author: '作者はトラ',
    },
  ],
};

履歴

2021/04/20
初版発行。