# Fumadocs (Framework Mode, TanStack Start): ストーリー
URL: /ja/docs/tanstack-start/integrations/story
Source: https://raw.githubusercontent.com/fuma-nama/fumadocs/refs/heads/main/apps/docs/content/docs/(framework)/[framework]/integrations/story/index.ja.mdx

コントロール付きでコンポーネントを表示します。

<story.WithControl />

## はじめに [#introduction]

Fumadocs Story は、コンポーネントを表示し、ドキュメント化するためのツールです。
[Storybook](https://storybook.js.org) に代わる、ドキュメントに特化したシンプルなツールで、主にコンポーネントライブラリ向けに設計されています。

ストーリーという概念を初めて知る方のために、**Storybook** のドキュメントから簡単な説明を引用します。

<blockquote>
  ストーリーは、UI コンポーネントのレンダリングされた状態を捉えたものです。アノテーションを持つオブジェクトであり、
  一連の引数が与えられたときのコンポーネントの振る舞いと外観を記述します。
</blockquote>

<Callout title="Storybook ではなくこちらを使うべきなのはどんなとき？">
Fumadocs Story は Storybook を置き換えるものではありません。本格的な UI テストには、引き続き Storybook をおすすめします。
</Callout>

## インストール [#installation]

```npm
npm i @fumadocs/story
```

Tailwind CSS のプリセットを追加します。

```css title="Tailwind CSS"
/* [!code ++] */
@import '@fumadocs/story/css/preset.css';
```

Vite プラグインを追加します。

```ts title="vite.config.ts"
import { defineConfig } from 'vite';
import story from '@fumadocs/story/vite';

export default defineConfig({
  plugins: [story()],
});
```

### ストーリーを作成する [#create-a-story]

グローバル設定を保持するストーリーファクトリーを作成します。

```ts title="lib/story.ts"
import { defineStoryFactory } from '@fumadocs/story/vite/client';

export const { defineStory } = defineStoryFactory();
```

次に、最初のストーリーを作成します。

```tsx tab="my-component.story.tsx"
import { defineStory } from '@/lib/story';
import { MyComponent } from './my-component';

export const story = defineStory({
  Component: MyComponent,
  args: {
    // デフォルトの props(推奨)
    initial: {},
  },
});
```

```tsx tab="my-component.tsx"
export interface MyComponentProps {
  title?: string;
}

export function MyComponent({ title }: MyComponentProps) {
  return <p>{title}</p>;
}
```

<Callout type="warn">
プラグインが変換するのは `*.story.{js,jsx,ts,tsx}` に一致するファイルのみです。この条件はVite プラグインの `filter` オプションで変更できます。
</Callout>

### ストーリーをレンダリングする [#render-a-story]

MDX ファイル内でストーリーをレンダリングします。

```mdx title="index.mdx"
import { story } from '@/components/my-component.story';

<story.WithControl />
```

## 設定 [#configurations]

### バリアント [#variants]

`args` を使うと、コンポーネントのバリアントを複数指定できます。

```ts
import { defineStory } from '@/lib/story';
import { Callout } from '@/components/callout';

export const story = defineStory({
  Component: Callout,
  args: [
    {
      variant: 'Default',
      initial: {
        title: 'This is a Callout',
      },
    },
    {
      variant: 'Warning',
      initial: {
        title: 'This is a Callout',
      },
      // props の固定値
      fixed: {
        type: 'warning',
      },
    },
  ],
});
```

### `controls` [#controls]

コントロールはコンポーネントのpropsから自動生成されます。これらを置き換えるには、コントロールノードを指定します。

```tsx
import { defineStory } from '@/lib/story';
import { GraphView } from '@/components/graph-view';

export const story = defineStory({
  Component: GraphView,
  args: {
    controls: {
      node: {
        type: 'object',
        properties: [],
      },
    },
  },
});
```

### `frame` [#frame]

レイアウトのようにビューポート全体を占めるコンポーネントは、iframe 内でレンダリングできます。
ストーリーパネルではフレームがパネルに収まるよう縮小して表示され、フルスクリーンで開くためのボタンも用意されています。

```tsx title="components/my-layout.story.tsx"
import { defineStory } from '@/lib/story';
import { MyLayout } from './my-layout.lazy';
import { Window } from './window';

export const story = defineStory({
  Component: MyLayout,
  frame: {
    src: '/story/my-layout',
    // ビューポートサイズ（省略可）
    width: 1280,
    height: 800,
    // フレームをウィンドウなどでラップする（省略可）
    Container: Window,
  },
});
```

コンポーネントをレンダリングするページを `src` に作成します。このページはストーリーパネルから引数を受け取ります。

```tsx title="src/routes/story/my-layout.tsx"
import { createFileRoute } from '@tanstack/react-router';
import { story } from '@/components/my-layout.story';

export const Route = createFileRoute('/story/my-layout')({
  component: () => <story.Frame />,
});
```

ストーリーは、それをレンダリングするすべてのページでコンポーネントを読み込みます。遅延読み込みのコンポーネントを渡せば、フレームでのみ読み込まれるようになります。

```tsx title="components/my-layout.lazy.tsx"
import { lazy } from 'react';

export const MyLayout = lazy(() =>
  import('./my-layout').then((mod) => ({ default: mod.MyLayout })),
);
```

<Callout title="補足">
* ページはドキュメントと同じオリジン上に配置する必要があります。
* 引数は `postMessage()` で送信されるため、シリアライズ可能な値である必要があります (関数や JSX は使用できません) 。
</Callout>

### 国際化 [#internationalization]

UI レベルで[国際化](/docs/tanstack-start/internationalization)を設定済みの場合:

```tsx title="layout.shared.tsx"
import { defineI18n } from 'fumadocs-core/i18n';
import { uiTranslations } from 'fumadocs-ui/i18n';
import { storyTranslations } from '@fumadocs/story/i18n';

const i18n = defineI18n({
  languages: ['en', 'cn'],
  defaultLanguage: 'en',
});

export const translations = i18n
  .translations()
  .extend(uiTranslations())
  // [!code ++]
  .extend(storyTranslations())
  .add({
    cn: {
      displayName: 'Chinese',
      // [!code ++]
      'Add Item(story arguments form)': '新增項目',
    },
  });
```

詳しくは[翻訳](/docs/ui/translations)を参照してください。