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: ButtonStyle { private let _makeBody: (Configuration) -> AnyView public init(_ style: S) { self._makeBody = { configuration in AnyView(style.makeBody(configuration: configuration)) } } public func makeBody(configuration: Configuration) -> some View { self._makeBody(configuration) } } /// A type erased primitive button style, used to style buttons in a namespace. public struct AnyPrimitiveButtonStyle: PrimitiveButtonStyle { private let _makeBody: (Configuration) -> AnyView public init(_ style: S) { self._makeBody = { configuration in AnyView(style.makeBody(configuration: configuration)) } } public func makeBody(configuration: Configuration) -> some View { self._makeBody(configuration) } } /// The default info button style. public struct DefaultInfoButtonStyle: 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(font) .foregroundStyle(color.opacity(configuration.isPressed ? 0.5 : 1)) .labelStyle(labelStyle) .scaleEffect(configuration.isPressed ? 0.8 : 1) } } public struct DefaultNextButtonStyle: 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(labelStyle: .iconOnly)) } public static func `default`(color: Color, font: Font, labelStyle: S) -> Self { .init(DefaultInfoButtonStyle(color: color, font: font, labelStyle: labelStyle)) } } private struct InfoButtonStyleKey: EnvironmentKey { static var defaultValue = AnyButtonStyle.default } private struct NextButtonStyleKey: EnvironmentKey { static var defaultValue = AnyPrimitiveButtonStyle( DefaultNextButtonStyle() ) } private struct ResetButtonStyleKey: EnvironmentKey { static var defaultValue = AnyPrimitiveButtonStyle(.borderedProminent) } extension EnvironmentValues { var infoButtonStyle: AnyButtonStyle { get { self[InfoButtonStyleKey.self] } set { self[InfoButtonStyleKey.self] = newValue } } var nextButtonStyle: AnyPrimitiveButtonStyle { get { self[NextButtonStyleKey.self] } set { self[NextButtonStyleKey.self] = newValue } } var resetButtonStyle: AnyPrimitiveButtonStyle { get { self[ResetButtonStyleKey.self] } set { self[ResetButtonStyleKey.self] = newValue } } } extension View { /// Sets the button style for the ``InfoButton`` type. public func infoButtonStyle(_ style: AnyButtonStyle) -> some View { environment(\.infoButtonStyle, style) } /// Sets the button style for the ``InfoButton`` type. public func infoButtonStyle(_ style: S) -> some View { infoButtonStyle(AnyButtonStyle(style)) } /// Sets the button style for the ``NextButton`` type. public func nextButtonStyle(_ style: AnyPrimitiveButtonStyle) -> some View { environment(\.nextButtonStyle, style) } /// Sets the button style for the ``NextButton`` type. public func nextButtonStyle(_ style: S) -> some View { nextButtonStyle(AnyPrimitiveButtonStyle(style)) } /// Sets the button style for the ``ResetButton`` type. public func resetButtonStyle(_ style: AnyPrimitiveButtonStyle) -> some View { environment(\.resetButtonStyle, style) } /// Sets the button style for the ``ResetButton`` type. public func resetButtonStyle(_ style: S) -> some View { resetButtonStyle(AnyPrimitiveButtonStyle(style)) } }