いろいろな Storybook Doc blocks
こんにちは。フロントエンドエンジニアの辻です。
前回に引き続き、他の Storybook Doc blocks について触れていこうと思います。
Storybook Docs ページのカスタマイズ
Storybook Doc blocks に触れていく前に、まず Docs ページのカスタマイズ方法を紹介します。
前回の Typeset のサンプルコードでチラリと登場していましたが、Storybook v7 では Docs ページのテンプレートを簡単にカスタマイズできます。
例えば、以下のような Tag コンポーネントとその Storybook ファイルがあるとします。
import { PropsWithChildren } from 'react'
type Tag = {
type?: 'primary' | 'secondary'
}
export const Tag = ({ type = 'primary', children }: PropsWithChildren<Tag>) => {
return (
<span
className={`
${type === 'primary' ? 'border-blue-500' : 'border-green-500'}
${type === 'secondary' ? 'text-blue-500' : 'text-green-500'}
font-bold py-1 px-2 rounded inline-flex border text-sm`}
>
{children}
</span>
)
}
import type { Meta, StoryObj } from '@storybook/react'
// ↓@storybook/blocks から import …(①)
import {
Title,
Subtitle,
Description,
Primary,
Controls,
Stories
} from '@storybook/blocks'
import { Tag } from './tag'
const meta = {
title: 'Components/Tag',
component: Tag,
parameters: {
layout: 'centered',
docs: {
// ↓ meta オブジェクトの parameters.docs.page に Stoybook Doc blocks を返す関数をセットします …(②)
page: () => (
<>
<Title />
<Subtitle />
<Description />
<Primary />
<Controls />
<Stories />
</>
)
}
},
argTypes: {
type: {
options: ['primary', 'secondary'],
control: { type: 'radio' }
}
}
} satisfies Meta<typeof Tag>
export default meta
type Story = StoryObj<typeof meta>
export const PrimaryTag: Story = {
args: {
children: 'Primary タグ',
type: 'primary'
}
}
export const SecondaryTag: Story = {
args: {
children: 'Secondary タグ',
type: 'secondary'
}
}
肝となるのは、@storybook/blocks から import した Doc Blocks コンポーネント群(①)と、meta オブジェクトの parameters.docs.page
にセットした関数(②)です。
parameters.docs.page
の関数にて返される結果が、そのまま Docs ページの内容となります。したがって、この関数の返り値を調整する事で Docs ページを柔軟にカスタマイズできます。
自作したコンポーネントを parameters.docs.page
の関数の返り値に含める事も可能です。
また、一つ一つの .stories.tsx を変更せずとも、.storybook/preview.tsx を更新する事で、すべての Docs ページのカスタマイズが可能です。
Storybook 公式サイトの Write a custom template にある通り、.storybook/preview.tsx を以下のように更新すれば、すべての Docs ページが preview.parameters.docs.page
の関数の返り値の形式になります。
import { Preview } from '@storybook/your-framework';
// ↓@storybook/blocks から import
import { Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/blocks';
const preview: Preview = {
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
// preview.parameters.docs.page に Doc blocks を返す関数をセットします
docs: {
page: () => (
<>
<Title />
<Subtitle />
<Description />
<Primary />
<Controls />
<Stories />
</>
),
},
},
};
export default preview;
いろいろな Storybook Doc blocks
さて、Docs ページのカスタマイズ方法が分かったところで、公式で用意されているいろいろな Storybook Doc blocks を見ていこうと思います。
Source
文字通り、コンポーネントのソースコードを表示する block です。
先程の Tag コンポーネントで使ってみます。
import type { Meta, StoryObj } from '@storybook/react'
import { renderToStaticMarkup } from 'react-dom/server' // ← 新規追加
import {
Title,
Subtitle,
Description,
Primary,
Controls,
Stories,
Source // ← 新規追加
} from '@storybook/blocks'
import { Tag } from './tag'
// …略…
// ↓ 新規追加
export const SourceStory: Story = {
render: () => <Source code={renderToStaticMarkup(<Tag>タグ</Tag>)} />
}
Stroybook を起動すると、下記のようなコードスニペットが表示されます。
「Copy」ボタンからコンポーネントのソースコードをコピーできます。
React や Vue のような JavaScript フレームワークを使わずに、シンプルなHTML・CSS で UI を構築している場合に重宝するでしょう。
ColorPalette
ColorPalette はカラーを一覧化するために利用します。
使い方は ColorPalette コンポーネントを用意して、その中に ColorItem コンポーネントを列挙していくのみです。
その際に、ColorItem コンポーネントの colors
に表示するカラーをオブジェクト形式で登録していきます。
例えば、以下のような colors.stories.tsx を用意した上で Stroybook を起動してみます。
import type { Meta, StoryObj } from '@storybook/react'
import { Title, ColorPalette, ColorItem } from '@storybook/blocks'
const BlankComponent = () => <div></div>
const meta: Meta<typeof BlankComponent> = {
title: 'Components/Colors',
component: BlankComponent,
parameters: {
docs: {
page: () => (
<>
<Title>Colors</Title>
<ColorPalette>
<ColorItem
title='theme.color.gray'
subtitle='gray colors'
colors={{
'50': '#f9fafb',
'100': '#f3f4f6',
'200': '#e5e7eb',
'300': '#d1d5db',
'400': '#9ca3af',
'500': '#6b7280',
'600': '#4b5563',
'700': '#374151',
'800': '#1f2937',
'900': '#111827',
'950': '#030712'
}}
/>
<ColorItem
title='theme.color.blue'
subtitle='blue colors'
colors={{
'50': '#eff6ff',
'100': '#dbeafe',
'200': '#bfdbfe',
'300': '#93c5fd',
'400': '#60a5fa',
'500': '#3b82f6',
'600': '#2563eb',
'700': '#1d4ed8',
'800': '#1e40af',
'900': '#1e3a8a',
'950': '#172554'
}}
/>
<ColorItem
title='theme.color.green'
subtitle='green colors'
colors={{
'50': '#f0fdf4',
'100': '#dcfce7',
'200': '#bbf7d0',
'300': '#86efac',
'400': '#4ade80',
'500': '#22c55e',
'600': '#16a34a',
'700': '#15803d',
'800': '#166534',
'900': '#14532d',
'950': '#052e16'
}}
/>
</ColorPalette>
</>
)
}
}
}
export default meta
type Story = StoryObj<typeof BlankComponent>
export const Base: Story = {
render: () => <BlankComponent />
}
すると、以下のようなカラーの一覧が表示されます。
プロジェクトで利用するカラーをまとめるのに便利ですね。
IconGallery
IconGallery はアイコンを一覧化するためのモノで、ColorPalette と使い方が似ています。
IconGallery の場合は、IconGallery コンポーネントを用意して、その中に IconItem コンポーネントを列挙していくのみです。
例えば、以下のような icon.stories.tsx を用意した上で Stroybook を起動してみます。
import type { Meta, StoryObj } from '@storybook/react'
import { Title, IconGallery, IconItem } from '@storybook/blocks'
const BlankComponent = () => <div></div>
const meta: Meta<typeof BlankComponent> = {
title: 'Components/Icons',
component: BlankComponent,
parameters: {
docs: {
page: () => (
<>
<Title>Icons</Title>
<IconGallery>
<IconItem name='Arrow up'>
<img src='/assets/images/icons/arrow-up.svg' alt='arrow up' />
</IconItem>
<IconItem name='Arrow right'>
<img
src='/assets/images/icons/arrow-right.svg'
alt='arrow right'
/>
</IconItem>
<IconItem name='Arrow left'>
<img src='/assets/images/icons/arrow-left.svg' alt='arrow left' />
</IconItem>
<IconItem name='Arrow down'>
<img src='/assets/images/icons/arrow-down.svg' alt='arrow down' />
</IconItem>
<IconItem name='Cloud'>
<img src='/assets/images/icons/cloud.svg' alt='cloud' />
</IconItem>
<IconItem name='Cloud upload'>
<img
src='/assets/images/icons/cloud-upload.svg'
alt='cloud-upload'
/>
</IconItem>
<IconItem name='Cloud download'>
<img
src='/assets/images/icons/cloud-download.svg'
alt='cloud-download'
/>
</IconItem>
<IconItem name='Copyright'>
<img src='/assets/images/icons/copyright.svg' alt='copyright' />
</IconItem>
</IconGallery>
</>
)
}
}
}
export default meta
type Story = StoryObj<typeof BlankComponent>
export const Base: Story = {
render: () => <BlankComponent />
}
すると、以下のようなアイコンの一覧が表示されます。
プロジェクトで利用するアイコンをまとめるのに便利です。
まとめ
Stroybook に備わったいろいろな Storybook Doc blocks を見てきました。
Storybook を導入した際に、UI を Storybook で閲覧できるようにするだけで留まってしまう場合も多いですが、Storybook Doc blocks を使ってカスタマイズすれば、よりプロジェクト全体のUIを見通しやすくなります。
今すぐの転職でなくてもOKです!まずはお話しませんか?
現在弊社では一緒にお仕事をしてくださるエンジニアさんやデザイナーさんを積極募集しています。まずはカジュアルな面談で、お互いに大事にしていることをお話できたらうれしいです。詳しい応募要項は以下からチェックしてください。
- React, Next.js を得意とするフロントエンドエンジニア募集要項
- シニアクラスのフロントエンドエンジニア募集要項
- 抽象的な物事を具体的な機能にビジュアライズできるUIデザイナー募集要項
- UIデザイナーとして手ざわりのいいUIを作りたい業務委託パートナーさん募集(Wantedly)
パートナー契約へのお問い合わせもお仕事へのお問い合わせも、どちらもいつでも大歓迎です。まずはオンラインでの面談でお話しましょう。ぜひお気軽にお問い合わせください!
話をしてみたい!