203 lines
5.2 KiB
Swift
203 lines
5.2 KiB
Swift
import SwiftUI
|
|
|
|
@MainActor
|
|
public protocol TextLabelStyle {
|
|
|
|
associatedtype Body: View
|
|
typealias Configuration = TextLabelConfiguration
|
|
|
|
func makeBody(configuration: Self.Configuration) -> Self.Body
|
|
}
|
|
|
|
extension TextLabelStyle {
|
|
public func combining<Other: TextLabelStyle>(_ style: Other) -> AnyTextLabelStyle {
|
|
AnyTextLabelStyle(style: self).combining(style)
|
|
}
|
|
}
|
|
|
|
public struct TextLabelConfiguration {
|
|
|
|
/// A type erased label for a text label.
|
|
public struct Label: View {
|
|
public var body: AnyView
|
|
|
|
public init<Content: View>(content: Content) {
|
|
body = AnyView(content)
|
|
}
|
|
}
|
|
|
|
public let label: TextLabelConfiguration.Label
|
|
}
|
|
|
|
@MainActor
|
|
public struct AnyTextLabelStyle: TextLabelStyle {
|
|
private var _makeBody: (Configuration) -> AnyView
|
|
|
|
internal init(makeBody: @escaping (Configuration) -> AnyView) {
|
|
self._makeBody = makeBody
|
|
}
|
|
|
|
public init<S: TextLabelStyle>(style: S) {
|
|
self._makeBody = { configuration in
|
|
AnyView(style.makeBody(configuration: configuration))
|
|
}
|
|
}
|
|
|
|
public func makeBody(configuration: Configuration) -> some View {
|
|
_makeBody(configuration)
|
|
}
|
|
|
|
public func combining<S: TextLabelStyle>(_ style: S) -> Self {
|
|
Self.init { configuration in
|
|
AnyView(
|
|
self.makeBody(
|
|
configuration: TextLabelConfiguration(
|
|
label: .init(content: style.makeBody(configuration: configuration))
|
|
)
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
public struct AutomaticTextLabelStyle: TextLabelStyle {
|
|
public func makeBody(configuration: Configuration) -> some View {
|
|
configuration.label
|
|
}
|
|
}
|
|
|
|
private struct TextLabelStyleKey: EnvironmentKey {
|
|
static let defaultValue = AnyTextLabelStyle(style: AutomaticTextLabelStyle())
|
|
}
|
|
|
|
private struct SectionHeaderLabelStyleKey: EnvironmentKey {
|
|
static let defaultValue = AnyTextLabelStyle(style: AutomaticTextLabelStyle())
|
|
}
|
|
|
|
extension EnvironmentValues {
|
|
public var textLabelStyle: AnyTextLabelStyle {
|
|
get { self[TextLabelStyleKey.self] }
|
|
set { self[TextLabelStyleKey.self] = newValue }
|
|
}
|
|
|
|
public var sectionHeaderLabelStyle: AnyTextLabelStyle {
|
|
get { self[SectionHeaderLabelStyleKey.self] }
|
|
set { self[SectionHeaderLabelStyleKey.self] = newValue }
|
|
}
|
|
}
|
|
|
|
public struct FontTextLabelStyle: TextLabelStyle {
|
|
let font: Font?
|
|
let fontWeight: Font.Weight?
|
|
|
|
public func makeBody(configuration: Configuration) -> some View {
|
|
configuration.label
|
|
.font(font)
|
|
.fontWeight(fontWeight)
|
|
}
|
|
}
|
|
|
|
public struct ColoredTextLabelStyle: TextLabelStyle {
|
|
|
|
let primary: Color
|
|
let secondary: Color?
|
|
let tertiary: Color?
|
|
|
|
@ViewBuilder
|
|
public func makeBody(configuration: Configuration) -> some View {
|
|
switch (secondary, tertiary) {
|
|
case let (.some(secondary), .some(tertiary)):
|
|
configuration.label.foregroundStyle(primary, secondary, tertiary)
|
|
case let (.some(secondary), .none):
|
|
configuration.label.foregroundStyle(primary, secondary)
|
|
case let (.none, .some(tertiary)):
|
|
configuration.label.foregroundStyle(primary, tertiary)
|
|
case (.none, .none):
|
|
configuration.label.foregroundStyle(primary)
|
|
}
|
|
}
|
|
|
|
public func font(_ font: Font? = nil, fontWeight: Font.Weight? = nil) -> AnyTextLabelStyle {
|
|
self.combining(.font(font, fontWeight: fontWeight))
|
|
}
|
|
}
|
|
|
|
extension TextLabelStyle where Self == AutomaticTextLabelStyle {
|
|
public static var automatic: Self {
|
|
.init()
|
|
}
|
|
}
|
|
|
|
extension TextLabelStyle where Self == FontTextLabelStyle {
|
|
public static func font(_ font: Font? = nil, fontWeight: Font.Weight? = nil) -> Self {
|
|
.init(font: font, fontWeight: fontWeight)
|
|
}
|
|
|
|
public static var heavyTitle2: Self {
|
|
.font(.title2, fontWeight: .heavy)
|
|
}
|
|
}
|
|
|
|
extension TextLabelStyle where Self == ColoredTextLabelStyle {
|
|
|
|
public static func colored(_ color: Color) -> Self {
|
|
.init(primary: color, secondary: nil, tertiary: nil)
|
|
}
|
|
|
|
public static func colored(_ primary: Color, _ secondary: Color, _ tertiary: Color? = nil) -> Self {
|
|
.init(primary: primary, secondary: secondary, tertiary: tertiary)
|
|
}
|
|
|
|
public static var secondary: Self {
|
|
self.colored(.secondary)
|
|
}
|
|
}
|
|
|
|
extension AnyTextLabelStyle {
|
|
|
|
public static var boldSecondary: AnyTextLabelStyle {
|
|
ColoredTextLabelStyle(primary: .secondary, secondary: nil, tertiary: nil)
|
|
.combining(.font(fontWeight: .bold))
|
|
}
|
|
|
|
}
|
|
|
|
public struct PillViewTextLabelStyle: TextLabelStyle {
|
|
|
|
let labelColor: Color?
|
|
let pillColor: Color
|
|
|
|
public func makeBody(configuration: Configuration) -> some View {
|
|
configuration.label
|
|
.foregroundStyle(labelColor ?? .primary)
|
|
.background {
|
|
Capsule()
|
|
.foregroundStyle(pillColor)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension TextLabelStyle where Self == PillViewTextLabelStyle {
|
|
public static func pill(
|
|
pillColor: Color,
|
|
labelColor: Color? = nil
|
|
) -> Self {
|
|
.init(labelColor: labelColor, pillColor: pillColor)
|
|
}
|
|
}
|
|
|
|
extension View {
|
|
|
|
public func textLabelStyle(_ style: AnyTextLabelStyle) -> some View {
|
|
environment(\.textLabelStyle, style)
|
|
}
|
|
|
|
public func textLabelStyle<S: TextLabelStyle>(_ style: S) -> some View {
|
|
textLabelStyle(AnyTextLabelStyle(style: style))
|
|
}
|
|
|
|
public func sectionHeaderLabelStyle<S: TextLabelStyle>(_ style: S) -> some View {
|
|
environment(\.sectionHeaderLabelStyle, AnyTextLabelStyle(style: style))
|
|
}
|
|
}
|