Skip to content

Introduce dynamic text styles and various font modifiers #186

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 8 additions & 10 deletions Examples/Sources/CounterExample/CounterApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,16 @@ struct CounterApp: App {
var body: some Scene {
WindowGroup("CounterExample: \(count)") {
#hotReloadable {
VStack {
HStack(spacing: 20) {
Button("-") {
count -= 1
}
Text("Count: \(count)")
Button("+") {
count += 1
}
HStack(spacing: 20) {
Button("-") {
count -= 1
}
Text("Count: \(count)")
Button("+") {
count += 1
}
.padding()
}
.padding()
}
}
.defaultSize(width: 400, height: 200)
Expand Down
70 changes: 37 additions & 33 deletions Sources/AppKitBackend/AppKitBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public final class AppKitBackend: AppBackend {
public let requiresImageUpdateOnScaleFactorChange = false
public let menuImplementationStyle = MenuImplementationStyle.dynamicPopover
public let canRevealFiles = true
public let deviceClass = DeviceClass.desktop

public var scrollBarWidth: Int {
// We assume that all scrollers have their controlSize set to `.regular` by default.
Expand Down Expand Up @@ -323,13 +324,9 @@ public final class AppKitBackend: AppBackend {

public func computeRootEnvironment(defaultEnvironment: EnvironmentValues) -> EnvironmentValues {
let isDark = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark"
let font = Font.system(
size: Int(NSFont.systemFont(ofSize: 0.0).pointSize.rounded(.awayFromZero))
)
return
defaultEnvironment
.with(\.colorScheme, isDark ? .dark : .light)
.with(\.font, font)
}

public func setRootEnvironmentChangeHandler(to action: @escaping () -> Void) {
Expand Down Expand Up @@ -752,8 +749,9 @@ public final class AppKitBackend: AppBackend {
textField.isEnabled = environment.isEnabled
textField.placeholderString = placeholder
textField.appearance = environment.colorScheme.nsAppearance
if textField.font != Self.font(for: environment) {
textField.font = Self.font(for: environment)
let resolvedFont = environment.resolvedFont
if textField.font != Self.font(for: resolvedFont) {
textField.font = Self.font(for: resolvedFont)
}
textField.onEdit = { textField in
onChange(textField.stringValue)
Expand Down Expand Up @@ -806,8 +804,9 @@ public final class AppKitBackend: AppBackend {
textEditor.onEdit = { textView in
onChange(self.getContent(ofTextEditor: textView))
}
if textEditor.font != Self.font(for: environment) {
textEditor.font = Self.font(for: environment)
let resolvedFont = environment.resolvedFont
if textEditor.font != Self.font(for: resolvedFont) {
textEditor.font = Self.font(for: resolvedFont)
}
textEditor.appearance = environment.colorScheme.nsAppearance
textEditor.isEditable = environment.isEnabled
Expand Down Expand Up @@ -1112,50 +1111,55 @@ public final class AppKitBackend: AppBackend {
case .trailing:
.right
}

let resolvedFont = environment.resolvedFont

// This is definitely what these properties were intended for
paragraphStyle.minimumLineHeight = CGFloat(resolvedFont.lineHeight)
paragraphStyle.maximumLineHeight = CGFloat(resolvedFont.lineHeight)
paragraphStyle.lineSpacing = 0

return [
.foregroundColor: environment.suggestedForegroundColor.nsColor,
.font: font(for: environment),
.font: font(for: resolvedFont),
.paragraphStyle: paragraphStyle,
]
}

private static func font(for environment: EnvironmentValues) -> NSFont {
switch environment.font {
case .system(let size, let weight, let design):
switch design {
case .default, .none:
NSFont.systemFont(
ofSize: CGFloat(size), weight: weight.map(Self.weight(for:)) ?? .regular
)
private static func font(for font: Font.Resolved) -> NSFont {
let size = CGFloat(font.pointSize)
let weight = weight(for: font.weight)
switch font.identifier.kind {
case .system:
switch font.design {
case .default:
return NSFont.systemFont(ofSize: size, weight: weight)
case .monospaced:
NSFont.monospacedSystemFont(
ofSize: CGFloat(size),
weight: weight.map(Self.weight(for:)) ?? .regular
)
return NSFont.monospacedSystemFont(ofSize: size, weight: weight)
}
}
}

private static func weight(for weight: Font.Weight) -> NSFont.Weight {
switch weight {
case .black:
.black
case .bold:
.bold
case .heavy:
.heavy
case .thin:
.thin
case .ultraLight:
.ultraLight
case .light:
.light
case .medium:
.medium
case .regular:
.regular
case .medium:
.medium
case .semibold:
.semibold
case .thin:
.thin
case .ultraLight:
.ultraLight
case .bold:
.bold
case .black:
.black
case .heavy:
.heavy
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Gtk/Utility/CSS/CSSProperty.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public struct CSSProperty: Equatable {
CSSProperty(key: "min-height", value: "\(height)px")
}

public static func fontSize(_ size: Int) -> CSSProperty {
public static func fontSize(_ size: Double) -> CSSProperty {
CSSProperty(key: "font-size", value: "\(size)px")
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Gtk3/Utility/CSS/CSSProperty.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public struct CSSProperty: Equatable {
CSSProperty(key: "min-height", value: "\(height)px")
}

public static func fontSize(_ size: Int) -> CSSProperty {
public static func fontSize(_ size: Double) -> CSSProperty {
CSSProperty(key: "font-size", value: "\(size)px")
}

Expand Down
24 changes: 13 additions & 11 deletions Sources/Gtk3Backend/Gtk3Backend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public final class Gtk3Backend: AppBackend {
public let requiresImageUpdateOnScaleFactorChange = true
public let menuImplementationStyle = MenuImplementationStyle.dynamicPopover
public let canRevealFiles = true
public let deviceClass = DeviceClass.desktop

var gtkApp: Application

Expand Down Expand Up @@ -1433,35 +1434,36 @@ public final class Gtk3Backend: AppBackend {
) -> [CSSProperty] {
var properties: [CSSProperty] = []
properties.append(.foregroundColor(environment.suggestedForegroundColor.gtkColor))
switch environment.font {
case .system(let size, let weight, let design):
properties.append(.fontSize(size))
let font = environment.resolvedFont
switch font.identifier.kind {
case .system:
properties.append(.fontSize(font.pointSize))
let weightNumber =
switch weight {
case .thin:
100
switch font.weight {
case .ultraLight:
100
case .thin:
200
case .light:
300
case .regular, .none:
case .regular:
400
case .medium:
500
case .semibold:
600
case .bold:
700
case .black:
900
case .heavy:
800
case .black:
900
}
properties.append(.fontWeight(weightNumber))
switch design {
switch font.design {
case .monospaced:
properties.append(.fontFamily("monospace"))
case .default, .none:
case .default:
break
}
}
Expand Down
34 changes: 20 additions & 14 deletions Sources/GtkBackend/GtkBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public final class GtkBackend: AppBackend {
public let requiresImageUpdateOnScaleFactorChange = false
public let menuImplementationStyle = MenuImplementationStyle.dynamicPopover
public let canRevealFiles = true
public let deviceClass = DeviceClass.desktop

var gtkApp: Application

Expand Down Expand Up @@ -1480,35 +1481,40 @@ public final class GtkBackend: AppBackend {
) -> [CSSProperty] {
var properties: [CSSProperty] = []
properties.append(.foregroundColor(environment.suggestedForegroundColor.gtkColor))
switch environment.font {
case .system(let size, let weight, let design):
properties.append(.fontSize(size))
let font = environment.resolvedFont
switch font.identifier.kind {
case .system:
properties.append(.fontSize(font.pointSize))
// For some reason I had to tweak these a bit to make them match
// up with AppKit's font weights. I didn't have to do that for
// Gtk3Backend (which matches SwiftUI's text layout and rendering
// remarkbly well).
let weightNumber =
switch weight {
case .thin:
100
switch font.weight {
case .ultraLight:
200
case .light:
case .thin:
300
case .regular, .none:
case .light:
400
case .medium:
case .regular:
500
case .semibold:
case .medium:
600
case .semibold:
700
case .bold:
700
case .black:
900
case .heavy:
800
case .black:
900
}
properties.append(.fontWeight(weightNumber))
switch design {
switch font.design {
case .monospaced:
properties.append(.fontFamily("monospace"))
case .default, .none:
case .default:
break
}
}
Expand Down
22 changes: 22 additions & 0 deletions Sources/SwiftCrossUI/Backend/AppBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@
/// are called.
var menuImplementationStyle: MenuImplementationStyle { get }

/// The class of device that the backend is currently running on. Used to
/// determine text sizing and other adaptive properties.
var deviceClass: DeviceClass { get }

/// Whether the backend can reveal files in the system file manager or not.
/// Mobile backends generally can't.
var canRevealFiles: Bool { get }
Expand Down Expand Up @@ -180,6 +184,17 @@
/// may or may not override the previous handler.
func setRootEnvironmentChangeHandler(to action: @escaping () -> Void)

/// Resolves the given text style to concrete font properties.
///
/// This method doesn't take ``EnvironmentValues`` because its result
/// should be consistent when given the same text style twice. Font modifiers
/// take effect later in the font resolution process.
///
/// A default implementation is provided. It uses the backend's reported
/// device class and looks up the text style in a lookup table derived
/// from Apple's typography guidelines. See ``TextStyle/resolve(for:)``.
@Sendable func resolveTextStyle(_ textStyle: Font.TextStyle) -> Font.TextStyle.Resolved

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 196 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

/// Computes a window's environment based off the root environment. This may involve
/// updating ``EnvironmentValues/windowScaleFactor`` etc.
func computeWindowEnvironment(
Expand Down Expand Up @@ -668,6 +683,13 @@
}

extension AppBackend {
@Sendable

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPad)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit-catalyst

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (TV)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6

Check warning on line 686 in Sources/SwiftCrossUI/Backend/AppBackend.swift

View workflow job for this annotation

GitHub Actions / uikit (iPhone)

instance methods of non-Sendable types cannot be marked as '@sendable'; this is an error in Swift 6
public func resolveTextStyle(
_ textStyle: Font.TextStyle
) -> Font.TextStyle.Resolved {
textStyle.resolve(for: deviceClass)
}

public func tag(widget: Widget, as tag: String) {
// This is only really to assist contributors when debugging backends,
// so it's safe enough to have a no-op default implementation.
Expand Down
30 changes: 29 additions & 1 deletion Sources/SwiftCrossUI/Environment/EnvironmentValues.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,35 @@ public struct EnvironmentValues {
/// The current stack spacing. Inherited by ``ForEach`` and ``Group`` so
/// that they can be used without affecting layout.
public var layoutSpacing: Int

/// The current font.
public var font: Font
/// A font overlay storing font modifications. If these conflict with the
/// font's internal overlay, these win.
///
/// We keep this separate overlay for modifiers because we want modifiers to
/// be persisted even if the developer sets a custom font further down the
/// view hierarchy.
var fontOverlay: Font.Overlay

/// A font resolution context derived from the current environment.
///
/// Essentially just a subset of the environment.
public var fontResolutionContext: Font.Context {
Font.Context(
overlay: fontOverlay,
deviceClass: backend.deviceClass,
resolveTextStyle: backend.resolveTextStyle(_:)
)
}

/// The current font resolved to a form suitable for rendering. Just a
/// helper method for our own backends. We haven't made this public because
/// it would be weird to have two pretty equivalent ways of resolving fonts.
package var resolvedFont: Font.Resolved {
font.resolve(in: fontResolutionContext)
}

/// How lines should be aligned relative to each other when line wrapped.
public var multilineTextAlignment: HorizontalAlignment

Expand Down Expand Up @@ -158,7 +185,8 @@ public struct EnvironmentValues {
layoutAlignment = .center
layoutSpacing = 10
foregroundColor = nil
font = .system(size: 12)
font = .body
fontOverlay = Font.Overlay()
multilineTextAlignment = .leading
colorScheme = .light
windowScaleFactor = 1
Expand Down
Loading
Loading