frontend-mobile-development-component-scaffold
TypeScriptや型定義・テスト・スタイルを含む、本番品質のReactコンポーネントをゼロからスキャフォールドするエキスパートエージェントです。アクセシビリティとパフォーマンスを考慮した完全な実装を自動生成したい場合に活用できます。
description の原文を見る
You are a React component architecture expert specializing in scaffolding production-ready, accessible, and performant components. Generate complete component implementations with TypeScript, tests, s
SKILL.md 本文
React/React Native コンポーネント スキャフォルディング
React コンポーネント アーキテクチャの専門家として、本番環境対応、アクセス可能、高性能なコンポーネントのスキャフォルディングを専門とします。TypeScript、テスト、スタイル、ドキュメントを含む完全なコンポーネント実装を、モダンなベストプラクティスに従って生成します。
このスキルを使用する場合
- React/React Native コンポーネント スキャフォルディングのタスクやワークフローに取り組んでいる場合
- React/React Native コンポーネント スキャフォルディングのガイダンス、ベストプラクティス、またはチェックリストが必要な場合
このスキルを使用しない場合
- タスクが React/React Native コンポーネント スキャフォルディングと無関係な場合
- このスコープ外の別のドメインやツールが必要な場合
コンテキスト
ユーザーは、適切な構造、フック、スタイリング、アクセシビリティ、テストカバレッジを備えた、一貫性のある型安全な React コンポーネントを作成する自動化されたコンポーネント スキャフォルディングが必要です。再利用可能なパターンと拡張可能なアーキテクチャに焦点を当てます。
要件
$ARGUMENTS
指示
1. コンポーネント要件の分析
interface ComponentSpec {
name: string;
type: 'functional' | 'page' | 'layout' | 'form' | 'data-display';
props: PropDefinition[];
state?: StateDefinition[];
hooks?: string[];
styling: 'css-modules' | 'styled-components' | 'tailwind';
platform: 'web' | 'native' | 'universal';
}
interface PropDefinition {
name: string;
type: string;
required: boolean;
defaultValue?: any;
description: string;
}
class ComponentAnalyzer {
parseRequirements(input: string): ComponentSpec {
// ユーザー入力からコンポーネント仕様を抽出
return {
name: this.extractName(input),
type: this.inferType(input),
props: this.extractProps(input),
state: this.extractState(input),
hooks: this.identifyHooks(input),
styling: this.detectStylingApproach(),
platform: this.detectPlatform()
};
}
}
2. React コンポーネントの生成
interface GeneratorOptions {
typescript: boolean;
testing: boolean;
storybook: boolean;
accessibility: boolean;
}
class ReactComponentGenerator {
generate(spec: ComponentSpec, options: GeneratorOptions): ComponentFiles {
return {
component: this.generateComponent(spec, options),
types: options.typescript ? this.generateTypes(spec) : null,
styles: this.generateStyles(spec),
tests: options.testing ? this.generateTests(spec) : null,
stories: options.storybook ? this.generateStories(spec) : null,
index: this.generateIndex(spec)
};
}
generateComponent(spec: ComponentSpec, options: GeneratorOptions): string {
const imports = this.generateImports(spec, options);
const types = options.typescript ? this.generatePropTypes(spec) : '';
const component = this.generateComponentBody(spec, options);
const exports = this.generateExports(spec);
return `${imports}\n\n${types}\n\n${component}\n\n${exports}`;
}
generateImports(spec: ComponentSpec, options: GeneratorOptions): string {
const imports = ["import React, { useState, useEffect } from 'react';"];
if (spec.styling === 'css-modules') {
imports.push(`import styles from './${spec.name}.module.css';`);
} else if (spec.styling === 'styled-components') {
imports.push("import styled from 'styled-components';");
}
if (options.accessibility) {
imports.push("import { useA11y } from '@/hooks/useA11y';");
}
return imports.join('\n');
}
generatePropTypes(spec: ComponentSpec): string {
const props = spec.props.map(p => {
const optional = p.required ? '' : '?';
const comment = p.description ? ` /** ${p.description} */\n` : '';
return `${comment} ${p.name}${optional}: ${p.type};`;
}).join('\n');
return `export interface ${spec.name}Props {\n${props}\n}`;
}
generateComponentBody(spec: ComponentSpec, options: GeneratorOptions): string {
const propsType = options.typescript ? `: React.FC<${spec.name}Props>` : '';
const destructuredProps = spec.props.map(p => p.name).join(', ');
let body = `export const ${spec.name}${propsType} = ({ ${destructuredProps} }) => {\n`;
// State フックを追加
if (spec.state) {
body += spec.state.map(s =>
` const [${s.name}, set${this.capitalize(s.name)}] = useState${options.typescript ? `<${s.type}>` : ''}(${s.initial});\n`
).join('');
body += '\n';
}
// エフェクトを追加
if (spec.hooks?.includes('useEffect')) {
body += ` useEffect(() => {\n`;
body += ` // TODO: エフェクトロジックを追加\n`;
body += ` }, [${destructuredProps}]);\n\n`;
}
// アクセシビリティを追加
if (options.accessibility) {
body += ` const a11yProps = useA11y({\n`;
body += ` role: '${this.inferAriaRole(spec.type)}',\n`;
body += ` label: ${spec.props.find(p => p.name === 'label')?.name || `'${spec.name}'`}\n`;
body += ` });\n\n`;
}
// JSX リターン
body += ` return (\n`;
body += this.generateJSX(spec, options);
body += ` );\n`;
body += `};`;
return body;
}
generateJSX(spec: ComponentSpec, options: GeneratorOptions): string {
const className = spec.styling === 'css-modules' ? `className={styles.${this.camelCase(spec.name)}}` : '';
const a11y = options.accessibility ? '{...a11yProps}' : '';
return ` <div ${className} ${a11y}>\n` +
` {/* TODO: コンポーネント内容を追加 */}\n` +
` </div>\n`;
}
}
3. React Native コンポーネントの生成
class ReactNativeGenerator {
generateComponent(spec: ComponentSpec): string {
return `
import React, { useState } from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
AccessibilityInfo
} from 'react-native';
interface ${spec.name}Props {
${spec.props.map(p => ` ${p.name}${p.required ? '' : '?'}: ${this.mapNativeType(p.type)};`).join('\n')}
}
export const ${spec.name}: React.FC<${spec.name}Props> = ({
${spec.props.map(p => p.name).join(',\n ')}
}) => {
return (
<View
style={styles.container}
accessible={true}
accessibilityLabel="${spec.name} component"
>
<Text style={styles.text}>
{/* コンポーネント内容 */}
</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 16,
backgroundColor: '#fff',
},
text: {
fontSize: 16,
color: '#333',
},
});
`;
}
mapNativeType(webType: string): string {
const typeMap: Record<string, string> = {
'string': 'string',
'number': 'number',
'boolean': 'boolean',
'React.ReactNode': 'React.ReactNode',
'Function': '() => void'
};
return typeMap[webType] || webType;
}
}
4. コンポーネント テストの生成
class ComponentTestGenerator {
generateTests(spec: ComponentSpec): string {
return `
import { render, screen, fireEvent } from '@testing-library/react';
import { ${spec.name} } from './${spec.name}';
describe('${spec.name}', () => {
const defaultProps = {
${spec.props.filter(p => p.required).map(p => ` ${p.name}: ${this.getMockValue(p.type)},`).join('\n')}
};
it('renders without crashing', () => {
render(<${spec.name} {...defaultProps} />);
expect(screen.getByRole('${this.inferAriaRole(spec.type)}')).toBeInTheDocument();
});
it('displays correct content', () => {
render(<${spec.name} {...defaultProps} />);
expect(screen.getByText(/content/i)).toBeVisible();
});
${spec.props.filter(p => p.type.includes('()') || p.name.startsWith('on')).map(p => `
it('calls ${p.name} when triggered', () => {
const mock${this.capitalize(p.name)} = jest.fn();
render(<${spec.name} {...defaultProps} ${p.name}={mock${this.capitalize(p.name)}} />);
const trigger = screen.getByRole('button');
fireEvent.click(trigger);
expect(mock${this.capitalize(p.name)}).toHaveBeenCalledTimes(1);
});`).join('\n')}
it('meets accessibility standards', async () => {
const { container } = render(<${spec.name} {...defaultProps} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
`;
}
getMockValue(type: string): string {
if (type === 'string') return "'test value'";
if (type === 'number') return '42';
if (type === 'boolean') return 'true';
if (type.includes('[]')) return '[]';
if (type.includes('()')) return 'jest.fn()';
return '{}';
}
}
5. スタイルの生成
class StyleGenerator {
generateCSSModule(spec: ComponentSpec): string {
const className = this.camelCase(spec.name);
return `
.${className} {
display: flex;
flex-direction: column;
padding: 1rem;
background-color: var(--bg-primary);
}
.${className}Title {
font-size: 1.5rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 0.5rem;
}
.${className}Content {
flex: 1;
color: var(--text-secondary);
}
`;
}
generateStyledComponents(spec: ComponentSpec): string {
return `
import styled from 'styled-components';
export const ${spec.name}Container = styled.div\`
display: flex;
flex-direction: column;
padding: \${({ theme }) => theme.spacing.md};
background-color: \${({ theme }) => theme.colors.background};
\`;
export const ${spec.name}Title = styled.h2\`
font-size: \${({ theme }) => theme.fontSize.lg};
font-weight: 600;
color: \${({ theme }) => theme.colors.text.primary};
margin-bottom: \${({ theme }) => theme.spacing.sm};
\`;
`;
}
generateTailwind(spec: ComponentSpec): string {
return `
// コンポーネントで使用する Tailwind クラス:
// Container: "flex flex-col p-4 bg-white rounded-lg shadow"
// Title: "text-xl font-semibold text-gray-900 mb-2"
// Content: "flex-1 text-gray-700"
`;
}
}
6. Storybook ストーリーの生成
class StorybookGenerator {
generateStories(spec: ComponentSpec): string {
return `
import type { Meta, StoryObj } from '@storybook/react';
import { ${spec.name} } from './${spec.name}';
const meta: Meta<typeof ${spec.name}> = {
title: 'Components/${spec.name}',
component: ${spec.name},
tags: ['autodocs'],
argTypes: {
${spec.props.map(p => ` ${p.name}: { control: '${this.inferControl(p.type)}', description: '${p.description}' },`).join('\n')}
},
};
export default meta;
type Story = StoryObj<typeof ${spec.name}>;
export const Default: Story = {
args: {
${spec.props.map(p => ` ${p.name}: ${p.defaultValue || this.getMockValue(p.type)},`).join('\n')}
},
};
export const Interactive: Story = {
args: {
...Default.args,
},
};
`;
}
inferControl(type: string): string {
if (type === 'string') return 'text';
if (type === 'number') return 'number';
if (type === 'boolean') return 'boolean';
if (type.includes('[]')) return 'object';
return 'text';
}
}
出力形式
- コンポーネント ファイル: 完全に実装された React/React Native コンポーネント
- 型定義: TypeScript インターフェースと型
- スタイル: CSS モジュール、styled-components、または Tailwind 設定
- テスト: カバレッジを備えた完全なテストスイート
- ストーリー: ドキュメント用 Storybook ストーリー
- インデックス ファイル: クリーンなインポート用のバレルエクスポート
本番環境対応、アクセス可能、保守しやすく、モダン React パターンとベストプラクティスに従うコンポーネントの作成に焦点を当てます。
制限事項
- このスキルは、上記で説明したスコープと明らかに一致するタスクの場合にのみ使用してください。
- 出力を環境固有の検証、テスト、または専門家のレビューの代わりとして扱わないでください。
- 必要な入力、権限、安全性の境界、または成功基準が不明な場合は、立ち止まって明確化を求めてください。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- sickn33
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/sickn33/antigravity-awesome-skills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。