Initial commit
This commit is contained in:
557
skills/documentation/SKILL.md
Normal file
557
skills/documentation/SKILL.md
Normal file
@@ -0,0 +1,557 @@
|
||||
---
|
||||
name: documentation
|
||||
description: Generate comprehensive feature documentation including Storybook stories, JSDoc comments, and feature guides. Use after completing a feature (may span multiple commits). Creates documentation for humans and AI to understand features, usage patterns, and design decisions.
|
||||
---
|
||||
|
||||
# Documentation (TypeScript + React)
|
||||
|
||||
Generate comprehensive documentation for features, components, and hooks.
|
||||
|
||||
## When to Use
|
||||
- After completing a feature (may span multiple commits)
|
||||
- When a component/hook needs usage documentation
|
||||
- When design decisions need recording
|
||||
- For public/shared components and hooks
|
||||
|
||||
## Documentation Types
|
||||
|
||||
### 1. Storybook Stories (Component Documentation)
|
||||
**Purpose**: Visual documentation of component usage and variants
|
||||
|
||||
**Creates**: `.stories.tsx` files alongside components
|
||||
|
||||
### 2. JSDoc Comments (Code Documentation)
|
||||
**Purpose**: Inline documentation for types, props, complex functions
|
||||
|
||||
**Location**: In source files (`.ts`, `.tsx`)
|
||||
|
||||
### 3. Feature Documentation (Architectural Documentation)
|
||||
**Purpose**: WHY decisions were made, HOW feature works, WHAT to extend
|
||||
|
||||
**Creates**: `docs/features/[feature-name].md`
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Identify Documentation Needs
|
||||
|
||||
Ask:
|
||||
- Is this a reusable component? → Storybook story
|
||||
- Is this a custom hook? → JSDoc + usage example
|
||||
- Is this a complete feature? → Feature documentation
|
||||
- Are types/props complex? → JSDoc comments
|
||||
|
||||
### 2. Create Storybook Stories
|
||||
|
||||
**For each component**, create stories showing:
|
||||
- Default state
|
||||
- All variants/props
|
||||
- Interactive states
|
||||
- Edge cases (loading, error, empty)
|
||||
|
||||
**Example**:
|
||||
```typescript
|
||||
// src/components/Button/Button.stories.tsx
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import { Button } from './Button'
|
||||
|
||||
const meta: Meta<typeof Button> = {
|
||||
title: 'Components/Button',
|
||||
component: Button,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: 'select',
|
||||
options: ['primary', 'secondary', 'danger']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof Button>
|
||||
|
||||
// Default story
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
label: 'Button',
|
||||
variant: 'primary',
|
||||
onClick: () => alert('clicked')
|
||||
}
|
||||
}
|
||||
|
||||
// Variants
|
||||
export const Secondary: Story = {
|
||||
args: {
|
||||
...Primary.args,
|
||||
variant: 'secondary'
|
||||
}
|
||||
}
|
||||
|
||||
export const Danger: Story = {
|
||||
args: {
|
||||
...Primary.args,
|
||||
variant: 'danger'
|
||||
}
|
||||
}
|
||||
|
||||
// States
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
...Primary.args,
|
||||
isDisabled: true
|
||||
}
|
||||
}
|
||||
|
||||
export const Loading: Story = {
|
||||
args: {
|
||||
...Primary.args,
|
||||
isLoading: true
|
||||
}
|
||||
}
|
||||
|
||||
// Interactive example
|
||||
export const WithIcon: Story = {
|
||||
args: {
|
||||
...Primary.args,
|
||||
icon: <IconCheck />
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Add JSDoc Comments
|
||||
|
||||
**For public types and interfaces**:
|
||||
```typescript
|
||||
/**
|
||||
* Props for the Button component.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <Button
|
||||
* label="Click me"
|
||||
* variant="primary"
|
||||
* onClick={() => console.log('clicked')}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export interface ButtonProps {
|
||||
/** The text to display on the button */
|
||||
label: string
|
||||
|
||||
/** The visual style variant of the button */
|
||||
variant?: 'primary' | 'secondary' | 'danger'
|
||||
|
||||
/** Callback fired when the button is clicked */
|
||||
onClick: () => void
|
||||
|
||||
/** If true, the button will be disabled */
|
||||
isDisabled?: boolean
|
||||
|
||||
/** If true, the button will show a loading spinner */
|
||||
isLoading?: boolean
|
||||
}
|
||||
```
|
||||
|
||||
**For custom hooks**:
|
||||
```typescript
|
||||
/**
|
||||
* Custom hook for managing user authentication state.
|
||||
*
|
||||
* Handles login, logout, and persisting auth state to localStorage.
|
||||
* Automatically refreshes token when it expires.
|
||||
*
|
||||
* @param options - Configuration options for authentication
|
||||
* @returns Authentication state and methods
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* function LoginForm() {
|
||||
* const { login, isLoading, error } = useAuth()
|
||||
*
|
||||
* const handleSubmit = async (email: string, password: string) => {
|
||||
* await login(email, password)
|
||||
* }
|
||||
*
|
||||
* return <Form onSubmit={handleSubmit} isLoading={isLoading} error={error} />
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function useAuth(options?: AuthOptions): UseAuthReturn {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
**For complex types**:
|
||||
```typescript
|
||||
/**
|
||||
* Represents the state of an asynchronous operation.
|
||||
*
|
||||
* Uses discriminated union to ensure invalid states are impossible
|
||||
* (e.g., cannot have both data and error simultaneously).
|
||||
*
|
||||
* @template T - The type of data returned on success
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const [state, setState] = useState<AsyncState<User>>({ status: 'idle' })
|
||||
*
|
||||
* // Type narrowing works automatically
|
||||
* if (state.status === 'success') {
|
||||
* console.log(state.data.name) // state.data is available and typed
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export type AsyncState<T> =
|
||||
| { status: 'idle' }
|
||||
| { status: 'loading' }
|
||||
| { status: 'success'; data: T }
|
||||
| { status: 'error'; error: Error }
|
||||
```
|
||||
|
||||
### 4. Create Feature Documentation
|
||||
|
||||
**For completed features**, create `docs/features/[feature-name].md`:
|
||||
|
||||
**Template**:
|
||||
```markdown
|
||||
# Feature: [Feature Name]
|
||||
|
||||
## Overview
|
||||
Brief description of what the feature does and why it exists.
|
||||
|
||||
## Problem
|
||||
What problem does this feature solve? What was the pain point?
|
||||
|
||||
## Solution
|
||||
How does this feature solve the problem? What approach was taken?
|
||||
|
||||
## Architecture
|
||||
|
||||
### Components
|
||||
- **ComponentName**: Purpose and responsibility
|
||||
- **AnotherComponent**: Purpose and responsibility
|
||||
|
||||
### Hooks
|
||||
- **useFeatureHook**: What it does and why it's separate
|
||||
|
||||
### Context
|
||||
- **FeatureContext**: What state it manages and why context was needed
|
||||
|
||||
### Types
|
||||
- **KeyType**: What it represents and why it's a custom type
|
||||
|
||||
## Key Design Decisions
|
||||
|
||||
### 1. [Decision Title]
|
||||
**Decision**: What was decided
|
||||
**Rationale**: Why this approach was chosen
|
||||
**Alternatives**: What other approaches were considered
|
||||
**Trade-offs**: What we gained and what we gave up
|
||||
|
||||
### 2. [Another Decision]
|
||||
...
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
```typescript
|
||||
// Simple example showing most common use case
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
```typescript
|
||||
// Example showing advanced features or edge cases
|
||||
```
|
||||
|
||||
### Integration
|
||||
How this feature integrates with other parts of the application.
|
||||
|
||||
## API Reference
|
||||
|
||||
### Components
|
||||
|
||||
#### ComponentName
|
||||
Props:
|
||||
- `propName` (Type): Description
|
||||
|
||||
Events:
|
||||
- `onEvent`: When it fires and what it provides
|
||||
|
||||
#### AnotherComponent
|
||||
...
|
||||
|
||||
### Hooks
|
||||
|
||||
#### useFeatureHook
|
||||
Parameters:
|
||||
- `param` (Type): Description
|
||||
|
||||
Returns:
|
||||
- `returnValue` (Type): Description
|
||||
|
||||
### Types
|
||||
|
||||
#### TypeName
|
||||
```typescript
|
||||
type TypeName = ...
|
||||
```
|
||||
|
||||
Description of when and how to use this type.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
- What is tested at the unit level (pure components, hooks)
|
||||
- Coverage expectations (100% for leaf components)
|
||||
|
||||
### Integration Tests
|
||||
- What user flows are tested
|
||||
- How mocking is handled (MSW for APIs)
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Compliance
|
||||
- WCAG level compliance (A, AA, AAA)
|
||||
- What accessibility features are implemented
|
||||
|
||||
### Keyboard Navigation
|
||||
- What keyboard shortcuts are supported
|
||||
- How tab order works
|
||||
|
||||
### Screen Reader Support
|
||||
- What ARIA attributes are used
|
||||
- What announcements are made
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Optimizations
|
||||
- What performance optimizations are implemented
|
||||
- Use of memo, useMemo, useCallback
|
||||
|
||||
### Bundle Impact
|
||||
- Approximate bundle size contribution
|
||||
- Any lazy loading or code splitting
|
||||
|
||||
## Known Limitations
|
||||
|
||||
### Current Limitations
|
||||
- What doesn't work yet
|
||||
- What edge cases aren't handled
|
||||
|
||||
### Future Enhancements
|
||||
- What could be improved
|
||||
- What features could be added
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Issue: [Problem Description]
|
||||
**Symptom**: What users will see
|
||||
**Cause**: Why this happens
|
||||
**Solution**: How to fix it
|
||||
|
||||
## Related Features
|
||||
- Links to related documentation
|
||||
- Dependencies on other features
|
||||
- Features that depend on this
|
||||
|
||||
## Migration Guide
|
||||
(If replacing existing functionality)
|
||||
|
||||
### Before
|
||||
```typescript
|
||||
// Old way
|
||||
```
|
||||
|
||||
### After
|
||||
```typescript
|
||||
// New way
|
||||
```
|
||||
|
||||
### Breaking Changes
|
||||
- What changed
|
||||
- How to update code
|
||||
|
||||
## Changelog
|
||||
- v1.1.0 (2024-01-15): Added support for...
|
||||
- v1.0.0 (2024-01-01): Initial implementation
|
||||
```
|
||||
|
||||
## Output Format
|
||||
|
||||
After generating documentation:
|
||||
|
||||
```
|
||||
📚 DOCUMENTATION GENERATED
|
||||
|
||||
Feature: User Authentication
|
||||
|
||||
Generated Files:
|
||||
✅ Storybook Stories (3 components)
|
||||
- src/features/auth/components/LoginForm.stories.tsx
|
||||
- src/features/auth/components/RegisterForm.stories.tsx
|
||||
- src/features/auth/components/PasswordInput.stories.tsx
|
||||
|
||||
✅ JSDoc Comments Added
|
||||
- src/features/auth/hooks/useAuth.ts (hook documentation)
|
||||
- src/features/auth/types.ts (type definitions)
|
||||
- src/features/auth/context/AuthContext.tsx (context API)
|
||||
|
||||
✅ Feature Documentation
|
||||
- docs/features/authentication.md (complete guide)
|
||||
|
||||
📖 Documentation includes:
|
||||
- Problem/solution overview
|
||||
- Architecture and design decisions
|
||||
- Usage examples (basic + advanced)
|
||||
- API reference (components, hooks, types)
|
||||
- Testing strategy
|
||||
- Accessibility features
|
||||
- Performance considerations
|
||||
- Troubleshooting guide
|
||||
|
||||
🎯 Next Steps:
|
||||
1. Review generated Storybook stories locally: npm run storybook
|
||||
2. Review feature documentation: docs/features/authentication.md
|
||||
3. Update any project-specific references or links
|
||||
4. Commit documentation with feature code
|
||||
|
||||
📝 Maintenance:
|
||||
- Update Storybook stories when component props change
|
||||
- Update JSDoc when APIs change
|
||||
- Update feature docs when design decisions change
|
||||
- Keep examples working (they're testable!)
|
||||
```
|
||||
|
||||
## Documentation Principles
|
||||
|
||||
### For Humans AND AI
|
||||
|
||||
Documentation serves two audiences:
|
||||
1. **Human developers**: Need to understand and extend code
|
||||
2. **AI assistants**: Need context to help debug and extend features
|
||||
|
||||
Write documentation that helps both audiences understand:
|
||||
- **WHY** decisions were made (context for future changes)
|
||||
- **HOW** the feature works (architecture and flow)
|
||||
- **WHAT** can be extended (integration points)
|
||||
|
||||
### Show, Don't Tell
|
||||
|
||||
Prefer code examples over prose descriptions:
|
||||
|
||||
**❌ Bad**:
|
||||
```
|
||||
The Button component accepts a variant prop that can be primary,
|
||||
secondary, or danger, and will style the button accordingly.
|
||||
```
|
||||
|
||||
**✅ Good**:
|
||||
```typescript
|
||||
<Button variant="primary" label="Save" />
|
||||
<Button variant="secondary" label="Cancel" />
|
||||
<Button variant="danger" label="Delete" />
|
||||
```
|
||||
|
||||
### Keep Examples Executable
|
||||
|
||||
Storybook stories and JSDoc examples should be real, working code that compiles and runs.
|
||||
|
||||
### Document Design Decisions
|
||||
|
||||
Most important: **WHY** decisions were made.
|
||||
|
||||
**❌ Bad**:
|
||||
```
|
||||
// Uses context for state management
|
||||
```
|
||||
|
||||
**✅ Good**:
|
||||
```
|
||||
/**
|
||||
* Uses AuthContext for state management instead of prop drilling.
|
||||
*
|
||||
* Decision: Context chosen because auth state is needed in 10+
|
||||
* components across different nesting levels (nav, profile, settings,
|
||||
* protected routes). Prop drilling would be unmaintainable.
|
||||
*
|
||||
* Alternative considered: Redux - overkill for single feature state
|
||||
*/
|
||||
```
|
||||
|
||||
## When to Document
|
||||
|
||||
### Always Document
|
||||
- Public/shared components
|
||||
- Custom hooks (except trivial ones)
|
||||
- Complex types (discriminated unions, branded types)
|
||||
- Completed features (spanning multiple commits)
|
||||
|
||||
### Consider Documenting
|
||||
- Complex utility functions
|
||||
- Non-obvious algorithms
|
||||
- Performance-critical code
|
||||
- Edge cases and workarounds
|
||||
|
||||
### Don't Over-Document
|
||||
- Trivial functions (self-explanatory)
|
||||
- Implementation details (private functions)
|
||||
- Obvious code (const user = getUser())
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Storybook
|
||||
- One story file per component
|
||||
- Show all variants
|
||||
- Include interactive controls
|
||||
- Document props with argTypes
|
||||
- Add accessibility checks (a11y addon)
|
||||
|
||||
### JSDoc
|
||||
- Use `@param`, `@returns`, `@example` tags
|
||||
- Include examples showing typical usage
|
||||
- Document complex types inline
|
||||
- Link related types with `@see`
|
||||
|
||||
### Feature Docs
|
||||
- Start with problem/solution
|
||||
- Include architecture diagrams (mermaid)
|
||||
- Provide working code examples
|
||||
- Document WHY, not just WHAT
|
||||
- Keep updated as feature evolves
|
||||
|
||||
## Tools
|
||||
|
||||
### Storybook Commands
|
||||
```bash
|
||||
# Run Storybook locally
|
||||
npm run storybook
|
||||
|
||||
# Build static Storybook
|
||||
npm run build-storybook
|
||||
|
||||
# Test stories (interaction testing)
|
||||
npm run test-storybook
|
||||
```
|
||||
|
||||
### TypeDoc (Alternative to JSDoc)
|
||||
```bash
|
||||
# Generate API documentation from TypeScript
|
||||
npx typedoc --entryPoints src/index.ts
|
||||
```
|
||||
|
||||
## Key Principles
|
||||
|
||||
See reference.md for detailed principles:
|
||||
- Document WHY, not just WHAT
|
||||
- Show working code examples
|
||||
- Keep docs close to code
|
||||
- Update docs with code changes
|
||||
- Test examples (Storybook)
|
||||
- Document for humans AND AI
|
||||
- Focus on usage, not implementation
|
||||
|
||||
See reference.md for complete documentation templates and examples.
|
||||
514
skills/documentation/reference.md
Normal file
514
skills/documentation/reference.md
Normal file
@@ -0,0 +1,514 @@
|
||||
# Documentation Reference (TypeScript + React)
|
||||
|
||||
## Documentation Strategy
|
||||
|
||||
### Three Layers
|
||||
|
||||
1. **Code Documentation** (JSDoc) - Inline with code
|
||||
2. **Component Documentation** (Storybook) - Visual examples
|
||||
3. **Feature Documentation** (Markdown) - Architecture and decisions
|
||||
|
||||
## JSDoc Best Practices
|
||||
|
||||
### Documenting Components
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* A reusable button component with multiple variants and states.
|
||||
*
|
||||
* Supports primary, secondary, and danger variants. Can display
|
||||
* loading states and be disabled. Fully accessible with ARIA attributes.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* // Primary button
|
||||
* <Button variant="primary" label="Save" onClick={handleSave} />
|
||||
*
|
||||
* // Loading state
|
||||
* <Button
|
||||
* variant="primary"
|
||||
* label="Saving..."
|
||||
* isLoading={true}
|
||||
* onClick={handleSave}
|
||||
* />
|
||||
*
|
||||
* // Disabled state
|
||||
* <Button
|
||||
* variant="secondary"
|
||||
* label="Cancel"
|
||||
* isDisabled={true}
|
||||
* onClick={handleCancel}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export function Button({ variant, label, onClick, isLoading, isDisabled }: ButtonProps) {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
### Documenting Hooks
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Manages form state and validation with Zod schema.
|
||||
*
|
||||
* Provides form values, errors, and handlers for controlled inputs.
|
||||
* Automatically validates on submit and provides field-level errors.
|
||||
*
|
||||
* @template T - The shape of the form data
|
||||
* @param schema - Zod schema for validation
|
||||
* @param initialValues - Initial form values
|
||||
* @param onSubmit - Callback called with validated data on successful submit
|
||||
* @returns Form state and handlers
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const LoginSchema = z.object({
|
||||
* email: z.string().email(),
|
||||
* password: z.string().min(8)
|
||||
* })
|
||||
*
|
||||
* function LoginForm() {
|
||||
* const { values, errors, setValue, handleSubmit } = useFormValidation(
|
||||
* LoginSchema,
|
||||
* { email: '', password: '' },
|
||||
* async (data) => {
|
||||
* await api.login(data.email, data.password)
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* return (
|
||||
* <form onSubmit={handleSubmit}>
|
||||
* <Input
|
||||
* label="Email"
|
||||
* value={values.email}
|
||||
* onChange={(e) => setValue('email', e.target.value)}
|
||||
* error={errors.email}
|
||||
* />
|
||||
* <Input
|
||||
* label="Password"
|
||||
* type="password"
|
||||
* value={values.password}
|
||||
* onChange={(e) => setValue('password', e.target.value)}
|
||||
* error={errors.password}
|
||||
* />
|
||||
* <button type="submit">Login</button>
|
||||
* </form>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function useFormValidation<T>(
|
||||
schema: ZodSchema<T>,
|
||||
initialValues: T,
|
||||
onSubmit: (data: T) => Promise<void>
|
||||
): UseFormValidationReturn<T> {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
### Documenting Types
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Branded type for user IDs.
|
||||
*
|
||||
* Prevents accidentally passing any string as a user ID.
|
||||
* Must be created through `createUserId` validation function.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // ❌ Error: Type 'string' is not assignable to type 'UserId'
|
||||
* const id: UserId = "some-id"
|
||||
*
|
||||
* // ✅ Must use constructor
|
||||
* const id = createUserId("uuid-here")
|
||||
*
|
||||
* // ✅ Type-safe function parameters
|
||||
* function getUser(id: UserId): User {
|
||||
* // id is guaranteed to be validated
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export type UserId = Brand<string, 'UserId'>
|
||||
|
||||
/**
|
||||
* Creates a validated UserId.
|
||||
*
|
||||
* @param value - String to validate as user ID
|
||||
* @returns Branded UserId type
|
||||
* @throws {Error} If value is empty or invalid format
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* try {
|
||||
* const id = createUserId("550e8400-e29b-41d4-a716-446655440000")
|
||||
* // id is now UserId type
|
||||
* } catch (error) {
|
||||
* console.error("Invalid user ID")
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function createUserId(value: string): UserId {
|
||||
if (!value || !isValidUUID(value)) {
|
||||
throw new Error(`Invalid user ID: ${value}`)
|
||||
}
|
||||
return value as UserId
|
||||
}
|
||||
```
|
||||
|
||||
## Storybook Templates
|
||||
|
||||
### Basic Component Story
|
||||
|
||||
```typescript
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import { Button } from './Button'
|
||||
|
||||
const meta: Meta<typeof Button> = {
|
||||
title: 'Components/Button',
|
||||
component: Button,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
docs: {
|
||||
description: {
|
||||
component: 'A versatile button component with multiple variants and states.'
|
||||
}
|
||||
}
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: 'select',
|
||||
options: ['primary', 'secondary', 'danger'],
|
||||
description: 'Visual style variant'
|
||||
},
|
||||
isDisabled: {
|
||||
control: 'boolean',
|
||||
description: 'Disables the button'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof Button>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
label: 'Button',
|
||||
variant: 'primary',
|
||||
onClick: () => console.log('clicked')
|
||||
}
|
||||
}
|
||||
|
||||
export const AllVariants: Story = {
|
||||
render: () => (
|
||||
<div style={{ display: 'flex', gap: '1rem' }}>
|
||||
<Button variant="primary" label="Primary" onClick={() => {}} />
|
||||
<Button variant="secondary" label="Secondary" onClick={() => {}} />
|
||||
<Button variant="danger" label="Danger" onClick={() => {}} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Form Component Story
|
||||
|
||||
```typescript
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
import { userEvent, within, expect } from '@storybook/test'
|
||||
import { LoginForm } from './LoginForm'
|
||||
|
||||
const meta: Meta<typeof LoginForm> = {
|
||||
title: 'Features/Auth/LoginForm',
|
||||
component: LoginForm,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
}
|
||||
}
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof LoginForm>
|
||||
|
||||
export const Default: Story = {}
|
||||
|
||||
// Interactive story with testing
|
||||
export const FilledForm: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement)
|
||||
|
||||
// Fill form
|
||||
await userEvent.type(canvas.getByLabelText(/email/i), 'test@example.com')
|
||||
await userEvent.type(canvas.getByLabelText(/password/i), 'password123')
|
||||
|
||||
// Click submit
|
||||
await userEvent.click(canvas.getByRole('button', { name: /log in/i }))
|
||||
|
||||
// Assert loading state appears
|
||||
await expect(canvas.getByText(/logging in/i)).toBeInTheDocument()
|
||||
}
|
||||
}
|
||||
|
||||
export const WithErrors: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement)
|
||||
|
||||
// Submit without filling
|
||||
await userEvent.click(canvas.getByRole('button', { name: /log in/i }))
|
||||
|
||||
// Assert errors appear
|
||||
await expect(canvas.getByText(/email is required/i)).toBeInTheDocument()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Feature Documentation Template
|
||||
|
||||
Complete template in SKILL.md. Key sections:
|
||||
|
||||
### Executive Summary
|
||||
```markdown
|
||||
# Feature: [Name]
|
||||
|
||||
## TL;DR
|
||||
One-paragraph summary of what this feature does and why it matters.
|
||||
|
||||
## Quick Start
|
||||
```typescript
|
||||
// Minimal example showing feature in action
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
### Problem & Solution
|
||||
```markdown
|
||||
## Problem
|
||||
What pain point does this solve? Be specific.
|
||||
|
||||
Example: "Users couldn't authenticate because..."
|
||||
|
||||
## Solution
|
||||
How does this feature solve it? High-level approach.
|
||||
|
||||
Example: "Implemented OAuth2 flow with JWT tokens..."
|
||||
```
|
||||
|
||||
### Architecture
|
||||
```markdown
|
||||
## Architecture
|
||||
|
||||
### Component Tree
|
||||
```
|
||||
AuthProvider
|
||||
└── LoginContainer
|
||||
├── LoginForm (presentational)
|
||||
├── PasswordInput (presentational)
|
||||
└── ErrorDisplay (presentational)
|
||||
```
|
||||
|
||||
### Data Flow
|
||||
```mermaid
|
||||
graph LR
|
||||
User[User Input] --> Form[LoginForm]
|
||||
Form --> Hook[useAuth]
|
||||
Hook --> API[Auth API]
|
||||
API --> Context[AuthContext]
|
||||
Context --> App[App State]
|
||||
```
|
||||
|
||||
### File Structure
|
||||
```
|
||||
src/features/auth/
|
||||
├── components/
|
||||
│ ├── LoginForm.tsx # Main form component
|
||||
│ ├── LoginForm.test.tsx # Tests
|
||||
│ └── LoginForm.stories.tsx # Storybook
|
||||
├── hooks/
|
||||
│ ├── useAuth.ts # Auth logic
|
||||
│ └── useAuth.test.ts # Hook tests
|
||||
├── context/
|
||||
│ └── AuthContext.tsx # Shared auth state
|
||||
├── types.ts # Email, UserId types
|
||||
├── api.ts # API client
|
||||
└── index.ts # Public exports
|
||||
```
|
||||
```
|
||||
|
||||
### Design Decisions
|
||||
```markdown
|
||||
## Key Design Decisions
|
||||
|
||||
### 1. Context for Auth State
|
||||
|
||||
**Decision**: Use React Context for auth state instead of prop drilling
|
||||
|
||||
**Rationale**:
|
||||
- Auth state needed in 10+ components (nav, profile, settings, routes)
|
||||
- Prop drilling through 4+ levels would be unmaintainable
|
||||
- Context provides clean API and prevents coupling
|
||||
|
||||
**Alternatives Considered**:
|
||||
- Redux: Overkill for single feature state
|
||||
- Zustand: Added dependency, context sufficient
|
||||
- Prop drilling: Would couple many components
|
||||
|
||||
**Trade-offs**:
|
||||
- ✅ Gained: Clean API, decoupled components, easy testing
|
||||
- ❌ Lost: Some component isolation, potential rerender issues
|
||||
- ⚖️ Mitigation: Split context into state and actions to minimize rerenders
|
||||
```
|
||||
|
||||
### Usage Examples
|
||||
```markdown
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
```typescript
|
||||
// Most common use case (90% of usage)
|
||||
function ProtectedPage() {
|
||||
const { user, logout } = useAuth()
|
||||
|
||||
if (!user) return <Redirect to="/login" />
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Welcome {user.name}</h1>
|
||||
<button onClick={logout}>Logout</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
```typescript
|
||||
// Complex scenario or edge case
|
||||
function AdminDashboard() {
|
||||
const { user, isLoading, error, refreshToken } = useAuth()
|
||||
|
||||
// Handle token refresh
|
||||
useEffect(() => {
|
||||
const interval = setInterval(refreshToken, 14 * 60 * 1000) // 14 min
|
||||
return () => clearInterval(interval)
|
||||
}, [refreshToken])
|
||||
|
||||
// ... rest of component
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## Documentation Checklist
|
||||
|
||||
Before considering documentation complete:
|
||||
|
||||
### Storybook Stories
|
||||
- [ ] Story file created for each component
|
||||
- [ ] Default story shows typical usage
|
||||
- [ ] All prop variants documented
|
||||
- [ ] Interactive states shown (loading, error, disabled)
|
||||
- [ ] Accessibility checks pass (a11y addon)
|
||||
- [ ] Controls configured for props
|
||||
- [ ] Component description added
|
||||
|
||||
### JSDoc Comments
|
||||
- [ ] All public types documented
|
||||
- [ ] All custom hooks documented
|
||||
- [ ] Complex functions documented
|
||||
- [ ] Examples included and working
|
||||
- [ ] Parameters documented with types
|
||||
- [ ] Return values documented
|
||||
|
||||
### Feature Documentation
|
||||
- [ ] Problem/solution described
|
||||
- [ ] Architecture explained
|
||||
- [ ] Design decisions documented (WHY)
|
||||
- [ ] Usage examples provided (basic + advanced)
|
||||
- [ ] API reference complete
|
||||
- [ ] Testing strategy documented
|
||||
- [ ] Accessibility features listed
|
||||
- [ ] Troubleshooting guide included
|
||||
- [ ] Related features linked
|
||||
|
||||
## Documentation Maintenance
|
||||
|
||||
### When Code Changes
|
||||
|
||||
| Change | Update Needed |
|
||||
|--------|--------------|
|
||||
| New prop added | Update Storybook story, JSDoc, examples |
|
||||
| Prop removed | Update all documentation, mark as breaking |
|
||||
| New variant | Add Storybook story, update docs |
|
||||
| API change | Update JSDoc, examples, feature docs |
|
||||
| New hook | Create JSDoc, add examples |
|
||||
| Refactor (no API change) | May update architecture docs |
|
||||
| Bug fix | Update troubleshooting if relevant |
|
||||
| Design decision changed | Update design decisions section |
|
||||
|
||||
### Regular Reviews
|
||||
|
||||
- **Quarterly**: Review all feature docs for accuracy
|
||||
- **On major releases**: Update all examples to latest API
|
||||
- **When onboarding**: Test docs with new team members
|
||||
|
||||
## Tools and Automation
|
||||
|
||||
### Storybook Addons
|
||||
|
||||
```javascript
|
||||
// .storybook/main.js
|
||||
module.exports = {
|
||||
addons: [
|
||||
'@storybook/addon-essentials', // Docs, controls, actions, etc.
|
||||
'@storybook/addon-a11y', // Accessibility checks
|
||||
'@storybook/addon-interactions', // Interactive testing
|
||||
'@storybook/addon-links' // Navigate between stories
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### TypeDoc Configuration
|
||||
|
||||
```json
|
||||
// typedoc.json
|
||||
{
|
||||
"entryPoints": ["src/index.ts"],
|
||||
"out": "docs/api",
|
||||
"exclude": ["**/*.test.ts", "**/*.stories.tsx"],
|
||||
"excludePrivate": true,
|
||||
"excludeProtected": true,
|
||||
"readme": "README.md"
|
||||
}
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
### Key Principles
|
||||
|
||||
1. **Document WHY**: Decisions and trade-offs
|
||||
2. **Show Code**: Working examples over prose
|
||||
3. **Keep Updated**: Docs with code changes
|
||||
4. **Test Examples**: Storybook stories compile and run
|
||||
5. **Multiple Audiences**: Humans and AI both need context
|
||||
6. **Focus on Usage**: Not implementation details
|
||||
7. **Colocate**: Docs near code they document
|
||||
|
||||
### Documentation Types
|
||||
|
||||
- **JSDoc**: Inline code documentation
|
||||
- **Storybook**: Visual component examples
|
||||
- **Feature Docs**: Architecture and decisions
|
||||
|
||||
### Quality Indicators
|
||||
|
||||
Good documentation:
|
||||
- Has working code examples
|
||||
- Explains WHY, not just WHAT
|
||||
- Shows common AND edge cases
|
||||
- Is kept up to date
|
||||
- Helps both debugging and extending
|
||||
|
||||
Bad documentation:
|
||||
- Out of date with code
|
||||
- Only describes WHAT code does
|
||||
- No examples or broken examples
|
||||
- Implementation details instead of usage
|
||||
- Written once, never updated
|
||||
Reference in New Issue
Block a user