Scaffold React component with TypeScript, tests, and Storybook. Use when creating React/TypeScript components.
npx claudepluginhub buldee/ai-craftsman-superpowersScaffold a complete React component with TypeScript, tests, and optional Storybook.
This command requires the React Pack to be enabled.
First, check if the pack is activated:
grep "react:" ~/.claude/.craft-config.yml 2>/dev/null | grep "true"
Display this message and STOP:
React Pack Required
This command is part of the React Pack which is not currently enabled.
To enable it:
1. Run /craftsman:setup
2. Select "React Pack" when prompted
3. Try this command again
Alternatively, you can use /craftsman:design for general component design
guidance that works with any technology stack.
Do NOT proceed with scaffolding if the pack is not enabled.
Continue with the scaffolding process below.
src/
└── components/
└── {ComponentName}/
├── {ComponentName}.tsx
├── {ComponentName}.test.tsx
├── {ComponentName}.stories.tsx (optional)
└── index.ts
import { type ReactNode } from 'react';
export interface {ComponentName}Props {
readonly children?: ReactNode;
readonly className?: string;
// Add other props with explicit types
}
export function {ComponentName}({
children,
className,
}: {ComponentName}Props): ReactNode {
return (
<div className={className}>
{children}
</div>
);
}
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi } from 'vitest';
import { {ComponentName} } from './{ComponentName}';
describe('{ComponentName}', () => {
it('renders children', () => {
render(<{ComponentName}>Test content</{ComponentName}>);
expect(screen.getByText('Test content')).toBeInTheDocument();
});
it('applies className', () => {
render(<{ComponentName} className="custom-class">Content</{ComponentName}>);
expect(screen.getByText('Content').parentElement).toHaveClass('custom-class');
});
// Add more behavioral tests
});
import type { Meta, StoryObj } from '@storybook/react';
import { {ComponentName} } from './{ComponentName}';
const meta: Meta<typeof {ComponentName}> = {
title: 'Components/{ComponentName}',
component: {ComponentName},
tags: ['autodocs'],
argTypes: {
// Define controls for props
},
};
export default meta;
type Story = StoryObj<typeof {ComponentName}>;
export const Default: Story = {
args: {
children: 'Default content',
},
};
export const WithCustomClass: Story = {
args: {
children: 'Styled content',
className: 'bg-blue-500 text-white p-4',
},
};
export { {ComponentName} } from './{ComponentName}';
export type { {ComponentName}Props } from './{ComponentName}';
| Rule | Enforcement |
|---|---|
No any types | Explicit types or unknown |
readonly props | All interface properties |
| Named exports | No default exports |
| Branded types | For domain primitives |
| Function components | No class components |
// types/branded.ts
declare const brand: unique symbol;
type Brand<T, B> = T & { readonly [brand]: B };
export type UserId = Brand<string, 'UserId'>;
export type Email = Brand<string, 'Email'>;
// Usage in component
interface UserCardProps {
readonly userId: UserId;
readonly email: Email;
}
type ButtonVariant = 'primary' | 'secondary' | 'danger';
interface ButtonProps {
readonly variant: ButtonVariant;
readonly disabled?: boolean;
readonly onClick: () => void;
}
// Specific children type
interface CardProps {
readonly header: ReactNode;
readonly children: ReactNode;
readonly footer?: ReactNode;
}
// Render props
interface DataFetcherProps<T> {
readonly url: string;
readonly children: (data: T) => ReactNode;
}
BEFORE generating any code, you MUST use the Read tool to load:
Read: knowledge/canonical/ts-react-component.tsx
Read: knowledge/canonical/ts-branded-type.ts
This ensures generated code matches project standards exactly.
npm run typecheck
npm test -- --filter={ComponentName}
| Anti-Pattern | Why Bad | Correct Approach |
|---|---|---|
| Prop drilling | Tight coupling | Context or composition |
any types | No type safety | Proper types or unknown |
| Default exports | Harder refactoring | Named exports only |
Non-null assertion ! | Hides bugs | Handle null explicitly |
| Inline styles | Inconsistent | Tailwind or CSS modules |