| name | component-gen |
| description | デザインシステム準拠のSwiftUIコンポーネントを生成する。新しいUIパーツの作成、コンポーネント生成時に使用。「コンポーネント作成」「新しいUI」「パーツ作成」「component generate」「UIパーツ」「新規コンポーネント」などのキーワードで自動適用。 |
コンポーネント生成スキル
Swift Design System に準拠した新規 SwiftUI コンポーネントを生成するためのガイド。
生成前チェックリスト
コンポーネントを生成する前に、以下を確認すること:
- 目的の明確化: このコンポーネントは何を解決するか?
- 既存コンポーネントの確認: 既に同等のものがないか確認
- Button (Primary/Secondary/Tertiary), Card, Chip, FloatingActionButton
- IconBadge, IconButton, ProgressBar, Snackbar, StatDisplay
- TextField (DSTextField), VideoPlayer
- Layout: AspectGrid, SectionCard
- Pickers: ColorPicker, EmojiPicker, IconPicker, ImagePicker
- 必要なトークンの特定: どのトークンを使用するか
- ColorPalette, SpacingScale, RadiusScale, Motion, Elevation, Typography
コード生成テンプレート
基本構造
import SwiftUI
import DesignSystem
public struct MyComponent<Content: View>: View {
@Environment(\.colorPalette) private var colors
@Environment(\.spacingScale) private var spacing
@Environment(\.radiusScale) private var radius
@Environment(\.motion) private var motion
private let title: String
private let content: Content
public init(
title: String,
@ViewBuilder content: () -> Content
) {
self.title = title
self.content = content()
}
public var body: some View {
VStack(alignment: .leading, spacing: spacing.md) {
Text(title)
.typography(.titleMedium)
.foregroundStyle(colors.onSurface)
content
}
.padding(spacing.lg)
.background(colors.surface)
.clipShape(RoundedRectangle(cornerRadius: radius.lg))
.elevation(.level1)
.accessibilityElement(children: .contain)
.accessibilityLabel(title)
}
}
重要な実装パターン
Environment アクセス
@Environment(\.colorPalette) private var colors
@Environment(\.spacingScale) private var spacing
@Environment(\.radiusScale) private var radius
@Environment(\.motion) private var motion
ThemeProvider ラッピング(Preview で必須)
#Preview {
MyComponent(title: "サンプル") {
Text("コンテンツ")
}
.padding()
.theme(ThemeProvider())
}
ViewModifier パターン
Text("見出し").typography(.headlineLarge)
Card { content }.elevation(.level2)
.animate(motion.tap, value: isPressed)
アクセシビリティ
.accessibilityLabel("説明テキスト")
.frame(minWidth: 44, minHeight: 44)
.accessibilityElement(children: .contain)
.accessibilityAddTraits(.isButton)
SF Symbols(アイコン)
Image(systemName: "star.fill")
.foregroundStyle(colors.primary)
IconBadge(systemName: "bell.fill", size: .medium)
必須 Preview 状態
最低5つの Preview を用意すること:
#Preview("Default") {
MyComponent(title: "デフォルト") {
Text("通常表示")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider())
}
#Preview("Dark Mode") {
MyComponent(title: "ダークモード") {
Text("ダーク表示")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider(initialMode: .dark))
}
#Preview("Large Text") {
MyComponent(title: "大きなテキスト") {
Text("Dynamic Type 対応確認")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider())
.environment(\.sizeCategory, .accessibilityExtraLarge)
}
#Preview("Compact") {
MyComponent(title: "短") {
Text("OK")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider())
}
#Preview("Edge Case") {
MyComponent(title: "非常に長いタイトルが入った場合の表示確認テスト") {
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
.typography(.bodyMedium)
}
.padding()
.theme(ThemeProvider())
}
Good / Bad パターン
カラー
.foregroundStyle(colors.onSurface)
.background(colors.surface)
.foregroundColor(.black)
.background(Color.white)
スペーシング
VStack(spacing: spacing.md) { ... }
.padding(spacing.lg)
VStack(spacing: 12) { ... }
.padding(16)
角丸
.clipShape(RoundedRectangle(cornerRadius: radius.lg))
.clipShape(RoundedRectangle(cornerRadius: 12))
アニメーション
.animate(motion.tap, value: isPressed)
.animation(.easeOut(duration: 0.1), value: isPressed)
コンポーネント活用
Card(elevation: .level2) { content }
Button("保存") { save() }.buttonStyle(.primary)
RoundedRectangle(cornerRadius: 8).fill(Color.white).shadow(radius: 4)
Typography
Text("見出し").typography(.headlineLarge)
Text("見出し").font(.system(size: 32, weight: .semibold))
生成後チェックリスト
関連スキル
- design-system-workflow: トークン・コンポーネントの詳細リファレンス
- design-audit: 生成後の準拠性チェック
- design-diff: 視覚的な確認
- ios-clean-architecture: アーキテクチャ上の配置
- ios-build-workflow: ビルド・テスト実行