跳至內容
Fumadocs

元件情境

透過控制項展示元件。

Callout

string
string

簡介

Fumadocs Story 可用來展示元件並為其撰寫文件。 它是 Storybook 的輕量替代方案,以文件為核心,主要為元件庫而設計。

如果您初次接觸元件情境 (Story) 的概念,以下是 Storybook 文件中的簡短說明:

元件情境記錄了 UI 元件已渲染的狀態。它是一個帶有註解的物件, 用來描述元件在給定一組引數時的行為與外觀。

何時該選用它,而不是 Storybook?

Fumadocs Story 並非用來取代 Storybook。若要進行完整的 UI 測試,我們仍建議使用 Storybook。

安裝

npm i @fumadocs/story

加入 Tailwind CSS 預設集:

Tailwind CSS
@import '@fumadocs/story/css/preset.css';

新增 Vite 外掛:

vite.config.ts
import { defineConfig } from 'vite';
import story from '@fumadocs/story/vite';

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

建立元件情境

建立一個元件情境工廠,用來存放您的全域設定:

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

export const { defineStory } = defineStoryFactory();

接著建立您的第一個元件情境:

import { defineStory } from '@/lib/story';
import { MyComponent } from './my-component';

export const story = defineStory({
  Component: MyComponent,
  args: {
    // 預設 props(建議設定)
    initial: {},
  },
});

檔名必須加上 .story 後綴

此外掛只會轉換符合 *.story.{js,jsx,ts,tsx} 的檔案。您可以透過 Vite 外掛的 filter 選項變更此規則。

算繪元件情境

在 MDX 檔案中算繪元件情境:

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

<story.WithControl />

設定

變體

您可以透過 args 為元件提供多個變體:

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

控制項會根據元件的 props 自動產生。您可以指定控制項節點來取代它們:

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

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

frame

填滿整個 viewport 的元件 (例如版面配置) 可以在 iframe 中算繪。 元件情境面板會將 frame 縮小至合適的大小,並提供按鈕讓您以全螢幕開啟。

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,
    // 包裹 frame 的容器,例如視窗(選填)
    Container: Window,
  },
});

在 src 建立一個頁面來算繪元件。此頁面會接收來自元件情境面板的引數:

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 />,
});

只要頁面算繪了元件情境,就會載入其元件。建議改為傳入延遲載入的元件,讓元件只在 frame 中載入:

components/my-layout.lazy.tsx
import { lazy } from 'react';

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

小提醒

  • 此頁面必須與您的文件位於相同來源 (origin) 。
  • 引數是透過 postMessage() 傳送,因此必須可序列化 (不能包含函式或 JSX) 。

國際化

假設您已在 UI 層級設定好國際化:

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())
  .extend(storyTranslations())
  .add({
    cn: {
      displayName: 'Chinese',
      'Add Item(story arguments form)': '新增項目',
    },
  });

詳情請參閱翻譯。

How is this guide?

最後更新於