TTBaseSUIButton
CoreSwiftUI 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
| TYPE | ButtonStyle Applied | Colors | Use Case |
|---|---|---|---|
.DEFAULT | DefaultButtonStyle | ViewConfig.buttonBgDef (blue) | Primary actions |
.WARRING | WarningButtonStyle | ViewConfig.buttonBgWar (red) | Destructive actions |
.DISABLE | DisableButtonStyle | 50% opacity | Non-interactive state |
.BORDER | BorderButtonStyle | Clear bg + border color | Secondary/outline actions |
.NO_BG_COLOR | TransparentButtonStyle | Transparent | Text-only link buttons |
.DEFAULT_COLOR(color:textColor:) | DefaultColorButtonStyle | Custom bg + custom text | Brand-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
| Initializer | Description |
|---|---|
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.