feat: Adds more buttons and reverse label style

This commit is contained in:
2024-06-04 19:38:40 -04:00
parent dd8f360417
commit a65ac76dde
5 changed files with 130 additions and 16 deletions

View File

@@ -221,9 +221,7 @@ public struct EstimateSettingsFormView: View {
HStack {
ResetButton { send(.resetButtonTapped) }
Spacer()
Button("Next") {
send(.nextButtonTapped)
}
NextButton { send(.nextButtonTapped) }
.disabled(!store.isValid)
}
.padding(.top)

View File

@@ -1,5 +1,20 @@
import SwiftUI
public struct DoneButton: View {
let action: () -> Void
public init(action: @escaping () -> Void) {
self.action = action
}
public var body: some View {
Button(action: action) {
Text("Done")
}
}
}
public struct InfoButton: View {
@Environment(\.infoButtonStyle) private var infoButtonStyle
@@ -18,6 +33,26 @@ public struct InfoButton: View {
}
}
public struct NextButton: View {
@Environment(\.nextButtonStyle) private var nextButtonStyle
let action: () -> Void
public init(action: @escaping () -> Void) {
self.action = action
}
public var body: some View {
Button {
action()
} label: {
Label("Next", systemImage: "chevron.right")
}
.buttonStyle(nextButtonStyle)
}
}
public struct ResetButton: View {
@Environment(\.resetButtonStyle) private var resetButtonStyle
@@ -48,6 +83,9 @@ struct ButtonPreview: View {
InfoButton {
lastButtonPressed = "Info button pressed."
}
NextButton {
lastButtonPressed = "Next button pressed."
}
ResetButton {
lastButtonPressed = "Reset button pressed."
}

View File

@@ -54,9 +54,7 @@ public struct InfoView: View {
.padding(.horizontal)
.navigationBarBackButtonHidden()
.toolbar {
Button("Done") {
store.send(.dismissButtonTapped)
}
DoneButton { store.send(.dismissButtonTapped) }
}
}
}

View File

@@ -3,9 +3,13 @@ import SwiftUI
/// A name space for info button styles.
public enum InfoButtonType { }
/// A name space for info button styles.
public enum NextButtonType { }
/// A name space for info button styles.
public enum ResetButtonType { }
/// A type erased button style, used to style buttons in a namespace.
public struct AnyButtonStyle<ButtonType>: ButtonStyle {
private let _makeBody: (Configuration) -> AnyView
@@ -20,6 +24,7 @@ public struct AnyButtonStyle<ButtonType>: ButtonStyle {
}
}
/// A type erased primitive button style, used to style buttons in a namespace.
public struct AnyPrimitiveButtonStyle<ButtonType>: PrimitiveButtonStyle {
private let _makeBody: (Configuration) -> AnyView
@@ -34,36 +39,62 @@ public struct AnyPrimitiveButtonStyle<ButtonType>: PrimitiveButtonStyle {
}
}
/// The default info button style.
public struct DefaultInfoButtonStyle<Style: LabelStyle>: ButtonStyle {
let color: Color
let font: Font
let labelStyle: Style
init(
color: Color = .accentColor,
font: Font = .title2,
labelStyle: Style
) {
self.color = color
self.font = font
self.labelStyle = labelStyle
}
public func makeBody(configuration: Configuration) -> some View {
configuration.label
.font(.title2)
.font(font)
.foregroundStyle(color.opacity(configuration.isPressed ? 0.5 : 1))
.labelStyle(labelStyle)
.scaleEffect(configuration.isPressed ? 0.8 : 1)
}
}
public struct DefaultNextButtonStyle<ButtonStyle: PrimitiveButtonStyle, Label: LabelStyle>: PrimitiveButtonStyle {
let buttonStyle: ButtonStyle
let labelStyle: Label
public init(buttonStyle: ButtonStyle, labelStyle: Label) {
self.buttonStyle = buttonStyle
self.labelStyle = labelStyle
}
public func makeBody(configuration: Configuration) -> some View {
Button(role: configuration.role, action: configuration.trigger) {
configuration.label
}
.labelStyle(labelStyle)
.buttonStyle(buttonStyle)
}
}
extension DefaultNextButtonStyle where ButtonStyle == BorderedProminentButtonStyle, Label == ReverseLabelStyle {
init() {
self.init(buttonStyle: .borderedProminent, labelStyle: .reverse())
}
}
extension AnyButtonStyle where ButtonType == InfoButtonType {
public static var `default`: Self {
.init(DefaultInfoButtonStyle<IconOnlyLabelStyle>(labelStyle: .iconOnly))
}
public static func `default`<S: LabelStyle>(color: Color, labelStyle: S) -> Self {
.init(DefaultInfoButtonStyle<S>(color: color, labelStyle: labelStyle))
public static func `default`<S: LabelStyle>(color: Color, font: Font, labelStyle: S) -> Self {
.init(DefaultInfoButtonStyle<S>(color: color, font: font, labelStyle: labelStyle))
}
}
@@ -71,17 +102,28 @@ private struct InfoButtonStyleKey: EnvironmentKey {
static var defaultValue = AnyButtonStyle<InfoButtonType>.default
}
private struct NextButtonStyleKey: EnvironmentKey {
static var defaultValue = AnyPrimitiveButtonStyle<NextButtonType>(
DefaultNextButtonStyle<BorderedProminentButtonStyle, ReverseLabelStyle>()
)
}
private struct ResetButtonStyleKey: EnvironmentKey {
static var defaultValue = AnyPrimitiveButtonStyle<ResetButtonType>(BorderedProminentButtonStyle())
static var defaultValue = AnyPrimitiveButtonStyle<ResetButtonType>(.borderedProminent)
}
extension EnvironmentValues {
public var infoButtonStyle: AnyButtonStyle<InfoButtonType> {
var infoButtonStyle: AnyButtonStyle<InfoButtonType> {
get { self[InfoButtonStyleKey.self] }
set { self[InfoButtonStyleKey.self] = newValue }
}
public var resetButtonStyle: AnyPrimitiveButtonStyle<ResetButtonType> {
var nextButtonStyle: AnyPrimitiveButtonStyle<NextButtonType> {
get { self[NextButtonStyleKey.self] }
set { self[NextButtonStyleKey.self] = newValue }
}
var resetButtonStyle: AnyPrimitiveButtonStyle<ResetButtonType> {
get { self[ResetButtonStyleKey.self] }
set { self[ResetButtonStyleKey.self] = newValue }
}
@@ -89,18 +131,32 @@ extension EnvironmentValues {
extension View {
/// Sets the button style for the ``InfoButton`` type.
public func infoButtonStyle(_ style: AnyButtonStyle<InfoButtonType>) -> some View {
environment(\.infoButtonStyle, style)
}
/// Sets the button style for the ``InfoButton`` type.
public func infoButtonStyle<S: ButtonStyle>(_ style: S) -> some View {
infoButtonStyle(AnyButtonStyle(style))
}
/// Sets the button style for the ``NextButton`` type.
public func nextButtonStyle(_ style: AnyPrimitiveButtonStyle<NextButtonType>) -> some View {
environment(\.nextButtonStyle, style)
}
/// Sets the button style for the ``NextButton`` type.
public func nextButtonStyle<S: PrimitiveButtonStyle>(_ style: S) -> some View {
nextButtonStyle(AnyPrimitiveButtonStyle(style))
}
/// Sets the button style for the ``ResetButton`` type.
public func resetButtonStyle(_ style: AnyPrimitiveButtonStyle<ResetButtonType>) -> some View {
environment(\.resetButtonStyle, style)
}
/// Sets the button style for the ``ResetButton`` type.
public func resetButtonStyle<S: PrimitiveButtonStyle>(_ style: S) -> some View {
resetButtonStyle(AnyPrimitiveButtonStyle(style))
}

View File

@@ -0,0 +1,24 @@
import SwiftUI
/// A label style that puts the title first and icon second.
public struct ReverseLabelStyle: LabelStyle {
let spacing: CGFloat
public init(spacing: CGFloat = 3) {
self.spacing = spacing
}
public func makeBody(configuration: Configuration) -> some View {
HStack(spacing: spacing) {
configuration.title
configuration.icon
}
}
}
extension LabelStyle where Self == ReverseLabelStyle {
public static func reverse(spacing: CGFloat = 3) -> Self {
.init(spacing: spacing)
}
}