TTBaseSUIButton

Core

SwiftUI button that uses the same TTBaseUIButton.TYPE enum as its UIKit sibling. Each type applies a pre-built ButtonStyle with TTBaseUIKit colors — the same primary blue, warning red, and border styles used in 36+ production apps.


📋 Declaration

public struct TTBaseSUIButton<Content: View>: View {
    public var cornerRadius: CGFloat  // From SizeConfig.CORNER_BUTTON
    public var fontSize: CGFloat      // From FontConfig.TITLE_H
    public let type: TTBaseUIButton.TYPE
    public let action: () -> Void
    public let label: () -> Content
}

🎨 Button Style Reference

TYPEButtonStyle AppliedColorsUse Case
.DEFAULTDefaultButtonStyleViewConfig.buttonBgDef (blue)Primary actions
.WARRINGWarningButtonStyleViewConfig.buttonBgWar (red)Destructive actions
.DISABLEDisableButtonStyle50% opacityNon-interactive state
.BORDERBorderButtonStyleClear bg + border colorSecondary/outline actions
.NO_BG_COLORTransparentButtonStyleTransparentText-only link buttons
.DEFAULT_COLOR(color:textColor:)DefaultColorButtonStyleCustom bg + custom textBrand-specific styling
Shared Types: TTBaseSUIButton uses TTBaseUIButton.TYPE from UIKit, ensuring the same button types/colors are available across both frameworks. Change ViewConfig.buttonBgDef once — both UIKit and SwiftUI buttons update.

🚀 Usage

Simple Buttons

// With just title and action
TTBaseSUIButton(title: "Sign In") {
    viewModel.signIn()
}

// Warning/destructive button
TTBaseSUIButton(type: .WARRING, title: "Delete Account") {
    viewModel.deleteAccount()
}

// Outline/border button
TTBaseSUIButton(type: .BORDER, title: "Cancel") {
    dismiss()
}

All Types

VStack(spacing: 12) {
    TTBaseSUIButton(type: .DEFAULT, title: "Default (Primary)")   { }
    TTBaseSUIButton(type: .WARRING, title: "Warning (Danger)")    { }
    TTBaseSUIButton(type: .DISABLE, title: "Disabled")            { }
    TTBaseSUIButton(type: .BORDER, title: "Border (Outline)")     { }
    TTBaseSUIButton(type: .NO_BG_COLOR, title: "No Background")   { }
    TTBaseSUIButton(
        type: .DEFAULT_COLOR(color: .systemPurple, textColor: .white),
        title: "Custom Purple"
    ) { }
}

Custom Content Label

// Icon + Text inside button
TTBaseSUIButton(type: .DEFAULT, label: {
    HStack(spacing: 8) {
        Image(systemName: "paperplane.fill")
        Text("Send Message")
            .fontWeight(.semibold)
    }
    .padding(.horizontal, 24)
    .padding(.vertical, 14)
}) {
    viewModel.sendMessage()
}

// Apple Pay style button
TTBaseSUIButton(type: .DEFAULT, label: {
    HStack {
        Image(systemName: "applelogo")
        Text("Pay with Apple Pay")
            .fontWeight(.bold)
    }
    .frame(maxWidth: .infinity)
    .padding(.vertical, 16)
}) {
    viewModel.processApplePay()
}

Loading State with @State

struct LoginView: View {
    @State private var isLoading = false

    var body: some View {
        if isLoading {
            TTBaseSUIButton(type: .DISABLE, title: "Signing in...") { }
        } else {
            TTBaseSUIButton(type: .DEFAULT, title: "Sign In") {
                self.isLoading = true
                Task {
                    await viewModel.signIn()
                    self.isLoading = false
                }
            }
        }
    }
}

Real-world: Flight Booking CTAs

// Bottom action buttons in 12Bay booking flow
VStack(spacing: 12) {
    TTBaseSUIButton(type: .DEFAULT, title: "Continue to Payment") {
        viewModel.proceedToPayment()
    }
    TTBaseSUIButton(type: .BORDER, title: "Modify Search") {
        viewModel.modifySearch()
    }
}

🔧 Initializers

InitializerDescription
init(type:label:action:)Full control: type + custom SwiftUI label view + action
init(type:title:action:)Standard: type + title string + action
init(type:title:)Type + title, no action (for preview/static use)
init(title:action:)Default type (.DEFAULT) + title + action
init(label:action:)Default type + custom label content + action
Pro Tip: All button types support frame(maxWidth: .infinity) for full-width buttons. By default buttons size to their content. Use .padding() on the label content to control internal spacing.