AgentSkillsCN

storybook

React组件文档和测试的Storybook 8。当创建故事、用Controls/Actions文档化组件、视觉测试和MDX文档时使用。触发于对Storybook故事、组件文档、视觉测试或交互式组件演示的请求。

SKILL.md
--- frontmatter
name: storybook
description: Storybook 8 for React component documentation and testing. Use for creating stories, documenting components with Controls/Actions, visual testing, and MDX documentation. Triggers on requests for Storybook stories, component documentation, visual testing, or interactive component demos.

Storybook Development

Story Structure (CSF 3.0)

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

const meta: Meta<typeof Button> = {
  title: 'Atoms/Button',
  component: Button,
  parameters: {
    layout: 'centered',
  },
  tags: ['autodocs'],
  argTypes: {
    variant: {
      control: 'select',
      options: ['primary', 'secondary', 'ghost'],
      description: 'Visual style variant',
    },
    size: {
      control: 'radio',
      options: ['sm', 'md', 'lg'],
    },
    disabled: { control: 'boolean' },
    onClick: { action: 'clicked' },
  },
  args: {
    children: 'Button',
    variant: 'primary',
    size: 'md',
  },
};

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

export const Primary: Story = {
  args: {
    variant: 'primary',
  },
};

export const Secondary: Story = {
  args: {
    variant: 'secondary',
  },
};

export const AllVariants: Story = {
  render: (args) => (
    <div style={{ display: 'flex', gap: '1rem' }}>
      <Button {...args} variant="primary">Primary</Button>
      <Button {...args} variant="secondary">Secondary</Button>
      <Button {...args} variant="ghost">Ghost</Button>
    </div>
  ),
};

File Naming

code
ComponentName/
├── ComponentName.tsx
├── ComponentName.stories.tsx   # Stories file
├── ComponentName.mdx           # Optional: Extended docs

Controls Configuration

Control TypeUse For
selectEnum with many options
radioEnum with 2-4 options
booleanTrue/false toggles
textString inputs
numberNumeric values
colorColor pickers
objectComplex objects
dateDate values

Common Patterns

Interactive Story with State

tsx
export const WithState: Story = {
  render: function Render(args) {
    const [count, setCount] = useState(0);
    return (
      <Button {...args} onClick={() => setCount(c => c + 1)}>
        Clicked {count} times
      </Button>
    );
  },
};

Story with Decorators

tsx
const meta: Meta<typeof Card> = {
  component: Card,
  decorators: [
    (Story) => (
      <div style={{ padding: '2rem', background: '#f5f5f5' }}>
        <Story />
      </div>
    ),
  ],
};

Responsive Preview

tsx
export const Responsive: Story = {
  parameters: {
    viewport: {
      viewports: {
        mobile: { name: 'Mobile', styles: { width: '375px', height: '667px' } },
        tablet: { name: 'Tablet', styles: { width: '768px', height: '1024px' } },
      },
      defaultViewport: 'mobile',
    },
  },
};

Organization by Atomic Design

Stories are grouped by title in the Storybook sidebar following Atomic Design:

tsx
// Atoms
title: 'Atoms/Button'
title: 'Atoms/Input'
title: 'Atoms/Icon'

// Molecules  
title: 'Molecules/SearchField'
title: 'Molecules/FormField'

// Organisms
title: 'Organisms/Header'
title: 'Organisms/ProductCard'

// Templates
title: 'Templates/DashboardLayout'

// Pages
title: 'Pages/HomePage'

Story files are located directly with the components:

code
src/components/
├── atoms/
│   ├── Button/
│   │   ├── Button.tsx
│   │   ├── Button.module.css
│   │   ├── Button.stories.tsx    # title: 'Atoms/Button'
│   │   └── index.ts
│   └── Input/
│       └── Input.stories.tsx     # title: 'Atoms/Input'
├── molecules/
│   └── SearchField/
│       └── SearchField.stories.tsx  # title: 'Molecules/SearchField'
└── organisms/
    └── Header/
        └── Header.stories.tsx    # title: 'Organisms/Header'

Best Practices

  1. One story file per component
  2. Use tags: ['autodocs'] for auto-generated docs
  3. Provide meaningful default args
  4. Show all variants in an overview story
  5. Use actions for event callbacks
  6. Document edge cases (loading, error, empty states)