Storybook文档技能Skill storybook-docs

利用Storybook生成UI组件文档的技能,包括配置文档插件、从故事生成文档、编写MDX文档、集成设计系统文档等,关键词:Storybook, UI组件, 文档生成, MDX, 设计系统集成

前端开发 0 次安装 0 次浏览 更新于 2/26/2026

storybook-docs Storybook集成用于UI组件文档。配置docs插件,从故事生成组件文档,编写MDX文档,并与设计系统集成。 允许的工具:阅读、写作、编辑、Bash、Glob、Grep, backlog-id:SK-017 元数据: 作者:babysitter-sdk 版本:“1.0.0”

Storybook文档技能

使用Storybook和MDX,autodocs,设计系统集成生成全面的UI组件文档。

能力

  • 配置Storybook文档插件
  • 从故事生成组件文档
  • 编写MDX故事文档
  • 配置autodocs以自动生成文档
  • 集成设计系统文档
  • 配置可访问性插件集成
  • 导出静态文档站点
  • 与Chromatic集成进行视觉测试

使用

当您需要时调用此技能:

  • 文档React/Vue/Angular组件库
  • 创建交互式组件文档
  • 构建设计系统文档
  • 从组件props生成API参考
  • 设置组件游乐场文档

输入

参数 类型 必需 描述
projectPath 字符串 Storybook项目的根路径
framework 字符串 react, vue, angular, web-components
outputDir 字符串 静态文档输出目录
includeAccessibility 布尔值 包括a11y插件文档
theme 字符串 文档主题(light, dark, custom)
generateMdx 布尔值 生成MDX文档文件

输入示例

{
  "projectPath": "./packages/components",
  "framework": "react",
  "outputDir": "docs/components",
  "includeAccessibility": true,
  "generateMdx": true
}

输出结构

docs/components/
├── index.html                    # 文档主页
├── iframe.html                   # 故事iframe
├── assets/
│   ├── manager.js
│   └── preview.js
├── sb-addons/                    # 插件资产
├── sb-common-assets/
├── sb-manager/
├── sb-preview/
└── stories.json                  # 故事元数据

Storybook配置

.storybook/main.ts

import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: [
    '../src/**/*.mdx',
    '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
  ],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
    '@storybook/addon-a11y',
    '@storybook/addon-designs',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
  docs: {
    autodocs: 'tag', // 为带有autodocs标签的组件生成文档
    defaultName: 'Documentation',
  },
  typescript: {
    reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
      shouldExtractLiteralValuesFromEnum: true,
      shouldRemoveUndefinedFromOptional: true,
      propFilter: (prop) =>
        prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
    },
  },
};

export default config;

.storybook/preview.ts

import type { Preview } from '@storybook/react';
import { themes } from '@storybook/theming';

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
    docs: {
      theme: themes.light,
      toc: {
        contentsSelector: '.sbdocs-content',
        headingSelector: 'h1, h2, h3',
        title: 'Table of Contents',
        disable: false,
      },
    },
    backgrounds: {
      default: 'light',
      values: [
        { name: 'light', value: '#ffffff' },
        { name: 'dark', value: '#1a1a1a' },
        { name: 'gray', value: '#f5f5f5' },
      ],
    },
  },
  tags: ['autodocs'],
};

export default preview;

故事模式

组件故事格式(CSF3)

// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { Button } from './Button';

/**
 * 用户交互的按钮组件。
 *
 * ## 使用
 * ```tsx
 * import { Button } from '@mylib/components';
 *
 * <Button variant="primary" onClick={handleClick}>
 *   点击我
 * </Button>
 * ```
 *
 * ## 可访问性
 * - 使用原生按钮元素以获得适当的语义
 * - 支持键盘导航
 * - 包括加载/禁用状态的ARIA属性
 */
const meta = {
  title: 'Components/Button',
  component: Button,
  tags: ['autodocs'],
  parameters: {
    layout: 'centered',
    docs: {
      description: {
        component: '主要的用户交互UI组件',
      },
    },
  },
  argTypes: {
    variant: {
      control: 'select',
      options: ['primary', 'secondary', 'tertiary', 'danger'],
      description: '视觉风格变体',
      table: {
        type: { summary: 'ButtonVariant' },
        defaultValue: { summary: 'primary' },
      },
    },
    size: {
      control: 'radio',
      options: ['sm', 'md', 'lg'],
      description: '按钮大小',
    },
    disabled: {
      control: 'boolean',
      description: '禁用按钮',
    },
    loading: {
      control: 'boolean',
      description: '显示加载 spinner',
    },
    onClick: {
      action: 'clicked',
      description: '点击处理器',
    },
  },
  args: {
    onClick: fn(),
  },
} satisfies Meta<typeof Button>;

export default meta;
type Story = StoryObj<typeof meta>;

/**
 * 主要按钮用于主要操作。
 */
export const Primary: Story = {
  args: {
    variant: 'primary',
    children: '主按钮',
  },
};

/**
 * 次要按钮用于不太突出的操作。
 */
export const Secondary: Story = {
  args: {
    variant: 'secondary',
    children: '次按钮',
  },
};

/**
 * 危险按钮用于破坏性操作。
 * 要谨慎使用,并与确认对话框一起使用。
 */
export const Danger: Story = {
  args: {
    variant: 'danger',
    children: '删除',
  },
  parameters: {
    docs: {
      description: {
        story: '用于删除或移除等破坏性操作。',
      },
    },
  },
};

/**
 * 加载状态带spinner。
 */
export const Loading: Story = {
  args: {
    variant: 'primary',
    loading: true,
    children: '保存中...',
  },
};

/**
 * 禁用状态。
 */
export const Disabled: Story = {
  args: {
    variant: 'primary',
    disabled: true,
    children: '禁用',
  },
};

/**
 * 尺寸变体比较。
 */
export const Sizes: Story = {
  render: () => (
    <div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
      <Button size="sm">小</Button>
      <Button size="md">中</Button>
      <Button size="lg">大</Button>
    </div>
  ),
  parameters: {
    docs: {
      description: {
        story: '不同上下文中可用的尺寸变体。',
      },
    },
  },
};

MDX文档

{/* Button.mdx */}
import { Meta, Canvas, Controls, Stories, Story } from '@storybook/blocks';
import * as ButtonStories from './Button.stories';
import { Button } from './Button';

<Meta of={ButtonStories} />

# 按钮

<Canvas of={ButtonStories.Primary} />

按钮组件用于在表单、对话框和整个界面中触发操作。

## 导入

```tsx
import { Button } from '@mylib/components';

使用

<Button variant="primary" onClick={handleClick}>
  点击我
</Button>

属性

<Controls />

变体

主要

使用主要变体用于页面上的主要操作。

<Canvas of={ButtonStories.Primary} />

次要

使用次要变体用于不太突出的操作。

<Canvas of={ButtonStories.Secondary} />

危险

使用危险变体用于破坏性操作。始终与用户确认。

<Canvas of={ButtonStories.Danger} />

状态

加载

当操作进行中时显示加载spinner。

<Canvas of={ButtonStories.Loading} />

禁用

当操作不可用时禁用按钮。

<Canvas of={ButtonStories.Disabled} />

尺寸

<Canvas of={ButtonStories.Sizes} />

可访问性

  • 使用语义<button>元素
  • 支持键盘焦点和激活
  • 包括禁用时的aria-disabled
  • 加载状态对屏幕阅读器宣布

设计指南

  • 使用清晰、面向操作的标签
  • 对于异步操作显示加载状态
  • 当操作不可用时禁用

不做

  • 不要用于导航(使用链接)
  • 不要堆叠多个主按钮
  • 不要禁用而不解释

所有故事

<Stories />


## Autodocs配置

### 每个组件Autodocs

```typescript
// 带有JSDoc的组件用于autodocs
import { FC, ReactNode } from 'react';

export interface CardProps {
  /** 标题显示在标题中 */
  title: string;
  /** 可选副标题在标题下方 */
  subtitle?: string;
  /** 卡片内容 */
  children: ReactNode;
  /** 视觉变体 */
  variant?: 'elevated' | 'outlined' | 'filled';
  /** 卡片是否可交互/可点击 */
  interactive?: boolean;
  /** 交互式卡片的点击处理器 */
  onClick?: () => void;
}

/**
 * 用于分组相关内容的卡片组件。
 *
 * @example
 * ```tsx
 * <Card title="欢迎" variant="elevated">
 *   <p>卡片内容放在这里</p>
 * </Card>
 * ```
 */
export const Card: FC<CardProps> = ({
  title,
  subtitle,
  children,
  variant = 'elevated',
  interactive = false,
  onClick,
}) => {
  // 实现
};

Autodocs定制

// Card.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Card } from './Card';

const meta: Meta<typeof Card> = {
  title: 'Components/Card',
  component: Card,
  tags: ['autodocs'],
  parameters: {
    docs: {
      description: {
        component: `
卡片是显示单个主题的内容和操作的表面。

它们应该容易被扫描以获取相关和可操作的信息。
元素,如文本和图像,应该以一种清晰指示层次结构的方式放置在它们上面。
        `,
      },
    },
  },
  argTypes: {
    children: {
      control: 'text',
      description: '卡片内容',
      table: {
        category: 'Content',
      },
    },
    title: {
      table: {
        category: 'Content',
      },
    },
    variant: {
      table: {
        category: 'Appearance',
      },
    },
    interactive: {
      table: {
        category: 'Behavior',
      },
    },
  },
};

export default meta;

设计系统文档

设计令牌MDX

{/* DesignTokens.mdx */}
import { Meta, ColorPalette, ColorItem, Typeset } from '@storybook/blocks';

<Meta title="Foundations/Design Tokens" />

# 设计令牌

设计系统的视觉设计原子。

## 颜色

### 主要

<ColorPalette>
  <ColorItem
    title="主要"
    subtitle="品牌颜色"
    colors={{
      '主要 50': '#E3F2FD',
      '主要 100': '#BBDEFB',
      '主要 500': '#2196F3',
      '主要 700': '#1976D2',
      '主要 900': '#0D47A1',
    }}
  />
</ColorPalette>

### 语义

<ColorPalette>
  <ColorItem
    title="成功"
    colors={{ 成功: '#4CAF50' }}
  />
  <ColorItem
    title="警告"
    colors={{ 警告: '#FF9800' }}
  />
  <ColorItem
    title="错误"
    colors={{ 错误: '#F44336' }}
  />
</ColorPalette>

## 排版

<Typeset
  fontSizes=['12px', '14px', '16px', '20px', '24px', '32px']
  fontWeight={400}
  sampleText="快速棕色狐狸跳过懒惰的狗"
  fontFamily="Inter, system-ui, sans-serif"
/>

图标文档

{/* Icons.mdx */}
import { Meta, IconGallery, IconItem } from '@storybook/blocks';
import * as Icons from '../icons';

<Meta title="Foundations/Icons" />

# 图标

设计系统图标库。

<IconGallery>
  <IconItem name="Add"><Icons.Add /></IconItem>
  <IconItem name="Edit"><Icons.Edit /></IconItem>
  <IconItem name="Delete"><Icons.Delete /></IconItem>
  <IconItem name="Search"><Icons.Search /></IconItem>
  <IconItem name="Settings"><Icons.Settings /></IconItem>
</IconGallery>

可访问性插件集成

A11y配置

// .storybook/preview.ts
import type { Preview } from '@storybook/react';

const preview: Preview = {
  parameters: {
    a11y: {
      config: {
        rules: [
          { id: 'color-contrast', enabled: true },
          { id: 'label', enabled: true },
          { id: 'button-name', enabled: true },
        ],
      },
      options: {
        runOnly: {
          type: 'tag',
          values: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'],
        },
      },
    },
  },
};

export default preview;

每个故事A11y

export const AccessibleButton: Story = {
  args: {
    children: '提交表单',
    'aria-label': '提交联系表单',
  },
  parameters: {
    a11y: {
      config: {
        rules: [{ id: 'color-contrast', enabled: true }],
      },
    },
  },
};

静态导出

构建文档

# 构建静态文档站点
npx storybook build --docs -o docs/components

# 带有自定义输出
npx storybook build --docs -o public/design-system

package.json脚本

{
  "scripts": {
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build",
    "build-docs": "storybook build --docs -o docs/components",
    "test-storybook": "test-storybook"
  }
}

工作流程

  1. 分析组件 - 扫描React/Vue/Angular组件
  2. 生成故事 - 为组件创建故事文件
  3. 提取属性 - 使用react-docgen进行属性文档
  4. 创建MDX - 生成MDX文档页面
  5. 配置autodocs - 设置自动文档
  6. 构建静态 - 导出静态文档站点

依赖

{
  "devDependencies": {
    "@storybook/react": "^8.0.0",
    "@storybook/react-vite": "^8.0.0",
    "@storybook/addon-essentials": "^8.0.0",
    "@storybook/addon-a11y": "^8.0.0",
    "@storybook/addon-interactions": "^8.0.0",
    "@storybook/addon-links": "^8.0.0",
    "@storybook/addon-designs": "^8.0.0",
    "@storybook/blocks": "^8.0.0",
    "@storybook/test": "^8.0.0",
    "react-docgen-typescript": "^2.2.0"
  }
}

最佳实践应用

  • 使用CSF3进行故事格式
  • 使用JSDoc注释记录属性
  • 在MDX中包括使用示例
  • 使用table.category对相关参数进行分组
  • 添加可访问性测试
  • 包括设计指南
  • 导出静态文档

参考

目标流程

  • sdk-doc-generation.js
  • interactive-tutorials.js
  • how-to-guides.js
  • docs-as-code-pipeline.js