skillby sgcarstrends

component-docs

Generate or update component documentation with usage examples, props tables, and Storybook stories. Use when documenting new components or improving existing component docs.

Installs: 0
Used in: 1 repos
Updated: 1d ago
$npx ai-builder add skill sgcarstrends/component-docs

Installs to .claude/skills/component-docs/

# Component Documentation Skill

This skill helps you create and maintain component documentation in `packages/ui/`.

## When to Use This Skill

- Writing documentation for new components
- Creating usage examples and code snippets
- Documenting component props and variants
- Setting up Storybook stories
- Generating API documentation
- Maintaining component README files

## Documentation Structure

```
packages/ui/
├── src/
│   ├── components/
│   │   ├── button.tsx          # Component implementation
│   │   ├── button.stories.tsx  # Storybook stories (optional)
│   │   └── __tests__/
│   │       └── button.test.tsx # Component tests
├── docs/
│   ├── components/
│   │   ├── button.md           # Component documentation
│   │   └── card.md
│   └── guides/
│       ├── getting-started.md
│       └── customization.md
└── README.md                    # Package overview
```

## Component Documentation Template

### Basic Component Documentation

```markdown
# Button

A customizable button component built with Radix UI primitives.

## Installation

This component is part of the `@sgcarstrends/ui` package.

\`\`\`bash
pnpm add @sgcarstrends/ui
\`\`\`

## Usage

\`\`\`tsx
import { Button } from "@sgcarstrends/ui";

export function Example() {
  return <Button>Click me</Button>;
}
\`\`\`

## Variants

### Default

\`\`\`tsx
<Button variant="default">Default Button</Button>
\`\`\`

### Destructive

\`\`\`tsx
<Button variant="destructive">Delete</Button>
\`\`\`

### Outline

\`\`\`tsx
<Button variant="outline">Outline Button</Button>
\`\`\`

## Sizes

\`\`\`tsx
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="icon">
  <Icon />
</Button>
\`\`\`

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| variant | `"default" \| "destructive" \| "outline" \| "secondary" \| "ghost" \| "link"` | `"default"` | The visual style of the button |
| size | `"default" \| "sm" \| "lg" \| "icon"` | `"default"` | The size of the button |
| asChild | `boolean` | `false` | Render as child element |
| disabled | `boolean` | `false` | Whether button is disabled |

## Examples

### With Icon

\`\`\`tsx
import { Button } from "@sgcarstrends/ui";
import { DownloadIcon } from "lucide-react";

export function DownloadButton() {
  return (
    <Button>
      <DownloadIcon className="mr-2 h-4 w-4" />
      Download
    </Button>
  );
}
\`\`\`

### Loading State

\`\`\`tsx
"use client";

import { useState } from "react";
import { Button } from "@sgcarstrends/ui";

export function LoadingButton() {
  const [isLoading, setIsLoading] = useState(false);

  return (
    <Button disabled={isLoading} onClick={() => setIsLoading(true)}>
      {isLoading ? "Loading..." : "Submit"}
    </Button>
  );
}
\`\`\`

### As Link

\`\`\`tsx
import { Button } from "@sgcarstrends/ui";
import Link from "next/link";

export function LinkButton() {
  return (
    <Button asChild>
      <Link href="/about">Learn More</Link>
    </Button>
  );
}
\`\`\`

## Accessibility

- Uses semantic `<button>` element
- Supports keyboard navigation (Enter, Space)
- Proper focus states
- ARIA attributes supported via props

## Styling

The Button component uses Tailwind CSS and CSS variables for theming. Customize via:

\`\`\`tsx
<Button className="custom-classes">Custom Styled</Button>
\`\`\`

## Related Components

- [Link Button](#)
- [Icon Button](#)
- [Button Group](#)
```

## JSDoc Comments

Add comprehensive JSDoc comments to components:

```typescript
/**
 * A customizable button component with multiple variants and sizes.
 *
 * @component
 * @example
 * ```tsx
 * <Button variant="default" size="md">
 *   Click me
 * </Button>
 * ```
 */
export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  /**
   * Render the button as a child element (e.g., Link)
   * @default false
   */
  asChild?: boolean;

  /**
   * The visual style variant of the button
   * @default "default"
   */
  variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";

  /**
   * The size of the button
   * @default "default"
   */
  size?: "default" | "sm" | "lg" | "icon";
}

/**
 * Button component
 *
 * @param {ButtonProps} props - Button props
 * @returns {React.ReactElement} Button element
 *
 * @example
 * Basic usage
 * ```tsx
 * <Button>Click me</Button>
 * ```
 *
 * @example
 * With variant
 * ```tsx
 * <Button variant="destructive">Delete</Button>
 * ```
 *
 * @example
 * As a link
 * ```tsx
 * <Button asChild>
 *   <Link href="/about">About</Link>
 * </Button>
 * ```
 */
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button";
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    );
  }
);

Button.displayName = "Button";
```

## Storybook Stories

### Installing Storybook (if not present)

```bash
cd packages/ui

# Initialize Storybook
npx storybook@latest init
```

### Basic Story

```typescript
// packages/ui/src/components/button.stories.tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "./button";

const meta = {
  title: "Components/Button",
  component: Button,
  parameters: {
    layout: "centered",
  },
  tags: ["autodocs"],
  argTypes: {
    variant: {
      control: "select",
      options: ["default", "destructive", "outline", "secondary", "ghost", "link"],
    },
    size: {
      control: "select",
      options: ["default", "sm", "lg", "icon"],
    },
  },
} satisfies Meta<typeof Button>;

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

export const Default: Story = {
  args: {
    children: "Button",
  },
};

export const Destructive: Story = {
  args: {
    variant: "destructive",
    children: "Delete",
  },
};

export const Outline: Story = {
  args: {
    variant: "outline",
    children: "Outline",
  },
};

export const Small: Story = {
  args: {
    size: "sm",
    children: "Small Button",
  },
};

export const Large: Story = {
  args: {
    size: "lg",
    children: "Large Button",
  },
};

export const WithIcon: Story = {
  args: {
    children: (
      <>
        <span className="mr-2">📥</span>
        Download
      </>
    ),
  },
};

export const Disabled: Story = {
  args: {
    children: "Disabled Button",
    disabled: true,
  },
};
```

### Complex Story with Interactions

```typescript
import type { Meta, StoryObj } from "@storybook/react";
import { within, userEvent, expect } from "@storybook/test";
import { Card, CardHeader, CardTitle, CardContent } from "./card";

const meta = {
  title: "Components/Card",
  component: Card,
  parameters: {
    layout: "centered",
  },
  tags: ["autodocs"],
} satisfies Meta<typeof Card>;

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

export const Default: Story = {
  render: () => (
    <Card className="w-[350px]">
      <CardHeader>
        <CardTitle>Card Title</CardTitle>
      </CardHeader>
      <CardContent>
        <p>Card content goes here.</p>
      </CardContent>
    </Card>
  ),
};

export const WithInteraction: Story = {
  render: () => (
    <Card className="w-[350px]">
      <CardHeader>
        <CardTitle>Interactive Card</CardTitle>
      </CardHeader>
      <CardContent>
        <button data-testid="card-button">Click me</button>
      </CardContent>
    </Card>
  ),
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    const button = canvas.getByTestId("card-button");

    await userEvent.click(button);
    await expect(button).toBeInTheDocument();
  },
};
```

## TypeDoc for API Documentation

### Setup TypeDoc

```bash
cd packages/ui

pnpm add -D typedoc
```

Add to `package.json`:

```json
{
  "scripts": {
    "docs:generate": "typedoc --out docs/api src/index.ts"
  }
}
```

### TypeDoc Configuration

```typescript
// packages/ui/typedoc.json
{
  "entryPoints": ["src/index.ts"],
  "out": "docs/api",
  "exclude": ["**/*.test.ts", "**/*.stories.tsx"],
  "excludePrivate": true,
  "excludeProtected": true,
  "plugin": ["typedoc-plugin-markdown"],
  "readme": "README.md",
  "theme": "default"
}
```

Generate documentation:

```bash
pnpm docs:generate
```

## README Documentation

### Package README Template

```markdown
# @sgcarstrends/ui

Shared UI component library for SG Cars Trends platform.

## Installation

\`\`\`bash
pnpm add @sgcarstrends/ui
\`\`\`

## Usage

\`\`\`tsx
import { Button, Card, Dialog } from "@sgcarstrends/ui";

export function Example() {
  return (
    <Card>
      <Button>Click me</Button>
    </Card>
  );
}
\`\`\`

## Components

### Core Components
- [Button](docs/components/button.md) - Customizable button with variants
- [Card](docs/components/card.md) - Container for content
- [Dialog](docs/components/dialog.md) - Modal dialog
- [Badge](docs/components/badge.md) - Status badges

### Form Components
- [Input](docs/components/input.md) - Text input
- [Textarea](docs/components/textarea.md) - Multi-line text input
- [Select](docs/components/select.md) - Dropdown select
- [Checkbox](docs/components/checkbox.md) - Checkbox input

### Layout Components
- [Separator](docs/components/separator.md) - Visual divider
- [Tabs](docs/components/tabs.md) - Tabbed interface

## Styling

Components use Tailwind CSS and CSS variables for theming.

### Dark Mode

Dark mode is supported via CSS variables defined in \`globals.css\`.

### Customization

Customize component styles:

\`\`\`tsx
<Button className="custom-classes">Custom Button</Button>
\`\`\`

## Development

\`\`\`bash
# Install dependencies
pnpm install

# Run tests
pnpm test

# Run Storybook
pnpm storybook

# Build package
pnpm build
\`\`\`

## Contributing

See [CONTRIBUTING.md](../../CONTRIBUTING.md)

## License

MIT
```

## Props Table Generator

Create a script to generate props tables from TypeScript:

```typescript
// scripts/generate-props-table.ts
import * as ts from "typescript";
import * as fs from "fs";

function generatePropsTable(componentPath: string) {
  const program = ts.createProgram([componentPath], {});
  const sourceFile = program.getSourceFile(componentPath);

  if (!sourceFile) return;

  const checker = program.getTypeChecker();

  ts.forEachChild(sourceFile, (node) => {
    if (ts.isInterfaceDeclaration(node) && node.name.text.endsWith("Props")) {
      console.log(`| Prop | Type | Default | Description |`);
      console.log(`|------|------|---------|-------------|`);

      node.members.forEach((member) => {
        if (ts.isPropertySignature(member) && member.name) {
          const name = member.name.getText(sourceFile);
          const type = checker.typeToString(
            checker.getTypeAtLocation(member)
          );
          const docs = ts.displayPartsToString(
            member.symbol?.getDocumentationComment(checker)
          );

          console.log(`| ${name} | \`${type}\` | - | ${docs} |`);
        }
      });
    }
  });
}

// Usage
generatePropsTable("src/components/button.tsx");
```

## Component Checklist

When documenting a component, ensure:

- [ ] Component file has JSDoc comments
- [ ] Props interface is fully documented
- [ ] Markdown documentation file exists
- [ ] Usage examples provided
- [ ] Props table included
- [ ] Variants documented
- [ ] Accessibility notes added
- [ ] Related components linked
- [ ] Storybook stories created (if using Storybook)
- [ ] Exported from package index
- [ ] Added to README component list

## Documentation Patterns

### Code Examples

Always provide working code examples:

```markdown
## Example: Search Form

\`\`\`tsx
"use client";

import { useState } from "react";
import { Input, Button } from "@sgcarstrends/ui";

export function SearchForm() {
  const [query, setQuery] = useState("");

  return (
    <form className="flex gap-2">
      <Input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder="Search..."
      />
      <Button type="submit">Search</Button>
    </form>
  );
}
\`\`\`
```

### Do's and Don'ts

```markdown
## Best Practices

### ✅ Do

- Use semantic HTML elements
- Provide accessible labels
- Test keyboard navigation
- Support dark mode

### ❌ Don't

- Nest buttons inside buttons
- Forget hover states
- Override core styles directly
- Skip accessibility attributes
```

## Automated Documentation

### Using react-docgen

```bash
pnpm add -D react-docgen-typescript
```

```typescript
// scripts/generate-docs.ts
import { parse } from "react-docgen-typescript";

const options = {
  savePropValueAsString: true,
  shouldExtractLiteralValuesFromEnum: true,
};

const docs = parse("src/components/button.tsx", options);

console.log(JSON.stringify(docs, null, 2));
```

## Testing Documentation

Ensure examples work:

```typescript
// __tests__/docs/examples.test.tsx
import { render } from "@testing-library/react";

// Test all documented examples
describe("Documentation Examples", () => {
  it("renders basic button example", () => {
    const { container } = render(<Button>Click me</Button>);
    expect(container.querySelector("button")).toBeInTheDocument();
  });

  it("renders button with icon example", () => {
    const { container } = render(
      <Button>
        <span className="mr-2">📥</span>
        Download
      </Button>
    );
    expect(container.textContent).toContain("Download");
  });
});
```

## References

- Related files:
  - `packages/ui/docs/` - Component documentation
  - `packages/ui/README.md` - Package overview
  - `packages/ui/src/components/*.stories.tsx` - Storybook stories
  - `packages/ui/CLAUDE.md` - UI package documentation

## Best Practices

1. **Clear Examples**: Provide complete, working code examples
2. **Props Documentation**: Document every prop with type and description
3. **Accessibility**: Include accessibility notes
4. **Visual Examples**: Use Storybook for interactive demos
5. **Keep Updated**: Update docs when components change
6. **Search Friendly**: Use clear headings and keywords
7. **Code Quality**: Test documented examples
8. **Version History**: Track changes in documentation

Quick Install

$npx ai-builder add skill sgcarstrends/component-docs

Details

Type
skill
Slug
sgcarstrends/component-docs
Created
4d ago