Skip to content

Instantly share code, notes, and snippets.

@ValentinWalter
Created June 8, 2023 17:59
Show Gist options
  • Save ValentinWalter/fe36ba6c2b865764b73a59a528eba39b to your computer and use it in GitHub Desktop.
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.
//
// 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