Skip to content
Draft
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
17 changes: 11 additions & 6 deletions Sources/MarkdownText/Models/MarkdownRenderConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,24 +111,27 @@ public struct MarkdownRenderConfig: Hashable, Sendable {
/// Foreground color applied to bold-emphasis runs.
public let boldTextColor: Color
/// Font used for link runs.
public let linkTextFont: MDFont
public var linkTextFont: MDFont { internalLinkTextFont.font }
/// Foreground color applied to link runs.
public let linkTextColor: Color
/// Font used for inline code spans.
public let codeTextFont: MDFont
public var codeTextFont: MDFont { internalCodeTextFont.font }
/// Foreground color applied to inline code spans.
public let codeTextColor: Color
/// Background fill behind inline code spans.
public let codeBackgroundColor: Color
/// Underline color drawn beneath inline code spans.
public let codeUnderlineColor: Color

private let internalLinkTextFont: SendableFont
private let internalCodeTextFont: SendableFont

/// Create an inline text style with the supplied fonts and color palette.
public init(boldTextColor: Color, linkTextFont: MDFont, linkTextColor: Color, codeTextFont: MDFont, codeTextColor: Color, codeBackgroundColor: Color, codeUnderlineColor: Color) {
self.boldTextColor = boldTextColor
self.linkTextFont = linkTextFont
self.internalLinkTextFont = SendableFont(linkTextFont)
self.linkTextColor = linkTextColor
self.codeTextFont = codeTextFont
self.internalCodeTextFont = SendableFont(codeTextFont)
self.codeTextColor = codeTextColor
self.codeBackgroundColor = codeBackgroundColor
self.codeUnderlineColor = codeUnderlineColor
Expand All @@ -142,12 +145,14 @@ public struct MarkdownRenderConfig: Hashable, Sendable {
/// Encoder/decoder used to embed citation payloads into the markdown.
public let coder: CitationCoder
/// Font applied to the rendered citation chip.
public let font: MDFont
public var font: MDFont { internalFont.font }
/// Foreground color of the citation chip text.
public let textColor: Color
/// Background fill of the citation chip.
public let backgroundColor: Color

private let internalFont: SendableFont

/// Create a citation configuration.
/// - Parameters:
/// - isEnabled: See `isEnabled`. Defaults to `true`.
Expand All @@ -164,7 +169,7 @@ public struct MarkdownRenderConfig: Hashable, Sendable {
) {
self.isEnabled = isEnabled
self.coder = coder
self.font = font
self.internalFont = SendableFont(font)
self.textColor = textColor
self.backgroundColor = backgroundColor
}
Expand Down
21 changes: 13 additions & 8 deletions Sources/MarkdownText/Style/TextFonts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,30 @@ import SwiftUI
/// to style a run of text.
public struct TextFonts: Hashable, Sendable {
/// Regular variant. Always required.
public let normal: MDFont
public var normal: MDFont { internalNormal.font }
/// Italic variant, or `nil` to fall back to `normal` for emphasis.
public let italic: MDFont?
public var italic: MDFont? { internalItalic?.font }
/// Bold variant, or `nil` to fall back to `normal` for strong runs.
public let bold: MDFont?
public var bold: MDFont? { internalBold?.font }
/// Bold-italic variant, or `nil` to fall back to `bold` then `italic`.
public let boldItalic: MDFont?
public var boldItalic: MDFont? { internalBoldItalic?.font }
/// Optional kerning override applied via `NSAttributedString.Key.kern`.
public let preferredLetterSpacing: CGFloat?
/// Optional preferred line height in points. When greater than the font's
/// natural line height, the renderer adds the difference as line spacing.
public let preferredLineHeight: CGFloat?

private let internalNormal: SendableFont
private let internalItalic: SendableFont?
private let internalBold: SendableFont?
private let internalBoldItalic: SendableFont?

/// Create a font set with explicit variants and optional spacing overrides.
public init(normal: MDFont, italic: MDFont?, bold: MDFont?, boldItalic: MDFont?, preferredLetterSpacing: CGFloat?, preferredLineHeight: CGFloat?) {
self.normal = normal
self.italic = italic
self.bold = bold
self.boldItalic = boldItalic
self.internalNormal = SendableFont(normal)
self.internalItalic = italic.map(SendableFont.init)
self.internalBold = bold.map(SendableFont.init)
self.internalBoldItalic = boldItalic.map(SendableFont.init)
self.preferredLetterSpacing = preferredLetterSpacing
self.preferredLineHeight = preferredLineHeight
}
Expand Down
26 changes: 26 additions & 0 deletions Sources/MarkdownText/Utilities/SendableFont.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
//

#if canImport(UIKit)
import UIKit
#elseif canImport(AppKit)
import AppKit
#endif

/// A `Sendable` wrapper around `MDFont` (`UIFont`/`NSFont`).
///
/// `UIFont`/`NSFont` are effectively immutable and safe to share across
/// concurrency domains, but the SDK does not mark them as `Sendable`. Storing a
/// font in this value type keeps the unchecked assertion in a single, auditable
/// place so font-holding configuration types can be plainly `Sendable` without
/// leaking a retroactive `Sendable` conformance onto the platform font types.
struct SendableFont: Hashable, @unchecked Sendable {
/// The wrapped platform font.
let font: MDFont

init(_ font: MDFont) {
self.font = font
}
}
Loading