diff --git a/Sources/MarkdownUI/Markdown.swift b/Sources/MarkdownUI/Markdown.swift index 392bd5e9..d1f73555 100644 --- a/Sources/MarkdownUI/Markdown.swift +++ b/Sources/MarkdownUI/Markdown.swift @@ -253,6 +253,7 @@ public struct Markdown: View { layoutDirection: self.layoutDirection, textAlignment: self.textAlignment ), + sizeCategory: self.sizeCategory, style: self.style, imageHandlers: self.imageHandlers ) diff --git a/Sources/MarkdownUI/Rendering/AttributedStringRenderer.swift b/Sources/MarkdownUI/Rendering/AttributedStringRenderer.swift index 7e239f7e..3d20da3d 100644 --- a/Sources/MarkdownUI/Rendering/AttributedStringRenderer.swift +++ b/Sources/MarkdownUI/Rendering/AttributedStringRenderer.swift @@ -39,6 +39,7 @@ struct AttributedStringRenderer { let baseURL: URL? let baseWritingDirection: NSWritingDirection let alignment: NSTextAlignment + let sizeCategory: ContentSizeCategory let style: MarkdownStyle func renderDocument(_ document: Document) -> NSAttributedString { @@ -174,7 +175,7 @@ extension AttributedStringRenderer { style.measurements.headIndentStep, NSAttributedString( string: "\(highestNumber).", - attributes: [.font: state.font.monospacedDigit().resolve()] + attributes: [.font: state.font.monospacedDigit().resolve(sizeCategory: sizeCategory)] ).em() + style.measurements.listMarkerSpacing ) @@ -341,7 +342,7 @@ extension AttributedStringRenderer { .init( string: .nbsp, attributes: [ - .font: state.font.resolve(), + .font: state.font.resolve(sizeCategory: sizeCategory), .strikethroughStyle: NSUnderlineStyle.single.rawValue, .strikethroughColor: PlatformColor.separator, ] @@ -424,7 +425,7 @@ extension AttributedStringRenderer { NSAttributedString( string: text, attributes: [ - .font: state.font.resolve(), + .font: state.font.resolve(sizeCategory: sizeCategory), .foregroundColor: PlatformColor(state.foregroundColor), ] ) @@ -490,7 +491,7 @@ extension AttributedStringRenderer { } private func paragraphStyle(state: State) -> NSParagraphStyle { - let pointSize = state.font.resolve().pointSize + let pointSize = state.font.resolve(sizeCategory: sizeCategory).pointSize let result = NSMutableParagraphStyle() result.setParagraphStyle(.default) result.baseWritingDirection = baseWritingDirection diff --git a/Sources/MarkdownUI/Rendering/Document+NSAttributedString.swift b/Sources/MarkdownUI/Rendering/Document+NSAttributedString.swift index 962d811d..ad867199 100644 --- a/Sources/MarkdownUI/Rendering/Document+NSAttributedString.swift +++ b/Sources/MarkdownUI/Rendering/Document+NSAttributedString.swift @@ -7,12 +7,14 @@ extension Document { baseURL: URL?, baseWritingDirection: NSWritingDirection, alignment: NSTextAlignment, + sizeCategory: ContentSizeCategory, style: MarkdownStyle ) -> NSAttributedString { AttributedStringRenderer( baseURL: baseURL, baseWritingDirection: baseWritingDirection, alignment: alignment, + sizeCategory: sizeCategory, style: style ).renderDocument(self) } @@ -21,6 +23,7 @@ extension Document { baseURL: URL?, baseWritingDirection: NSWritingDirection, alignment: NSTextAlignment, + sizeCategory: ContentSizeCategory, style: MarkdownStyle, imageHandlers: [String: MarkdownImageHandler] ) -> AnyPublisher { @@ -30,6 +33,7 @@ extension Document { baseURL: baseURL, baseWritingDirection: baseWritingDirection, alignment: alignment, + sizeCategory: sizeCategory, style: style ) ) diff --git a/Sources/MarkdownUI/Style/Font.swift b/Sources/MarkdownUI/Style/Font.swift index 75ba0d60..f37b5084 100644 --- a/Sources/MarkdownUI/Style/Font.swift +++ b/Sources/MarkdownUI/Style/Font.swift @@ -8,15 +8,15 @@ extension MarkdownStyle { public struct Font: Hashable { private var provider: AnyHashable - func resolve() -> PlatformFont { + func resolve(sizeCategory: ContentSizeCategory = .large) -> PlatformFont { guard let fontProvider = self.provider.base as? FontProvider else { fatalError("provider should conform to FontProvider") } #if os(macOS) - return .init(descriptor: fontProvider.fontDescriptor(), size: 0) + return .init(descriptor: fontProvider.fontDescriptor(compatibleWith: sizeCategory), size: 0) ?? .preferredFont(forTextStyle: .body) #elseif os(iOS) || os(tvOS) - return .init(descriptor: fontProvider.fontDescriptor(), size: 0) + return .init(descriptor: fontProvider.fontDescriptor(compatibleWith: sizeCategory), size: 0) #endif } } @@ -150,21 +150,22 @@ extension MarkdownStyle.Font { // MARK: - FontProvider private protocol FontProvider { - func fontDescriptor() -> PlatformFontDescriptor + func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor } private struct TextStyleFontProvider: Hashable, FontProvider { var style: SwiftUI.Font.TextStyle var design: SwiftUI.Font.Design - func fontDescriptor() -> PlatformFontDescriptor { + func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor { #if os(macOS) let fontDescriptor = PlatformFontDescriptor.preferredFontDescriptor( forTextStyle: .init(style) ) #elseif os(iOS) || os(tvOS) let fontDescriptor = PlatformFontDescriptor.preferredFontDescriptor( - withTextStyle: .init(style) + withTextStyle: .init(style), + compatibleWith: .init(preferredContentSizeCategory: .init(sizeCategory)) ) #endif @@ -177,7 +178,7 @@ private struct SystemFontProvider: Hashable, FontProvider { var weight: SwiftUI.Font.Weight var design: SwiftUI.Font.Design - func fontDescriptor() -> PlatformFontDescriptor { + func fontDescriptor(compatibleWith _: ContentSizeCategory) -> PlatformFontDescriptor { let fontDescriptor = PlatformFont.systemFont(ofSize: size, weight: .init(weight)) .fontDescriptor return fontDescriptor.withDesign(.init(design)) ?? fontDescriptor @@ -189,12 +190,16 @@ private struct CustomFontProvider: Hashable, FontProvider { var size: CGFloat var textStyle: SwiftUI.Font.TextStyle? - func fontDescriptor() -> PlatformFontDescriptor { + func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor { var size = self.size #if os(iOS) || os(tvOS) if let textStyle = self.textStyle { - size = UIFontMetrics(forTextStyle: .init(textStyle)).scaledValue(for: size) + size = UIFontMetrics(forTextStyle: .init(textStyle)) + .scaledValue( + for: size, + compatibleWith: .init(preferredContentSizeCategory: .init(sizeCategory)) + ) } #endif @@ -211,11 +216,11 @@ private struct FontModifierProvider: Hashable, FontProvider where M: Hashable var base: AnyHashable var modifier: M - func fontDescriptor() -> PlatformFontDescriptor { + func fontDescriptor(compatibleWith sizeCategory: ContentSizeCategory) -> PlatformFontDescriptor { guard let fontProvider = self.base.base as? FontProvider else { fatalError("base should conform to FontProvider") } - var fontDescriptor = fontProvider.fontDescriptor() + var fontDescriptor = fontProvider.fontDescriptor(compatibleWith: sizeCategory) modifier.modify(&fontDescriptor) return fontDescriptor } @@ -399,3 +404,38 @@ extension PlatformFontDescriptor.SystemDesign { } } } + +#if os(iOS) || os(tvOS) + extension UIContentSizeCategory { + fileprivate init(_ contentSizeCategory: ContentSizeCategory) { + switch contentSizeCategory { + case .extraSmall: + self = .extraSmall + case .small: + self = .small + case .medium: + self = .medium + case .large: + self = .large + case .extraLarge: + self = .extraLarge + case .extraExtraLarge: + self = .extraExtraLarge + case .extraExtraExtraLarge: + self = .extraExtraExtraLarge + case .accessibilityMedium: + self = .accessibilityMedium + case .accessibilityLarge: + self = .accessibilityLarge + case .accessibilityExtraLarge: + self = .accessibilityExtraLarge + case .accessibilityExtraExtraLarge: + self = .accessibilityExtraExtraLarge + case .accessibilityExtraExtraExtraLarge: + self = .accessibilityExtraExtraExtraLarge + @unknown default: + self = .large + } + } + } +#endif diff --git a/Tests/MarkdownUITests/MarkdownTests.swift b/Tests/MarkdownUITests/MarkdownTests.swift index 7e79bf77..5d5b2e94 100644 --- a/Tests/MarkdownUITests/MarkdownTests.swift +++ b/Tests/MarkdownUITests/MarkdownTests.swift @@ -449,5 +449,20 @@ assertSnapshot(matching: view, as: .image(layout: layout), named: platformName) } + + #if os(iOS) + func testSizeCategory() { + let view = VStack { + ForEach(ContentSizeCategory.allCases, id: \.self) { sizeCategory in + Markdown("Markdown**UI**") + .environment(\.sizeCategory, sizeCategory) + } + } + .background(Color.orange) + .padding() + + assertSnapshot(matching: view, as: .image(layout: layout), named: platformName) + } + #endif } #endif diff --git a/Tests/MarkdownUITests/ReadMeImagesTests.swift b/Tests/MarkdownUITests/ReadMeImagesTests.swift index 951b6a91..d6783f1c 100644 --- a/Tests/MarkdownUITests/ReadMeImagesTests.swift +++ b/Tests/MarkdownUITests/ReadMeImagesTests.swift @@ -48,6 +48,7 @@ ) } + @available(iOS 15.0, *) func testMarkdownStyle() { let view = Markdown( #""" diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testBlockQuote.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testBlockQuote.iOS.png index eccc7617..95dbb121 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testBlockQuote.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testBlockQuote.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testBulletList.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testBulletList.iOS.png index b859eae6..c7dac5c4 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testBulletList.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testBulletList.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testCodeBlock.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testCodeBlock.iOS.png index 6fba6814..58f05194 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testCodeBlock.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testCodeBlock.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testCodeBlockInsideList.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testCodeBlockInsideList.iOS.png index a157ae5e..2fe411d0 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testCodeBlockInsideList.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testCodeBlockInsideList.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testHeadings.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testHeadings.iOS.png index cd683903..25311912 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testHeadings.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testHeadings.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testHeadingsAndBlockQuotesInsideList.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testHeadingsAndBlockQuotesInsideList.iOS.png index 0b066d82..808b5233 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testHeadingsAndBlockQuotesInsideList.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testHeadingsAndBlockQuotesInsideList.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testInlines.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testInlines.iOS.png index 05c51fd4..9d2b167f 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testInlines.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testInlines.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testListAndHeadingsInsideBlockQuotes.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testListAndHeadingsInsideBlockQuotes.iOS.png index e0243c38..f5b59bd0 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testListAndHeadingsInsideBlockQuotes.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testListAndHeadingsInsideBlockQuotes.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testMarkdownStyle.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testMarkdownStyle.iOS.png index 0ec42e76..aa54b574 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testMarkdownStyle.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testMarkdownStyle.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testOrderedList.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testOrderedList.iOS.png index 4b70c362..4e18c67e 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testOrderedList.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testOrderedList.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testParagraph.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testParagraph.iOS.png index 4628692a..bebb157f 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testParagraph.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testParagraph.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testParagraphAndLineBreak.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testParagraphAndLineBreak.iOS.png index 134c4c76..28353638 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testParagraphAndLineBreak.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testParagraphAndLineBreak.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftList.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftList.iOS.png index 039aebee..e2dad7ce 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftList.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftList.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftParagraph.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftParagraph.iOS.png index 9089cf25..8eef9443 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftParagraph.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftParagraph.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftTrailingParagraph.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftTrailingParagraph.iOS.png index aadf057c..ad3b4bcb 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftTrailingParagraph.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testRightToLeftTrailingParagraph.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testSizeCategory.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testSizeCategory.iOS.png new file mode 100644 index 00000000..762583c1 Binary files /dev/null and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testSizeCategory.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testThematicBreak.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testThematicBreak.iOS.png index 22e2bd07..2b8fdba5 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testThematicBreak.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testThematicBreak.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testTrailingParagraph.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testTrailingParagraph.iOS.png index 938af393..8412bcc6 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testTrailingParagraph.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testTrailingParagraph.iOS.png differ diff --git a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testVerbatimHTML.iOS.png b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testVerbatimHTML.iOS.png index 744ad055..1489d12e 100644 Binary files a/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testVerbatimHTML.iOS.png and b/Tests/MarkdownUITests/__Snapshots__/MarkdownTests/testVerbatimHTML.iOS.png differ