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"
}
}
工作流程
- 分析组件 - 扫描React/Vue/Angular组件
- 生成故事 - 为组件创建故事文件
- 提取属性 - 使用react-docgen进行属性文档
- 创建MDX - 生成MDX文档页面
- 配置autodocs - 设置自动文档
- 构建静态 - 导出静态文档站点
依赖
{
"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对相关参数进行分组
- 添加可访问性测试
- 包括设计指南
- 导出静态文档
参考
- Storybook Docs: https://storybook.js.org/docs
- Storybook Addons: https://storybook.js.org/integrations
- MDX Documentation: https://storybook.js.org/docs/writing-docs/mdx
- Autodocs: https://storybook.js.org/docs/writing-docs/autodocs
- Chromatic: https://www.chromatic.com/
目标流程
- sdk-doc-generation.js
- interactive-tutorials.js
- how-to-guides.js
- docs-as-code-pipeline.js