storybook-stories

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Storybook Stories

Storybook 故事

This skill enforces consistent Storybook story creation patterns across the application. It ensures that all components have proper documentation, interactive examples, and follow the established project structure.
<critical_component_usage> MANDATORY: Always Use Base UI Components from @agh/ui
CRITICAL REQUIREMENTS:
  • ALWAYS import components from
    @agh/ui
    package (
    packages/ui
    )
  • ALWAYS use existing base UI components instead of creating new ones from scratch
  • ALWAYS follow design system rules from
    @.cursor/rules/react.mdc
    and
    @.cursor/rules/shadcn.mdc
  • ALWAYS use design tokens (e.g.,
    bg-background
    ,
    text-foreground
    ,
    border-border
    ) instead of explicit colors
  • NEVER create components from scratch when a base component exists in
    @agh/ui
  • NEVER use explicit color values (e.g.,
    bg-white
    ,
    text-black
    ) - always use design tokens
  • NEVER duplicate component logic - compose from base components
  • NEVER set
    tags: ["autodocs"]
    or enable Storybook autodocs on any story meta (
    packages/ui
    ,
    web/src/components/ui
    , or
    web/src/systems/**
    ). Use
    parameters.docs.description.component
    , JSDoc on stories, and the Docs addon manually if needed.
Available Base Components: All components from
packages/ui/src/components
are available via
@agh/ui
:
  • Button, Card, Dialog, Input, Select, Badge, Avatar, Accordion, Alert, etc.
  • See
    packages/ui/src/index.ts
    for complete list of exports
Design System Rules:
  • Follow React best practices:
    @.cursor/rules/react.mdc
  • Follow Shadcn UI patterns:
    @.cursor/rules/shadcn.mdc
  • Use design tokens for theming:
    bg-background
    ,
    text-foreground
    ,
    border-border
    , etc. </critical_component_usage>
本技能确保应用程序中Storybook故事的创建模式保持一致,保证所有组件具备完善的文档、交互式示例,并遵循既定的项目结构。
<critical_component_usage> 强制要求:始终使用来自@agh/ui的基础UI组件
关键要求:
  • 始终
    @agh/ui
    包(
    packages/ui
    )导入组件
  • 始终使用现有基础UI组件,而非从头创建新组件
  • 始终遵循
    @.cursor/rules/react.mdc
    @.cursor/rules/shadcn.mdc
    中的设计系统规则
  • 始终使用设计令牌(如
    bg-background
    text-foreground
    border-border
    )而非明确的颜色值
  • 禁止
    @agh/ui
    已有基础组件的情况下从头创建新组件
  • 禁止使用明确的颜色值(如
    bg-white
    text-black
    )——务必使用设计令牌
  • 禁止重复组件逻辑——通过基础组件组合实现
  • 禁止在任何故事元数据(
    packages/ui
    web/src/components/ui
    web/src/systems/**
    )中设置
    tags: ["autodocs"]
    或启用Storybook自动文档功能。如需使用,可手动使用
    parameters.docs.description.component
    、故事上的JSDoc以及Docs插件。
可用基础组件:
packages/ui/src/components
中的所有组件均可通过
@agh/ui
访问:
  • Button、Card、Dialog、Input、Select、Badge、Avatar、Accordion、Alert等
  • 完整导出列表请查看
    packages/ui/src/index.ts
设计系统规则:
  • 遵循React最佳实践:
    @.cursor/rules/react.mdc
  • 遵循Shadcn UI模式:
    @.cursor/rules/shadcn.mdc
  • 使用设计令牌实现主题化:
    bg-background
    text-foreground
    border-border
    等 </critical_component_usage>

Instructions

操作说明

  1. File Location & Naming
    • Place story files in a
      stories/
      folder within the same category folder as the component.
    • Example:
      src/components/base/accordion.tsx
      ->
      src/components/base/stories/accordion.stories.tsx
      .
    • Use the Storybook instance that matches the layer:
      • packages/ui/.storybook
        for
        packages/ui/src/components/*.stories.tsx
      • web/.storybook
        for
        web/src/components/ui/**/*.stories.tsx
        and
        web/src/systems/**/components/stories/*.stories.tsx
  2. Component Imports
    • MANDATORY: Import base UI components from
      @agh/ui
    • Use:
      import { Button, Card, Dialog } from "@agh/ui";
    • Only import custom/domain-specific components from local files
    • Check
      packages/ui/src/index.ts
      to see available components before creating new ones
  3. Meta Configuration
    • Title should follow the directory structure:
      components/custom/ComponentName
      or
      components/ui/ComponentName
      .
    • Include
      component
      in the meta object.
    • Set
      parameters.layout
      to
      "centered"
      by default.
    • Add
      parameters.docs.description.component
      to describe the component.
    • Use
      decorators
      if the component requires a specific container width or context.
    • MANDATORY: Use explicit type annotation:
      const meta: Meta<typeof Component> = { ... }
    • MANDATORY: Do not add
      tags: ["autodocs"]
      to meta (any layer). Autodocs inflates generated docs noise and is forbidden in this repo.
    • web
      system stories may rely on the shared QueryClient + router + MSW decorators from
      web/.storybook/preview.ts
      ; prefer those global decorators over per-story provider duplication.
  4. Story Definition
    • Define a helper type:
      type Story = StoryObj<typeof meta>;
      .
    • Export stories as named constants (PascalCase).
    • Always add JSDoc comments above each story export; these appear in the Storybook UI.
    • Use the
      Default
      story as the primary example.
    • MANDATORY: All stories must include
      args
      property, even if empty:
      args: {}
    • Keep it concise: Create only essential stories (2-5 max per component). Avoid over-engineering with excessive variations or complex scenarios.
    • For system stories, keep titles aligned to the domain surface:
      systems/<name>/<ComponentName>
      .
  5. Render vs Args
    • Use
      render
      functions for compound components (like Accordion, Dialog, Select) that require children composition.
    • Use
      args
      for simple components (like Button, Badge) where props define the variation.
    • MANDATORY: Even when using
      render
      , include
      args: {}
      property
  6. Design System Compliance
    • ALWAYS use design tokens for colors:
      bg-background
      ,
      text-foreground
      ,
      border-border
    • NEVER use explicit colors:
      bg-white
      ,
      text-black
      ,
      border-gray-200
    • Follow accessibility guidelines from
      @.cursor/rules/shadcn.mdc
    • Use semantic HTML elements and proper ARIA attributes
  1. 文件位置与命名
    • 将故事文件放置在组件所在分类文件夹内的
      stories/
      目录中。
    • 示例:
      src/components/base/accordion.tsx
      ->
      src/components/base/stories/accordion.stories.tsx
    • 使用与层级匹配的Storybook实例:
      • packages/ui/.storybook
        用于
        packages/ui/src/components/*.stories.tsx
      • web/.storybook
        用于
        web/src/components/ui/**/*.stories.tsx
        web/src/systems/**/components/stories/*.stories.tsx
  2. 组件导入
    • 强制要求:从
      @agh/ui
      导入基础UI组件
    • 正确用法:
      import { Button, Card, Dialog } from "@agh/ui";
    • 仅从本地文件导入自定义/领域特定组件
    • 创建新组件前,请先查看
      packages/ui/src/index.ts
      确认可用组件
  3. 元数据配置
    • 标题应遵循目录结构:
      components/custom/ComponentName
      components/ui/ComponentName
    • 在元对象中包含
      component
      属性。
    • 默认将
      parameters.layout
      设置为
      "centered"
    • 添加
      parameters.docs.description.component
      来描述组件。
    • 如果组件需要特定容器宽度或上下文,使用
      decorators
    • 强制要求:使用显式类型注解:
      const meta: Meta<typeof Component> = { ... }
    • 强制要求:不要在元数据中添加
      tags: ["autodocs"]
      (任何层级)。自动文档会增加生成文档的冗余信息,本仓库禁止使用。
    • web
      系统故事可依赖
      web/.storybook/preview.ts
      中的共享QueryClient + 路由 + MSW装饰器;优先使用这些全局装饰器,而非每个故事重复添加提供者。
  4. 故事定义
    • 定义辅助类型:
      type Story = StoryObj<typeof meta>;
    • 使用大驼峰命名的常量导出故事。
    • 每个故事导出上方务必添加JSDoc注释;这些注释会显示在Storybook界面中。
    • 使用
      Default
      故事作为主要示例。
    • 强制要求:所有故事必须包含
      args
      属性,即使为空:
      args: {}
    • 保持简洁:每个组件仅创建必要的故事(最多2-5个)。避免过度设计,添加过多变体或复杂场景。
    • 系统故事的标题需与领域范围对齐:
      systems/<name>/<ComponentName>
  5. Render与Args的使用
    • 对于需要子组件组合的复合组件(如Accordion、Dialog、Select),使用
      render
      函数。
    • 对于通过props定义变体的简单组件(如Button、Badge),使用
      args
    • 强制要求:即使使用
      render
      ,也需包含
      args: {}
      属性
  6. 设计系统合规性
    • 始终使用设计令牌设置颜色:
      bg-background
      text-foreground
      border-border
    • 禁止使用明确颜色值:
      bg-white
      text-black
      border-gray-200
    • 遵循
      @.cursor/rules/shadcn.mdc
      中的无障碍指南
    • 使用语义化HTML元素和正确的ARIA属性

Example Template

示例模板

Using Base UI Components from @agh/ui

使用来自@agh/ui的基础UI组件

tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button, Card, CardHeader, CardTitle, CardContent } from "@agh/ui";
import { MyCustomComponent } from "./my-custom-component";

const meta: Meta<typeof MyCustomComponent> = {
  title: "components/custom/MyCustomComponent",
  component: MyCustomComponent,
  parameters: {
    layout: "centered",
    docs: {
      description: {
        component: "A custom component that composes base UI components from @agh/ui.",
      },
    },
  },
  // Optional decorator using design tokens
  decorators: [
    Story => (
      <div className="w-[400px] p-4 bg-background border border-border rounded-lg">
        <Story />
      </div>
    ),
  ],
};

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

/**
 * Default usage showing the standard behavior
 * Uses base Button and Card components from @agh/ui
 */
export const Default: Story = {
  args: {},
  render: () => (
    <Card>
      <CardHeader>
        <CardTitle>My Custom Component</CardTitle>
      </CardHeader>
      <CardContent>
        <MyCustomComponent>
          <Button variant="default">Action</Button>
        </MyCustomComponent>
      </CardContent>
    </Card>
  ),
};

/**
 * Variation with specific props
 * All styling uses design tokens (bg-background, text-foreground, etc.)
 */
export const WithVariant: Story = {
  args: {},
  render: () => (
    <div className="bg-card border border-border rounded-lg p-4">
      <MyCustomComponent variant="secondary">
        <Button variant="outline">Secondary Action</Button>
      </MyCustomComponent>
    </div>
  ),
};
tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button, Card, CardHeader, CardTitle, CardContent } from "@agh/ui";
import { MyCustomComponent } from "./my-custom-component";

const meta: Meta<typeof MyCustomComponent> = {
  title: "components/custom/MyCustomComponent",
  component: MyCustomComponent,
  parameters: {
    layout: "centered",
    docs: {
      description: {
        component: "A custom component that composes base UI components from @agh/ui.",
      },
    },
  },
  // Optional decorator using design tokens
  decorators: [
    Story => (
      <div className="w-[400px] p-4 bg-background border border-border rounded-lg">
        <Story />
      </div>
    ),
  ],
};

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

/**
 * Default usage showing the standard behavior
 * Uses base Button and Card components from @agh/ui
 */
export const Default: Story = {
  args: {},
  render: () => (
    <Card>
      <CardHeader>
        <CardTitle>My Custom Component</CardTitle>
      </CardHeader>
      <CardContent>
        <MyCustomComponent>
          <Button variant="default">Action</Button>
        </MyCustomComponent>
      </CardContent>
    </Card>
  ),
};

/**
 * Variation with specific props
 * All styling uses design tokens (bg-background, text-foreground, etc.)
 */
export const WithVariant: Story = {
  args: {},
  render: () => (
    <div className="bg-card border border-border rounded-lg p-4">
      <MyCustomComponent variant="secondary">
        <Button variant="outline">Secondary Action</Button>
      </MyCustomComponent>
    </div>
  ),
};

Story for Base UI Component (from @agh/ui)

基础UI组件的故事(来自@agh/ui)

tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "@agh/ui";

const meta: Meta<typeof Button> = {
  title: "components/ui/Button",
  component: Button,
  parameters: {
    layout: "centered",
    docs: {
      description: {
        component: "A button component with multiple variants and sizes.",
      },
    },
  },
};

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

/**
 * Default button with standard styling
 */
export const Default: Story = {
  args: {
    children: "Button",
    variant: "default",
    size: "default",
  },
};

/**
 * All variants using design tokens
 */
export const AllVariants: Story = {
  args: {},
  render: () => (
    <div className="flex flex-wrap gap-4 bg-background p-4 rounded-lg">
      <Button variant="default">Default</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="muted">Muted</Button>
    </div>
  ),
};
tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "@agh/ui";

const meta: Meta<typeof Button> = {
  title: "components/ui/Button",
  component: Button,
  parameters: {
    layout: "centered",
    docs: {
      description: {
        component: "A button component with multiple variants and sizes.",
      },
    },
  },
};

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

/**
 * Default button with standard styling
 */
export const Default: Story = {
  args: {
    children: "Button",
    variant: "default",
    size: "default",
  },
};

/**
 * All variants using design tokens
 */
export const AllVariants: Story = {
  args: {},
  render: () => (
    <div className="flex flex-wrap gap-4 bg-background p-4 rounded-lg">
      <Button variant="default">Default</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="muted">Muted</Button>
    </div>
  ),
};

Best Practices

最佳实践

Autodocs (forbidden)

自动文档(禁止使用)

Do not use Storybook autodocs. Never set
tags: ["autodocs"]
on
meta
for
packages/ui
,
web/src/components/ui
, or
web/src/systems/**
stories. Rationale: autodocs-generated pages add noise and duplicate what we already express with concise stories,
parameters.docs.description.component
, and per-story JSDoc. If a component needs richer prose, write it in the description fields and keep the canvas as the source of truth.
请勿使用Storybook自动文档功能。切勿在
packages/ui
web/src/components/ui
web/src/systems/**
的故事元数据中设置
tags: ["autodocs"]
。原因:自动文档生成的页面会增加冗余信息,与我们通过简洁故事、
parameters.docs.description.component
和每个故事的JSDoc所表达的内容重复。如果组件需要更丰富的描述,可在描述字段中编写,并将画布作为信息来源的基准。

Conciseness & Simplicity

简洁性与简易性

<critical> **MANDATORY: Keep Stories Concise and Focused**
  • DO: Create only essential stories that demonstrate core functionality
  • DO: Use minimal, realistic examples that show the component's purpose
  • DO: Focus on one concept per story
  • DON'T: Create excessive variations that don't add value
  • DON'T: Over-engineer with complex mock data or elaborate scenarios
  • DON'T: Create stories for every possible prop combination
  • DON'T: Add unnecessary decorators or wrappers unless required
Story Count Guidelines:
  • Simple components (Button, Badge): 2-3 stories max (Default + 1-2 key variations)
  • Medium components (Card, Dialog): 3-4 stories max (Default + key use cases)
  • Complex components: 4-5 stories max (Default + essential scenarios)
  • Never create more than 5 stories per component unless absolutely necessary </critical>
<critical> **强制要求:保持故事简洁且聚焦**
  • 务必仅创建展示核心功能的必要故事
  • 务必使用最小化、贴近真实的示例来展示组件用途
  • 务必每个故事聚焦一个概念
  • 禁止创建无价值的过多变体
  • 禁止过度设计,添加复杂的模拟数据或繁琐场景
  • 禁止为每个可能的props组合创建故事
  • 禁止添加不必要的装饰器或包装器,除非必须
故事数量指南:
  • 简单组件(Button、Badge):最多2-3个故事(默认示例 + 1-2个关键变体)
  • 中等组件(Card、Dialog):最多3-4个故事(默认示例 + 关键用例)
  • 复杂组件:最多4-5个故事(默认示例 + 核心场景)
  • 除非绝对必要,每个组件的故事数量不得超过5个 </critical>

Component Usage

组件使用

  • Base Components First: Always check
    @agh/ui
    for existing components before creating new ones
  • Composition Over Creation: Compose complex components from base UI components
  • Compound Components: Always demonstrate the full structure (Parent + Children) when using compound components from
    @agh/ui
  • Design Tokens: Always use design tokens (
    bg-background
    ,
    text-foreground
    , etc.) instead of explicit colors
  • 优先使用基础组件:创建新组件前,务必先检查
    @agh/ui
    是否已有对应组件
  • 组合优先于创建:通过基础UI组件组合实现复杂组件
  • 复合组件:使用
    @agh/ui
    中的复合组件时,务必展示完整结构(父组件 + 子组件)
  • 设计令牌:始终使用设计令牌(
    bg-background
    text-foreground
    等)而非明确颜色值

Story Structure

故事结构

  • Mock Data: Keep mock data minimal and realistic - only include what's necessary to demonstrate the component
  • Interactivity: For components like Accordion or Dialog, ensure the
    render
    function sets up the component in a way that allows interaction (e.g., not force-controlled unless necessary)
  • Cleanliness: Remove unused imports and generic "template" comments
  • Type Safety: Always use explicit type annotation for
    meta
    :
    const meta: Meta<typeof Component>
  • Args Property: Always include
    args: {}
    in all stories, even when using custom
    render
    functions
  • One Story Per Concept: Each story should demonstrate one clear use case or variation, not multiple concepts
  • 模拟数据:保持模拟数据最小化且贴近真实——仅包含展示组件所需的内容
  • 交互性:对于Accordion或Dialog等组件,确保
    render
    函数设置的组件允许交互(例如,除非必要,不要强制受控)
  • 整洁性:移除未使用的导入和通用的“模板”注释
  • 类型安全:始终为
    meta
    使用显式类型注解:
    const meta: Meta<typeof Component>
  • Args属性:所有故事务必包含
    args: {}
    ,即使使用自定义
    render
    函数
  • 每个故事一个概念:每个故事应展示一个清晰的用例或变体,而非多个概念

Design System Compliance

设计系统合规性

  • Follow React Rules: Adhere to patterns in
    @.cursor/rules/react.mdc
  • Follow Shadcn Rules: Adhere to patterns in
    @.cursor/rules/shadcn.mdc
  • Accessibility: Use semantic HTML and proper ARIA attributes
  • Theme Support: All stories should work in both light and dark themes using design tokens
  • 遵循React规则:遵守
    @.cursor/rules/react.mdc
    中的模式
  • 遵循Shadcn规则:遵守
    @.cursor/rules/shadcn.mdc
    中的模式
  • 无障碍性:使用语义化HTML和正确的ARIA属性
  • 主题支持:所有故事应通过设计令牌适配亮色和暗色主题

Common Mistakes to Avoid

需避免的常见错误

Creating components from scratch when base components exist:
tsx
// ❌ BAD: Creating a button from scratch
export const Bad: Story = {
  render: () => <button className="bg-blue-500 text-white px-4 py-2 rounded">Click me</button>,
};

// ✅ GOOD: Using base Button from @agh/ui
import { Button } from "@agh/ui";
export const Good: Story = {
  args: {},
  render: () => <Button variant="default">Click me</Button>,
};
Enabling autodocs on meta:
tsx
// ❌ BAD: autodocs tag (forbidden in this repo)
const meta: Meta<typeof Button> = {
  title: "ui/Button",
  component: Button,
  tags: ["autodocs"],
};

// ✅ GOOD: no autodocs tag; describe the component in parameters.docs
const meta: Meta<typeof Button> = {
  title: "ui/Button",
  component: Button,
  parameters: {
    layout: "centered",
    docs: {
      description: {
        component: "Primary action button with variants and sizes.",
      },
    },
  },
};
Using explicit colors instead of design tokens:
tsx
// ❌ BAD: Using explicit colors
<div className="bg-white text-black border-gray-200">

// ✅ GOOD: Using design tokens
<div className="bg-background text-foreground border-border">
Missing args property:
tsx
// ❌ BAD: Missing args property
export const Bad: Story = {
  render: () => <Button>Click</Button>,
};

// ✅ GOOD: Including args property
export const Good: Story = {
  args: {},
  render: () => <Button>Click</Button>,
};
Missing explicit type annotation:
tsx
// ❌ BAD: Type inference
const meta = {
  title: "Components/Button",
  component: Button,
} satisfies Meta<typeof Button>;

// ✅ GOOD: Explicit type annotation
const meta: Meta<typeof Button> = {
  title: "Components/Button",
  component: Button,
};
Over-engineering stories with unnecessary examples:
tsx
// ❌ BAD: Too many stories with similar variations
export const Default: Story = { ... };
export const WithIcon: Story = { ... };
export const WithIconLeft: Story = { ... };
export const WithIconRight: Story = { ... };
export const WithLongText: Story = { ... };
export const WithShortText: Story = { ... };
export const Disabled: Story = { ... };
export const Loading: Story = { ... };
export const WithTooltip: Story = { ... };
export const InCard: Story = { ... };
export const InDialog: Story = { ... };
// ... 10+ stories for a simple button

// ✅ GOOD: Concise, focused stories
export const Default: Story = {
  args: {
    children: "Button",
    variant: "default",
  },
};

export const Variants: Story = {
  args: {},
  render: () => (
    <div className="flex gap-2">
      <Button variant="default">Default</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="outline">Outline</Button>
    </div>
  ),
};

export const Disabled: Story = {
  args: {
    children: "Disabled",
    disabled: true,
  },
};
// Only 3 stories covering essential use cases
Over-complicated mock data or scenarios:
tsx
// ❌ BAD: Unnecessarily complex mock data
const mockUsers = [
  { id: "1", name: "John Doe", email: "john@example.com", role: "admin", avatar: "...", lastLogin: "...", permissions: [...], metadata: {...} },
  { id: "2", name: "Jane Smith", email: "jane@example.com", role: "user", avatar: "...", lastLogin: "...", permissions: [...], metadata: {...} },
  // ... 10 more users with full data
];

// ✅ GOOD: Minimal, realistic data
const mockUsers = [
  { id: "1", name: "John Doe", email: "john@example.com" },
  { id: "2", name: "Jane Smith", email: "jane@example.com" },
];
已有基础组件时仍从头创建组件:
tsx
// ❌ 错误:从头创建按钮
export const Bad: Story = {
  render: () => <button className="bg-blue-500 text-white px-4 py-2 rounded">Click me</button>,
};

// ✅ 正确:使用来自@agh/ui的基础Button组件
import { Button } from "@agh/ui";
export const Good: Story = {
  args: {},
  render: () => <Button variant="default">Click me</Button>,
};
在元数据中启用自动文档:
tsx
// ❌ 错误:使用autodocs标签(本仓库禁止)
const meta: Meta<typeof Button> = {
  title: "ui/Button",
  component: Button,
  tags: ["autodocs"],
};

// ✅ 正确:不使用autodocs标签;在parameters.docs中描述组件
const meta: Meta<typeof Button> = {
  title: "ui/Button",
  component: Button,
  parameters: {
    layout: "centered",
    docs: {
      description: {
        component: "Primary action button with variants and sizes.",
      },
    },
  },
};
使用明确颜色值而非设计令牌:
tsx
// ❌ 错误:使用明确颜色值
<div className="bg-white text-black border-gray-200">

// ✅ 正确:使用设计令牌
<div className="bg-background text-foreground border-border">
缺少args属性:
tsx
// ❌ 错误:缺少args属性
export const Bad: Story = {
  render: () => <Button>Click</Button>,
};

// ✅ 正确:包含args属性
export const Good: Story = {
  args: {},
  render: () => <Button>Click</Button>,
};
缺少显式类型注解:
tsx
// ❌ 错误:类型推断
const meta = {
  title: "Components/Button",
  component: Button,
} satisfies Meta<typeof Button>;

// ✅ 正确:显式类型注解
const meta: Meta<typeof Button> = {
  title: "Components/Button",
  component: Button,
};
过度设计故事,添加不必要的示例:
tsx
// ❌ 错误:过多相似变体的故事
export const Default: Story = { ... };
export const WithIcon: Story = { ... };
export const WithIconLeft: Story = { ... };
export const WithIconRight: Story = { ... };
export const WithLongText: Story = { ... };
export const WithShortText: Story = { ... };
export const Disabled: Story = { ... };
export const Loading: Story = { ... };
export const WithTooltip: Story = { ... };
export const InCard: Story = { ... };
export const InDialog: Story = { ... };
// ... 一个简单按钮有10多个故事

// ✅ 正确:简洁、聚焦的故事
export const Default: Story = {
  args: {
    children: "Button",
    variant: "default",
  },
};

export const Variants: Story = {
  args: {},
  render: () => (
    <div className="flex gap-2">
      <Button variant="default">Default</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="outline">Outline</Button>
    </div>
  ),
};

export const Disabled: Story = {
  args: {
    children: "Disabled",
    disabled: true,
  },
};
// 仅3个故事,覆盖核心用例
过度复杂的模拟数据或场景:
tsx
// ❌ 错误:不必要的复杂模拟数据
const mockUsers = [
  { id: "1", name: "John Doe", email: "john@example.com", role: "admin", avatar: "...", lastLogin: "...", permissions: [...], metadata: {...} },
  { id: "2", name: "Jane Smith", email: "jane@example.com", role: "user", avatar: "...", lastLogin: "...", permissions: [...], metadata: {...} },
  // ... 另外10个包含完整数据的用户
];

// ✅ 正确:最小化、贴近真实的数据
const mockUsers = [
  { id: "1", name: "John Doe", email: "john@example.com" },
  { id: "2", name: "Jane Smith", email: "jane@example.com" },
];
",