MyCuppa

iOS Quick Start

This guide will help you build your first iOS application with Cuppa and SwiftUI.

Creating Your First View

Create a new SwiftUI view in ios/App/Views/HomeView.swift:

import SwiftUI
import CuppaUI

struct HomeView: View {
    @StateObject private var viewModel = HomeViewModel()

    var body: some View {
        VStack(spacing: 20) {
            Text("Welcome to Cuppa!")
                .font(.largeTitle)
                .bold()

            CuppaButton(
                title: "Get Started",
                style: .primary,
                action: {
                    viewModel.handleGetStarted()
                }
            )

            if viewModel.isLoading {
                ProgressView()
            }
        }
        .padding()
    }
}

Creating a ViewModel

Create the corresponding ViewModel using shared Cuppa logic:

import Foundation
import Combine
import CuppaCore

class HomeViewModel: ObservableObject {
    @Published var isLoading = false
    @Published var items: [Item] = []

    func handleGetStarted() {
        isLoading = true

        Task {
            do {
                // Use shared Cuppa data fetching
                let data = try await CuppaData.fetch("api/items")
                await MainActor.run {
                    self.items = data
                    self.isLoading = false
                }
            } catch {
                print("Error: \\(error)")
                await MainActor.run {
                    self.isLoading = false
                }
            }
        }
    }
}

Adding Navigation

Set up navigation in ContentView.swift:

import SwiftUI
import CuppaRouter

struct ContentView: View {
    var body: some View {
        CuppaNavigationStack {
            HomeView()
                .cuppaRoute("/")

            ProfileView()
                .cuppaRoute("/profile")

            SettingsView()
                .cuppaRoute("/settings")
        }
    }
}

Using Cuppa Components

Cuppa provides pre-built SwiftUI components:

Buttons

// Primary button
CuppaButton(title: "Submit", style: .primary) {
    handleSubmit()
}

// Secondary button
CuppaButton(title: "Cancel", style: .secondary) {
    handleCancel()
}

// Outlined button
CuppaButton(title: "Learn More", style: .outlined) {
    openDocs()
}

Form Inputs

struct LoginView: View {
    @State private var email = ""
    @State private var password = ""

    var body: some View {
        VStack(spacing: 16) {
            CuppaTextField(
                text: $email,
                placeholder: "Email",
                keyboardType: .emailAddress
            )

            CuppaSecureField(
                text: $password,
                placeholder: "Password"
            )

            CuppaButton(title: "Sign In", style: .primary) {
                handleSignIn()
            }
        }
        .padding()
    }
}

Lists

struct ItemListView: View {
    let items: [Item]

    var body: some View {
        CuppaList(items) { item in
            HStack {
                Text(item.title)
                    .font(.headline)
                Spacer()
                Image(systemName: "chevron.right")
                    .foregroundColor(.gray)
            }
        }
    }
}

Integrating with Shared Code

Use your shared TypeScript/JavaScript business logic from iOS:

import CuppaBridge

class DataManager {
    static func fetchUserData() async throws -> User {
        // Call shared TypeScript function
        let result = try await CuppaBridge.call(
            function: "getUserData",
            args: []
        )
        return try JSONDecoder().decode(User.self, from: result)
    }
}

Adding Plugins

Integrate Cuppa plugins for common functionality:

Authentication Plugin

import CuppaAuth

// Sign in with email
await CuppaAuth.signIn(
    email: email,
    password: password
)

// Sign out
await CuppaAuth.signOut()

// Get current user
let user = CuppaAuth.currentUser

Data Plugin

import CuppaData

// Query data
let items = try await CuppaData.query("items", filters: [
    "category": "featured"
])

// Mutate data
try await CuppaData.mutate("items/create", data: newItem)

Running Your App

Build and run your app:

# Run on iOS simulator
pnpm ios

# Run on specific device
pnpm ios --device="iPhone 15 Pro"

Next Steps