Skip to content

Commit b6e88f1

Browse files
authored
Resolve fonts considering the environment's size category (#94)
* Resolve fonts considering the environment's size category * Fix generation of README images
1 parent 3c6b679 commit b6e88f1

25 files changed

+77
-15
lines changed

Sources/MarkdownUI/Markdown.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ public struct Markdown: View {
253253
layoutDirection: self.layoutDirection,
254254
textAlignment: self.textAlignment
255255
),
256+
sizeCategory: self.sizeCategory,
256257
style: self.style,
257258
imageHandlers: self.imageHandlers
258259
)

Sources/MarkdownUI/Rendering/AttributedStringRenderer.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct AttributedStringRenderer {
3939
let baseURL: URL?
4040
let baseWritingDirection: NSWritingDirection
4141
let alignment: NSTextAlignment
42+
let sizeCategory: ContentSizeCategory
4243
let style: MarkdownStyle
4344

4445
func renderDocument(_ document: Document) -> NSAttributedString {
@@ -174,7 +175,7 @@ extension AttributedStringRenderer {
174175
style.measurements.headIndentStep,
175176
NSAttributedString(
176177
string: "\(highestNumber).",
177-
attributes: [.font: state.font.monospacedDigit().resolve()]
178+
attributes: [.font: state.font.monospacedDigit().resolve(sizeCategory: sizeCategory)]
178179
).em() + style.measurements.listMarkerSpacing
179180
)
180181

@@ -341,7 +342,7 @@ extension AttributedStringRenderer {
341342
.init(
342343
string: .nbsp,
343344
attributes: [
344-
.font: state.font.resolve(),
345+
.font: state.font.resolve(sizeCategory: sizeCategory),
345346
.strikethroughStyle: NSUnderlineStyle.single.rawValue,
346347
.strikethroughColor: PlatformColor.separator,
347348
]
@@ -424,7 +425,7 @@ extension AttributedStringRenderer {
424425
NSAttributedString(
425426
string: text,
426427
attributes: [
427-
.font: state.font.resolve(),
428+
.font: state.font.resolve(sizeCategory: sizeCategory),
428429
.foregroundColor: PlatformColor(state.foregroundColor),
429430
]
430431
)
@@ -490,7 +491,7 @@ extension AttributedStringRenderer {
490491
}
491492

492493
private func paragraphStyle(state: State) -> NSParagraphStyle {
493-
let pointSize = state.font.resolve().pointSize
494+
let pointSize = state.font.resolve(sizeCategory: sizeCategory).pointSize
494495
let result = NSMutableParagraphStyle()
495496
result.setParagraphStyle(.default)
496497
result.baseWritingDirection = baseWritingDirection

Sources/MarkdownUI/Rendering/Document+NSAttributedString.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ extension Document {
77
baseURL: URL?,
88
baseWritingDirection: NSWritingDirection,
99
alignment: NSTextAlignment,
10+
sizeCategory: ContentSizeCategory,
1011
style: MarkdownStyle
1112
) -> NSAttributedString {
1213
AttributedStringRenderer(
1314
baseURL: baseURL,
1415
baseWritingDirection: baseWritingDirection,
1516
alignment: alignment,
17+
sizeCategory: sizeCategory,
1618
style: style
1719
).renderDocument(self)
1820
}
@@ -21,6 +23,7 @@ extension Document {
2123
baseURL: URL?,
2224
baseWritingDirection: NSWritingDirection,
2325
alignment: NSTextAlignment,
26+
sizeCategory: ContentSizeCategory,
2427
style: MarkdownStyle,
2528
imageHandlers: [String: MarkdownImageHandler]
2629
) -> AnyPublisher<NSAttributedString, Never> {
@@ -30,6 +33,7 @@ extension Document {
3033
baseURL: baseURL,
3134
baseWritingDirection: baseWritingDirection,
3235
alignment: alignment,
36+
sizeCategory: sizeCategory,
3337
style: style
3438
)
3539
)

Sources/MarkdownUI/Style/Font.swift

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ extension MarkdownStyle {
88
public struct Font: Hashable {
99
private var provider: AnyHashable
1010

11-
func resolve() -> PlatformFont {
11+
func resolve(sizeCategory: ContentSizeCategory = .large) -> PlatformFont {
1212
guard let fontProvider = self.provider.base as? FontProvider else {
1313
fatalError("provider should conform to FontProvider")
1414
}
1515
#if os(macOS)
16-
return .init(descriptor: fontProvider.fontDescriptor(), size: 0)
16+
return .init(descriptor: fontProvider.fontDescriptor(compatibleWith: sizeCategory), size: 0)
1717
?? .preferredFont(forTextStyle: .body)
1818
#elseif os(iOS) || os(tvOS)
19-
return .init(descriptor: fontProvider.fontDescriptor(), size: 0)
19+
return .init(descriptor: fontProvider.fontDescriptor(compatibleWith: sizeCategory), size: 0)
2020
#endif
2121
}
2222
}
@@ -150,21 +150,22 @@ extension MarkdownStyle.Font {
150150
// MARK: - FontProvider
151151

152152
private protocol FontProvider {
153-
func fontDescriptor() -> PlatformFontDescriptor
153+
func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor
154154
}
155155

156156
private struct TextStyleFontProvider: Hashable, FontProvider {
157157
var style: SwiftUI.Font.TextStyle
158158
var design: SwiftUI.Font.Design
159159

160-
func fontDescriptor() -> PlatformFontDescriptor {
160+
func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor {
161161
#if os(macOS)
162162
let fontDescriptor = PlatformFontDescriptor.preferredFontDescriptor(
163163
forTextStyle: .init(style)
164164
)
165165
#elseif os(iOS) || os(tvOS)
166166
let fontDescriptor = PlatformFontDescriptor.preferredFontDescriptor(
167-
withTextStyle: .init(style)
167+
withTextStyle: .init(style),
168+
compatibleWith: .init(preferredContentSizeCategory: .init(sizeCategory))
168169
)
169170
#endif
170171

@@ -177,7 +178,7 @@ private struct SystemFontProvider: Hashable, FontProvider {
177178
var weight: SwiftUI.Font.Weight
178179
var design: SwiftUI.Font.Design
179180

180-
func fontDescriptor() -> PlatformFontDescriptor {
181+
func fontDescriptor(compatibleWith _: ContentSizeCategory) -> PlatformFontDescriptor {
181182
let fontDescriptor = PlatformFont.systemFont(ofSize: size, weight: .init(weight))
182183
.fontDescriptor
183184
return fontDescriptor.withDesign(.init(design)) ?? fontDescriptor
@@ -189,12 +190,16 @@ private struct CustomFontProvider: Hashable, FontProvider {
189190
var size: CGFloat
190191
var textStyle: SwiftUI.Font.TextStyle?
191192

192-
func fontDescriptor() -> PlatformFontDescriptor {
193+
func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor {
193194
var size = self.size
194195

195196
#if os(iOS) || os(tvOS)
196197
if let textStyle = self.textStyle {
197-
size = UIFontMetrics(forTextStyle: .init(textStyle)).scaledValue(for: size)
198+
size = UIFontMetrics(forTextStyle: .init(textStyle))
199+
.scaledValue(
200+
for: size,
201+
compatibleWith: .init(preferredContentSizeCategory: .init(sizeCategory))
202+
)
198203
}
199204
#endif
200205

@@ -211,11 +216,11 @@ private struct FontModifierProvider<M>: Hashable, FontProvider where M: Hashable
211216
var base: AnyHashable
212217
var modifier: M
213218

214-
func fontDescriptor() -> PlatformFontDescriptor {
219+
func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor {
215220
guard let fontProvider = self.base.base as? FontProvider else {
216221
fatalError("base should conform to FontProvider")
217222
}
218-
var fontDescriptor = fontProvider.fontDescriptor()
223+
var fontDescriptor = fontProvider.fontDescriptor(compatibleWith: sizeCategory)
219224
modifier.modify(&fontDescriptor)
220225
return fontDescriptor
221226
}
@@ -399,3 +404,38 @@ extension PlatformFontDescriptor.SystemDesign {
399404
}
400405
}
401406
}
407+
408+
#if os(iOS) || os(tvOS)
409+
extension UIContentSizeCategory {
410+
fileprivate init(_ contentSizeCategory: ContentSizeCategory) {
411+
switch contentSizeCategory {
412+
case .extraSmall:
413+
self = .extraSmall
414+
case .small:
415+
self = .small
416+
case .medium:
417+
self = .medium
418+
case .large:
419+
self = .large
420+
case .extraLarge:
421+
self = .extraLarge
422+
case .extraExtraLarge:
423+
self = .extraExtraLarge
424+
case .extraExtraExtraLarge:
425+
self = .extraExtraExtraLarge
426+
case .accessibilityMedium:
427+
self = .accessibilityMedium
428+
case .accessibilityLarge:
429+
self = .accessibilityLarge
430+
case .accessibilityExtraLarge:
431+
self = .accessibilityExtraLarge
432+
case .accessibilityExtraExtraLarge:
433+
self = .accessibilityExtraExtraLarge
434+
case .accessibilityExtraExtraExtraLarge:
435+
self = .accessibilityExtraExtraExtraLarge
436+
@unknown default:
437+
self = .large
438+
}
439+
}
440+
}
441+
#endif

Tests/MarkdownUITests/MarkdownTests.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,5 +449,20 @@
449449

450450
assertSnapshot(matching: view, as: .image(layout: layout), named: platformName)
451451
}
452+
453+
#if os(iOS)
454+
func testSizeCategory() {
455+
let view = VStack {
456+
ForEach(ContentSizeCategory.allCases, id: \.self) { sizeCategory in
457+
Markdown("Markdown**UI**")
458+
.environment(\.sizeCategory, sizeCategory)
459+
}
460+
}
461+
.background(Color.orange)
462+
.padding()
463+
464+
assertSnapshot(matching: view, as: .image(layout: layout), named: platformName)
465+
}
466+
#endif
452467
}
453468
#endif

Tests/MarkdownUITests/ReadMeImagesTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
)
4949
}
5050

51+
@available(iOS 15.0, *)
5152
func testMarkdownStyle() {
5253
let view = Markdown(
5354
#"""
6.95 KB
Loading
2.91 KB
Loading
1.59 KB
Loading
162 Bytes
Loading

0 commit comments

Comments
 (0)