Agent skill
swiftui-view-generator
Generate SwiftUI views with proper state management (@State, @Binding, @ObservedObject, @StateObject) and macOS-specific patterns
Install this agent skill to your Project
npx add-skill https://github.com/a5c-ai/babysitter/tree/main/library/specializations/desktop-development/skills/swiftui-view-generator
SKILL.md
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
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
gsd-tools
Central utility skill for GSD operations. Provides config parsing, slug generation, timestamps, path operations, and orchestrates calls to other specialized skills. Acts as the unified entry point that the original gsd-tools.cjs provided via its lib/ modules (commands, config, core, init).
model-profile-resolution
Resolve model profile (quality/balanced/budget) at orchestration start and map agents to specific models. Enables cost/quality tradeoffs by selecting appropriate AI models for each agent role.
verification-suite
Plan structure validation, phase completeness checks, reference integrity verification, and artifact existence confirmation. Provides the structured verification layer ensuring GSD artifacts are well-formed and complete.
state-management
STATE.md reading, writing, and field-level updates. Provides cross-session state persistence via .planning/STATE.md with structured fields for current task, completed phases, blockers, decisions, and quick tasks.
git-integration
Git commit patterns, formats, and conventions for GSD methodology. Provides atomic commits per task, structured commit messages, planning file commits, branch management, and milestone tag operations.
frontmatter-parsing
YAML frontmatter parsing and manipulation for .planning/ documents. Provides read, write, update, query, and validation operations on frontmatter blocks in GSD markdown artifacts.
Didn't find tool you were looking for?