Files

189 lines
5.7 KiB
Swift

import SwiftUI
#warning("Remove button types and just make styles stand-alone")
/// A name space for edit button styles.
public enum EditButtonType { }
/// 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 primitive button style, used to style buttons in a namespace.
@MainActor
public struct AnyPrimitiveButtonStyle<ButtonType>: PrimitiveButtonStyle {
private let _makeBody: (Configuration) -> AnyView
public init<S: PrimitiveButtonStyle>(_ 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.
@MainActor
public struct DefaultInfoButtonStyle<Style: LabelStyle>: PrimitiveButtonStyle {
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 {
Button(role: configuration.role, action: configuration.trigger) {
configuration.label
.font(font)
.foregroundStyle(color)
.labelStyle(labelStyle)
}
.buttonStyle(.plain)
}
}
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 == NextLabelStyle {
init() {
self.init(buttonStyle: .borderedProminent, labelStyle: .nextLabel())
}
}
public struct ToolbarNextButtonStyle: PrimitiveButtonStyle {
public func makeBody(configuration: Configuration) -> some View {
Button(role: configuration.role, action: configuration.trigger) {
configuration.label
.foregroundStyle(Color.accentColor)
}
.labelStyle(NextLabelStyle())
.buttonStyle(.plain)
}
}
extension AnyPrimitiveButtonStyle<NextButtonType> {
public static var toolbar: Self { .init(ToolbarNextButtonStyle()) }
}
private struct InfoButtonStyleKey: @preconcurrency EnvironmentKey {
@MainActor
static var defaultValue: AnyPrimitiveButtonStyle<InfoButtonType> {
AnyPrimitiveButtonStyle<InfoButtonType>(DefaultInfoButtonStyle(labelStyle: .iconOnly))
}
}
private struct NextButtonStyleKey: EnvironmentKey {
static var defaultValue: AnyPrimitiveButtonStyle<NextButtonType> {
MainActor.assumeIsolated {
AnyPrimitiveButtonStyle<NextButtonType>(
DefaultNextButtonStyle<BorderedProminentButtonStyle, NextLabelStyle>()
)
}
}
}
private struct ResetButtonStyleKey: EnvironmentKey {
static let defaultValue = MainActor.assumeIsolated {
AnyPrimitiveButtonStyle<ResetButtonType>(.borderedProminent)
}
}
extension EnvironmentValues {
// @Entry var infoButtonStyle: AnyButtonStyle<InfoButtonType> = AnyButtonStyle.default
@Entry var editButtonStyle = MainActor.assumeIsolated {
AnyPrimitiveButtonStyle<EditButtonType>(DefaultInfoButtonStyle(labelStyle: .automatic))
}
var infoButtonStyle: AnyPrimitiveButtonStyle<InfoButtonType> {
get { self[InfoButtonStyleKey.self] }
set { self[InfoButtonStyleKey.self] = newValue }
}
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 }
}
}
extension View {
/// Sets the button style for the ``EditButton`` type.
public func editButtonStyle(_ style: AnyPrimitiveButtonStyle<EditButtonType>) -> some View {
environment(\.editButtonStyle, style)
}
/// Sets the button style for the ``EditButton`` type.
public func editButtonStyle<S: PrimitiveButtonStyle>(_ style: S) -> some View {
editButtonStyle(AnyPrimitiveButtonStyle(style))
}
/// Sets the button style for the ``InfoButton`` type.
public func infoButtonStyle(_ style: AnyPrimitiveButtonStyle<InfoButtonType>) -> some View {
environment(\.infoButtonStyle, style)
}
/// Sets the button style for the ``InfoButton`` type.
public func infoButtonStyle<S: PrimitiveButtonStyle>(_ style: S) -> some View {
infoButtonStyle(AnyPrimitiveButtonStyle(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))
}
}