11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

storybook6のcontrolsまとめ

Posted at

はじめに

本記事では,UIカタログとして利用されるstorybookについて記述します.
storybookにはcontrolsと呼ばれる便利機能があり,コンポーネントなどに与えるデータやプロパティをstorybook上で簡単に変更することができます.新たに作ったUIコンポーネントのテストはもちろん,すでに作られたコンポーネントの挙動を理解するためにも大いに役立ちます.
sample1.gif
storybookのcontrols機能では,前述のように,UIコンポーネントにデータやプロパティを変更できる機能のことです.ここに貼ったgif画像では,bool値であるprimaryの値をスライドボタンで切り替えたり,ボタンのラベルを変更しています.storybookではこのような値の変更方法以外にも,様々な方法が用意されています.本記事はVue.js環境におけるこれらの記述方法を備忘録的にまとめたものです.
本記事では,あくまでcontrolsの記述方法にフォーカスしていますので,storybookそのもののセットアップ方法や概要などを詳しく知りたい方は,公式ドキュメントや,他の方の記事を参照してください.他の方の記事ですが以下の記事は個人的にとてもわかりやすかったです.
参考記事:Vue と CSF によるモダンな Storybook 6 のはじめかた

どんな入力方法があるのか?

storybook公式ドキュメントのcontrolsの項目では,以下のようにまとめられています.
スクリーンショット 2021-08-02 22.09.45.png
15種類のControl Typeがあることがわかります.
以降から,storybookをインストールした直後の環境で動くサンプルコードを載せていきます.作成するファイルは全てsrc/stories/配下に置いていきます.
それでは一つづつ記述方法と動作を確認してみましょう.

boolean

boolean

booleanでは,文字通りtrue,falseの値を切り替えることができるcontrolです.
動作確認用に,bool値を受け取る,flagというpropsを持つsampleコンポーネントを作成します.flagに渡される値によって表示される文字が変化します.

sample.vue
<template>
  <div>
    <p v-if=flag>true</p>
    <p v-else>false</p>
  </div>
</template>

<script>
export default {
  name: 'Sample',

  props: {
    flag: {
      type: Boolean,
      required: true,
    },
  },
};
</script>

次に,sample.vueを呼び出すstories.jsファイルを作成します.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  flag: true, // デフォルト値
};

実際に動作確認してみます.
sample2.gif
flagのトグルボタンによってコンポーネントへ渡されているデータが変化していることがわかります.<sample v-bind="args" />でargsを渡すことで,flag: trueのデフォルト値を渡しているのです.しかし,実際のところ,最後のPrimary.argsは記述せずともほぼ同様に動作します.これは,storybookが非常に賢いために,呼び出されているsample.vueに定義されているpropsを解析して,その型に適した入力方法を表示してくれるのです.つまり,NumberやString,Objectなどの型を指定したpropsなどは,storiesに呼び出してargsをv-bindするだけで利用できるようになります.

Number

Number

前項のsample.vueを少し書き加えてみましょう

sample.vue
<template>
  <div>
    <p v-if=flag>true</p>
    <p v-else>false</p>
    {{ num }} <!-- 追記部分 -->
  </div>
</template>

<script>
export default {
  name: 'Sample',

  props: {
    flag: {
      type: Boolean,
      required: false,
    },
    num : { // 追記部分
      type: Number,
      default: 0,
    }
  },
};
</script>

propsに数字を受け取るように書き換えました.実行結果はこんな感じ.
sample3.gif

Number(range)

rengeでは,Number型のインプットをスライドバー形式で操作ができるようになります.通常のNumberとは異なり,必ずstoriesファイルで追記が必要になります.

sample.vue
<template>
  <div>
    {{ rangeNum }}
  </div>
</template>

<script>
export default {
  name: 'Sample',

  props: {
    rangeNum : {
      type: Number,
      default: 0,
    }
  },
};
</script>

storiesファイルのargTypesプロパティを指定します.今回は,rangeNumという変数をcontrol type:'range'で指定します.デフォルト値を指定したい場合はargsで指定してあげましょう.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  // ここの記述がポイント
  argTypes: {
    rangeNum: {
      control: {
        type: 'range',
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  rangeNum: 0, // デフォルト値
};

sample5.gif

Object

Object

コンポーネントにObjectを受け取るpropsを用意し,storiesファイルでObject型の変数を渡してあげます.argTypesの記述は必要ありません(もちろん明示的に記述しても構いません).

sample.vue
<template>
  <div>
    {{ sampleObject }}
  </div>
</template>

<script>
export default {
  name: 'Sample',

  props: {
    sampleObject: {
      type: Object,
      required: false,
      default: {},
    },
  },
};
</script>
sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  sampleObject: {
    apple: 'red',
    grape: 'purple',
  },
};

実行結果はこんな感じ
sample6.gif

Array

Array

ArrayもObjectと同様に,Array型の変数を受け取るpropsを用意してあげて,storiesファイルでpropsにArray型の変数を渡してあげます.

sample.vue
<template>
  <div>
    {{ sampleArray }}
  </div>
</template>

<script>
export default {
  name: 'Sample',

  props: {
    sampleArray: {
      type: Array,
      required: false,
      default: [],
    },
  },
};
</script>
sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  sampleArray: ['a', 'b', 'c'],
};

実行結果はこんな感じ
sample7.gif

Array(file)

ファイルをinputすることもできます(あまり使う機会はなさそう).
Arrayのサンプルコンポーネントをそのまま流用して,storiesファイルのみ書き換えていきます.fileの場合はargTypesを記述します.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  // ここがポイント
  argTypes: {
    sampleArray: {
      control: {
        type: 'file',
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  sampleArray: [],
};

実行結果はこんな感じ
sample8.gif

enum

enumではいわゆる選択式のデータの渡し方を記述できます.6種類の入力方法があります.この6種類は基本的に描き方が同様です.
### radio
radioでは,storiesファイルのargTypesのtypeにradioを指定し,選択肢をoptionsに配列として記述します.

sample.vue
<template>
  <div>
    {{ fruit }}
  </div>
</template>

<script>
export default {
  name: 'Sample',

  props: {
    fruit: {
      type: String,
      required: false,
      default: '',
    },
  },
};
</script>
sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    fruit: {
      control: {
        type: 'radio', // ここと,
        options: ['apple', 'banana', 'grape', 'orange'], // ここ
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  fruit: 'apple',
};

実行結果はこんな感じ
sample9.gif

実際に渡したいデータにラベルを指定したい場合は,argTypesにlabelsを以下のようにオブジェクト形式で記述してあげると実現できます.vueファイルの変更はありません.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    fruit: {
      control: {
        type: 'radio',
        options: ['apple', 'banana', 'grape', 'orange'],
        labels: { // ここでラベルを指定する
          apple: 'りんご',
          banana: 'ばなな',
          grape: 'ぶどう',
          orange: 'オレンジ'
        },
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  fruit: 'apple',
};

実行結果はこんな感じ
sample10.gif

inline-radio

radioの選択肢を選択肢ごとに改行せずに横並びに表示します.radioの記述方法と同様で,argTypesのtypeinline-radioにすることで動作します.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    fruit: {
      control: {
        type: 'inline-radio', // 変えるのはここだけ
        options: ['apple', 'banana', 'grape', 'orange'],
        labels: {
          apple: 'りんご',
          banana: 'ばなな',
          grape: 'ぶどう',
          orange: 'オレンジ'
        },
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  fruit: 'apple',
};

実行結果はこんな感じ
sample11.gif

選択肢の数が多い場合やラベルの文字列が長い場合はradio,そうでない場合はinline-radioを使うのがいいかと思います.

check

checkradioと記述方法は同様ですが,複数選択が可能で,入力を配列としてコンポーネントに渡します.
vueファイルはradioと同様です.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    fruit: {
      control: {
        type: 'check', // 変えるのはここだけ
        options: ['apple', 'banana', 'grape', 'orange'],
        labels: {
          apple: 'りんご',
          banana: 'ばなな',
          grape: 'ぶどう',
          orange: 'オレンジ'
        },
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  fruit: 'apple',
};

実行結果はこんな感じ
sample12.gif

inline-check

checkの選択肢を選択肢ごとに改行せずに横並びに表示します.checkの記述方法と同様で,argTypesのtypeinline-checkにすることで動作します.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    fruit: {
      control: {
        type: 'inline-check', // 変えるのはここだけ
        options: ['apple', 'banana', 'grape', 'orange'],
        labels: {
          apple: 'りんご',
          banana: 'ばなな',
          grape: 'ぶどう',
          orange: 'オレンジ'
        },
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  fruit: 'apple',
};

実行結果はこんな感じ
sample13.gif
radio同様,選択肢の数が多い場合やラベルの文字列が長い場合はcheck,そうでない場合はinline-checkを使うのがいいかと思います.

select

selectでは,プルダウン形式で単一の選択肢を行うことができます.
他のenumと同様の記述方法で,argTypesのtypeselectにすることで動作します.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    fruit: {
      control: {
        type: 'select', // 変えるのはここだけ
        options: ['apple', 'banana', 'grape', 'orange'],
        labels: {
          apple: 'りんご',
          banana: 'ばなな',
          grape: 'ぶどう',
          orange: 'オレンジ'
        },
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  fruit: 'apple',
};

実行結果はこんな感じ
sample14.gif

radioとの使い分けは,より選択肢が多い場合にselect,そうでもない時にradioを使うのがいいかと思います.

multi-select

selectのようなUIで,複数選択できるようにしたものがmulti-selectです.ctrlキーを押しながら選択することで複数選択が出入るようになります.
選択されたデータは配列の形でコンポーネントに渡されます.
他のenumと同様の記述方法で,argTypesのtypemulti-selectにすることで動作します.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    fruit: {
      control: {
        type: 'multi-select', // 変えるのはここだけ
        options: ['apple', 'banana', 'grape', 'orange'],
        labels: {
          apple: 'りんご',
          banana: 'ばなな',
          grape: 'ぶどう',
          orange: 'オレンジ'
        },
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

Primary.args = {
  fruit: 'apple',
};

実行結果はこんな感じ
sample15.gif

string

String

コンポーネントにtype: Stringのpropsを追加することで表示することができます.argTypesの指定は必要ありません(明示的に指定しても当然動作します.).

sample.vue
<template>
  <div>
    {{ message }} <!-- 変更部分 -->
  </div>
</template>

<script>
export default {
  name: 'Sample',

  props: {
    message: { // 変更部分
      type: String,
      required: false,
      default: '',
    },
  },
};
</script>

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

sample4.gif

color

colorを用いることで,カラーパレットを使ってカラーコードを指定することができるようになります.
argTypesでtypeにcolorを指定することで実現できます.
vueファイルはstringと同様です.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    fruit: {
      control: {
        type: 'color', // ここで指定
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

実行結果はこんな感じ
sample16.gif

date

dateを用いることでカレンダーから日付と時刻を選択することができるようになります.
コンポーネントに渡される値はUNIX Time形式になります.

argTypesでtypeにdateを指定することで実現できます.
vueファイルはstringと同様です.

sample.stories.js
import Sample from './sample.vue';

export default {
  title: 'Example/Sample',
  component: Sample,
  argTypes: {
    fruit: {
      control: {
        type: 'date', // ここで指定
      },
    },
  },
};

const Template = (args) => ({
  components: { Sample },
  setup() {
    return { args };
  },
  template: '<sample v-bind="args" />',
});

export const Primary = Template.bind({});

実行結果はこんな感じ
sample17.gif

おわりに

この記事ではStoryBook6に用意されているconnrols addonを一通り動かしてみました.これらを組み合わせると非常にリッチなコンポーネントのカタログを作成することができます.
storybookをつかった開発にお役立ていただけたら幸いです.

11
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?