Skip to content

Instantly share code, notes, and snippets.

@ahtcx
Created August 29, 2024 22:10
Show Gist options
  • Save ahtcx/ffe76cd40b6c1e817d90222c2be64578 to your computer and use it in GitHub Desktop.
Save ahtcx/ffe76cd40b6c1e817d90222c2be64578 to your computer and use it in GitHub Desktop.
A button style designed to highlight key actions with a pill-shaped appearance
import SwiftUI
/// A button style designed to highlight key actions with a pill-shaped appearance
///
/// To apply this style to a button, use the `buttonStyle(_:)` modifier.
/// For example:
/// ```swift
/// Button("Action") {
/// // Button action
/// }
/// .buttonStyle(.pill) // Applies the pill button style
/// ```
public struct PillButtonStyle: PrimitiveButtonStyle {
/// Creates a pill button style.
public init() {}
/// Creates a view that represents the body of a button.
///
/// The system calls this method for each ``Button`` instance in a view
/// hierarchy where this style is the current button style.
///
/// - Parameter configuration: The properties of the button.
/// - Returns: A view that represents the body of the button.
public func makeBody(configuration: Configuration) -> some View {
Button(role: configuration.role, action: configuration.trigger) {
configuration.label
.labeledContentStyle(.compact)
.lineLimit(1)
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.overlay { Capsule().stroke(.tint).opacity(0.5) }
.applyTintIfDestructive(configuration.role)
}
}
private extension View {
/// Applies a red tint to the button if its role is `.destructive`.
///
/// - Parameter role: The role of the button which determines if the
/// tint should be applied.
/// - Returns: A view that either has a red tint applied or remains unchanged.
@ViewBuilder
func applyTintIfDestructive(_ role: ButtonRole?) -> some View {
if role == .destructive {
tint(.red)
} else {
self
}
}
}
public extension PrimitiveButtonStyle where Self == PillButtonStyle {
/// A pill button style that applies a pill-shaped border around the button
/// and conditionally tints it based on the button's role.
///
/// You can also use `PillButtonStyle()` to construct this style.
static var pill: PillButtonStyle {
PillButtonStyle()
}
}
#Preview(traits: .sizeThatFitsLayout) {
Group {
Button("Extra Large") {}
.buttonStyle(.pill)
.controlSize(.extraLarge)
Button("Default") {}
.buttonStyle(.pill)
Button("Mini") {}
.buttonStyle(.pill)
.controlSize(.mini)
Button("Accent") {}
.buttonStyle(.pill)
.tint(.accentColor)
Button("Green") {}
.buttonStyle(.pill)
.tint(.green)
Button("Orange") {}
.buttonStyle(.pill)
.tint(.orange)
Button("Delete", role: .destructive) {}
.buttonStyle(.pill)
Button("Disabled") {}
.buttonStyle(.pill)
.disabled(true)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment