Synthèse automatique
Génère des vues SwiftUI pour macOS avec une gestion d'état explicite (@State, @Binding, @ObservedObject, @StateObject, @EnvironmentObject) à partir d'une spécification JSON décrivant la vue et ses propriétés.
Points forts
- Schéma d'entrée/sortie explicite (nom de vue, type, propriétés d'état, ViewModel optionnel) qui rend la génération prévisible
- Applique les bons wrappers de propriété et place le ViewModel sur @MainActor avec @Published
- Couvre les motifs propres à macOS : NavigationSplitView, toolbar, searchable, sheet et blocs #Preview
- Produit plusieurs fichiers identifiés par type (view, viewmodel, model) dans le résultat
Limites
- Centré sur macOS : les motifs iOS, watchOS ou tvOS ne sont pas traités
- S'appuie sur ObservableObject/Combine plutôt que sur la macro @Observable plus récente
- Suppose un projet Xcode existant et ne décrit ni compilation ni tests de validation du code généré
À utiliser pour échafauder rapidement un nouvel écran ou composant SwiftUI macOS avec son flux de données et ses previews.
À éviter pour du code iOS/iPadOS spécifique, pour une architecture AppKit, ou si vous voulez imposer la macro @Observable et le framework Observation.
Analyse de sécurité
PrudenceThe content is an ordinary SwiftUI code-generation reference: property-wrapper examples, view templates, and JSON schemas. There are no destructive commands, no curl|sh-style installs, no obfuscated payloads, and no attempt to exfiltrate credentials or tokens. Risk is limited to the declared tool set: Write/Edit against a caller-supplied project path plus an unused Bash grant, which warrant caution rather than a clean `safe` rating. No prompt-injection or instruction-override attempts were observed in the data.
- •Declares Bash in allowed-tools but no instruction in the skill actually uses it; the code-generation workflow only needs Read/Write/Edit/Glob/Grep, so the shell permission is broader than necessary.
- •Takes an arbitrary `projectPath` and writes Swift files into it (Write/Edit) with no stated guardrails (e.g., path validation, overwrite confirmation), so an agent could clobber existing sources.
- •Example code calls an undefined `DataService.shared` network/backing service; harmless as sample code, but it encourages wiring views to data services without describing where data comes from.
- •Declared allowed-tools include Bash, Write, and Edit, which allow arbitrary command execution and file modification; however, the skill content itself contains no bash commands, no network calls, and no destructive operations — tool use is limited to generating/writing Swift source files in the user's project.
Exemples
Generate a SwiftUI settings screen named PreferencesView for my macOS project at ~/Dev/MyApp, with @State properties for the selected tab, and a view model.Create a SwiftUI list view called ProjectListView in ~/Dev/MyApp using NavigationSplitView, a @StateObject view model, and a searchable field wired to the view model.Generate a reusable SwiftUI component named TagChipView for macOS in ~/Dev/MyApp, taking a @Binding for the selected tag and no view model.name: swiftui-view-generator description: Generate SwiftUI views with proper state management (@State, @Binding, @ObservedObject, @StateObject) and macOS-specific patterns allowed-tools: Read, Write, Edit, Bash, Glob, Grep tags: [swiftui, macos, swift, ui, apple]
swiftui-view-generator
Generate SwiftUI views with proper state management for macOS applications. This skill creates well-structured SwiftUI components using @State, @Binding, @ObservedObject, @StateObject, and @EnvironmentObject property wrappers.
Capabilities
- Generate SwiftUI views with proper state management
- Create reusable view components
- Set up data flow with Combine
- Implement navigation patterns
- Generate macOS-specific UI elements
- Create preference-based layouts
- Set up environment values
- Generate preview providers
Input Schema
{
"type": "object",
"properties": {
"projectPath": {
"type": "string",
"description": "Path to the Swift project"
},
"viewName": {
"type": "string",
"description": "Name of the view to generate"
},
"viewType": {
"enum": ["screen", "component", "list", "form", "settings", "sheet"],
"default": "screen"
},
"stateProperties": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"type": { "type": "string" },
"wrapper": { "enum": ["State", "Binding", "ObservedObject", "StateObject", "EnvironmentObject"] }
}
}
},
"includeViewModel": {
"type": "boolean",
"default": true
},
"macOSSpecific": {
"type": "boolean",
"default": true
}
},
"required": ["projectPath", "viewName"]
}
Output Schema
{
"type": "object",
"properties": {
"success": { "type": "boolean" },
"files": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": { "type": "string" },
"type": { "enum": ["view", "viewmodel", "model"] }
}
}
}
},
"required": ["success"]
}
Generated SwiftUI View Example
// ContentView.swift
import SwiftUI
struct ContentView: View {
@StateObject private var viewModel = ContentViewModel()
@State private var searchText = ""
@State private var isShowingSettings = false
var body: some View {
NavigationSplitView {
// Sidebar
SidebarView(selection: $viewModel.selectedCategory)
} detail: {
// Detail view
if let category = viewModel.selectedCategory {
CategoryDetailView(category: category)
} else {
Text("Select a category")
.foregroundStyle(.secondary)
}
}
.searchable(text: $searchText, prompt: "Search items...")
.onChange(of: searchText) { _, newValue in
viewModel.search(query: newValue)
}
.toolbar {
ToolbarItemGroup {
Button(action: viewModel.refresh) {
Label("Refresh", systemImage: "arrow.clockwise")
}
Button(action: { isShowingSettings = true }) {
Label("Settings", systemImage: "gear")
}
}
}
.sheet(isPresented: $isShowingSettings) {
SettingsView()
}
.task {
await viewModel.loadData()
}
}
}
// MARK: - Preview
#Preview {
ContentView()
}
#Preview("With Data") {
ContentView()
.environmentObject(PreviewData.sampleViewModel)
}
ViewModel
// ContentViewModel.swift
import SwiftUI
import Combine
@MainActor
class ContentViewModel: ObservableObject {
@Published var items: [Item] = []
@Published var selectedCategory: Category?
@Published var isLoading = false
@Published var errorMessage: String?
private let dataService: DataService
private var cancellables = Set<AnyCancellable>()
init(dataService: DataService = .shared) {
self.dataService = dataService
}
func loadData() async {
isLoading = true
errorMessage = nil
do {
items = try await dataService.fetchItems()
} catch {
errorMessage = error.localizedDescription
}
isLoading = false
}
func search(query: String) {
// Debounced search implementation
Task {
try? await Task.sleep(nanoseconds: 300_000_000)
// Perform search
}
}
func refresh() {
Task {
await loadData()
}
}
}
Reusable Component
// ItemRowView.swift
import SwiftUI
struct ItemRowView: View {
let item: Item
@Binding var isSelected: Bool
var onDelete: (() -> Void)?
var body: some View {
HStack {
Image(systemName: item.icon)
.foregroundStyle(item.color)
.frame(width: 24, height: 24)
VStack(alignment: .leading, spacing: 4) {
Text(item.title)
.font(.headline)
Text(item.subtitle)
.font(.subheadline)
.foregroundStyle(.secondary)
}
Spacer()
if isSelected {
Image(systemName: "checkmark")
.foregroundStyle(.blue)
}
}
.padding(.vertical, 4)
.contentShape(Rectangle())
.onTapGesture {
isSelected.toggle()
}
.contextMenu {
Button("Edit") { }
Button("Duplicate") { }
Divider()
Button("Delete", role: .destructive) {
onDelete?()
}
}
}
}
Settings View (macOS)
// SettingsView.swift
import SwiftUI
struct SettingsView: View {
var body: some View {
TabView {
GeneralSettingsView()
.tabItem {
Label("General", systemImage: "gear")
}
AppearanceSettingsView()
.tabItem {
Label("Appearance", systemImage: "paintpalette")
}
AdvancedSettingsView()
.tabItem {
Label("Advanced", systemImage: "slider.horizontal.3")
}
}
.frame(width: 500, height: 400)
}
}
struct GeneralSettingsView: View {
@AppStorage("launchAtLogin") private var launchAtLogin = false
@AppStorage("checkForUpdates") private var checkForUpdates = true
var body: some View {
Form {
Toggle("Launch at Login", isOn: $launchAtLogin)
Toggle("Check for Updates Automatically", isOn: $checkForUpdates)
}
.formStyle(.grouped)
.padding()
}
}
List View with Selection
// ItemListView.swift
import SwiftUI
struct ItemListView: View {
@ObservedObject var viewModel: ItemListViewModel
@State private var selection: Set<Item.ID> = []
@State private var sortOrder = [KeyPathComparator(\Item.name)]
var body: some View {
Table(viewModel.items, selection: $selection, sortOrder: $sortOrder) {
TableColumn("Name", value: \.name)
TableColumn("Type", value: \.type)
TableColumn("Modified", value: \.modifiedDate) { item in
Text(item.modifiedDate, style: .date)
}
TableColumn("Size") { item in
Text(ByteCountFormatter.string(fromByteCount: item.size, countStyle: .file))
}
.width(80)
}
.onChange(of: sortOrder) { _, newOrder in
viewModel.sort(by: newOrder)
}
.contextMenu(forSelectionType: Item.ID.self) { items in
Button("Open") { viewModel.open(items) }
Button("Delete", role: .destructive) { viewModel.delete(items) }
} primaryAction: { items in
viewModel.open(items)
}
}
}
State Management Patterns
@State - Local state
@State private var isExpanded = false
@State private var selectedTab = 0
@Binding - Two-way binding from parent
@Binding var isPresented: Bool
@Binding var selectedItem: Item?
@StateObject - Owned observable object
@StateObject private var viewModel = MyViewModel()
@ObservedObject - Passed observable object
@ObservedObject var viewModel: MyViewModel
@EnvironmentObject - Shared via environment
@EnvironmentObject var settings: AppSettings
@AppStorage - UserDefaults backed
@AppStorage("username") private var username = ""
Best Practices
- Use @StateObject for ownership: When the view creates the object
- Use @ObservedObject for injection: When the object is passed in
- Keep views small: Extract components
- Use previews: Test different states
- Mark async operations: Use @MainActor for ViewModels
- Handle errors gracefully: Show user-friendly messages
Related Skills
macos-entitlements-generator- App capabilitiesmacos-notarization-workflow- Distributionxctest-ui-test-generator- UI testing
Related Agents
swiftui-macos-expert- SwiftUI expertisedesktop-ux-analyst- UX patterns
Du fichier au premier essai
Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.
Consulter la source et ses fichiers annexesCe téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.
1. Télécharger le fichier
Télécharger SKILL.mdDepuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.
Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.
mkdir -p '.skill-downloads/swiftui-view-generator-mmlj2o7o' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/swiftui-view-generator-mmlj2o7o/download' --output '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md.part' && mv '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md.part' '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md'2. Vérifier les prérequis
Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.
Outils déclarés par l’auteur (à vérifier dans votre agent) : Read, Write, Edit, Bash, Glob, Grep
Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.
Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.
3. Charger la skill
Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.
Claude Code
test -f '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md' && test -s '.skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/swiftui-view-generator' && cp -R '.skill-downloads/swiftui-view-generator-mmlj2o7o' '.claude/skills/swiftui-view-generator'OpenSkills
OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.
Installation officielle d’OpenSkillsopenskills install './.skill-downloads/swiftui-view-generator-mmlj2o7o'openskills read 'swiftui-view-generator-mmlj2o7o'La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.
Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.
openskills syncMode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.
4. Faire un premier essai
Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :
Lis .skill-downloads/swiftui-view-generator-mmlj2o7o/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.
Bonnes pratiques React Hook Form
Developpement
Maîtrisez React Hook Form : évitez les anti-patterns, gérez les abonnements, et traitez correctement reset, dirty state et entrées contrôlées.
Migration Emotion vers Mantine
Developpement
Migrer les styled-components Emotion vers des composants Mantine avec style props et modules CSS. Pour convertir .styled.tsx ou supprimer les imports @emotion.
Détecteur de dérive de périmètre
Developpement
Analyse les diffs git par rapport à une intention pour détecter la dérive de périmètre, fichiers non liés et PR trop larges, puis suggère de garder, diviser ou justifier.