Created
June 8, 2023 17:59
-
-
Save ValentinWalter/fe36ba6c2b865764b73a59a528eba39b to your computer and use it in GitHub Desktop.
Build Text instances in a declarative manner, similar to regular views, from Text and Image. This ensures the font’s kerning, ligatures, and other properties are preserved across the entire text.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TextBuilder.swift | |
// | |
// | |
// Created by Valentin Walter on 14.02.23. | |
// | |
import SwiftUI | |
/// Build Text instances in a declarative manner, similar to regular views, from | |
/// Text and Image. This ensures the font’s kerning, ligatures, and other | |
/// properties are preserved across the entire text. | |
/// | |
/// Example | |
/// | |
/// ```swift | |
/// Text { | |
/// for index in 0..<10 { | |
/// Image(systemName: "\(index).circle") | |
/// .foregroundColor(.secondary) | |
/// } | |
/// | |
/// if showLabel { | |
/// Text(label) | |
/// .font(.headline) | |
/// } | |
/// } | |
/// ``` | |
/// | |
@resultBuilder | |
public struct TextBuilder { | |
@inlinable | |
public static func buildBlock(_ components: Text...) -> Text { | |
buildArray(components) | |
} | |
@inlinable | |
public static func buildArray(_ components: [Text]) -> Text { | |
components.dropFirst().reduce(components.first ?? Text(""), +) | |
} | |
@inlinable | |
public static func buildEither(first component: Text) -> Text { | |
component | |
} | |
@inlinable | |
public static func buildEither(second component: Text) -> Text { | |
component | |
} | |
@inlinable | |
public static func buildOptional(_ component: Text?) -> Text { | |
component ?? Text("") | |
} | |
@inlinable | |
public static func buildExpression(_ image: Image) -> Text { | |
Text("\(image)") | |
} | |
@inlinable | |
public static func buildExpression(_ text: Text) -> Text { | |
text | |
} | |
} | |
extension Text { | |
/// Build `Text` instances in a declarative manner, similar to regular | |
/// views, from `Text` and `Image`. This ensures the font's kerning, | |
/// ligatures, and other properties are preserved across the entire text. | |
/// | |
/// Example | |
/// | |
/// ```swift | |
/// Text { | |
/// for index in 0..<10 { | |
/// Image(systemName: "\(index).circle") | |
/// .foregroundColor(.secondary) | |
/// } | |
/// | |
/// if showLabel { | |
/// Text(label) | |
/// .font(.headline) | |
/// } | |
/// } | |
/// ``` | |
/// | |
public init(@TextBuilder content: () -> Text) { | |
self = content() | |
} | |
} | |
// MARK: - Auxiliary | |
extension Image { | |
@inlinable | |
public func foregroundColor(_ color: Color?) -> Text { | |
Text("\(self)").foregroundColor(color) | |
} | |
} | |
// MARK: - Previews | |
struct TextBuilder_Previews: PreviewProvider { | |
static var previews: some View { | |
let showLabel = true | |
Text { | |
for index in 0..<4 { | |
Image(systemName: "\(index).circle") | |
.foregroundColor(.secondary) | |
} | |
Text(" ") | |
if showLabel { | |
Text("Label") | |
.font(.headline) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment