From e3d66784b8b64b5633690167766f0451819bdab1 Mon Sep 17 00:00:00 2001 From: Guille Gonzalez Date: Sat, 15 Apr 2023 15:17:59 +0200 Subject: [PATCH 1/9] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2394fbc8..35360990 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,7 @@ extension Theme { [Swift Package Index](https://swiftpackageindex.com) kindly hosts the online documentation for all versions, available here: - [main](https://swiftpackageindex.com/gonzalezreal/swift-markdown-ui/main/documentation/markdownui) +- [2.1.0](https://swiftpackageindex.com/gonzalezreal/swift-markdown-ui/2.1.0/documentation/markdownui) - [2.0.2](https://swiftpackageindex.com/gonzalezreal/swift-markdown-ui/2.0.2/documentation/markdownui) ## Demo From dba08f8641638b4310bea87eaf9f27ffedffd398 Mon Sep 17 00:00:00 2001 From: Guille Gonzalez Date: Thu, 27 Apr 2023 10:10:44 +0200 Subject: [PATCH 2/9] Apply the current text style foreground color to code blocks (#228) --- Sources/MarkdownUI/Views/Blocks/CodeBlockView.swift | 1 + .../Views/Environment/Environment+TextStyle.swift | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Sources/MarkdownUI/Views/Blocks/CodeBlockView.swift b/Sources/MarkdownUI/Views/Blocks/CodeBlockView.swift index 86f6d941..f2047a3c 100644 --- a/Sources/MarkdownUI/Views/Blocks/CodeBlockView.swift +++ b/Sources/MarkdownUI/Views/Blocks/CodeBlockView.swift @@ -25,5 +25,6 @@ struct CodeBlockView: View { private var label: some View { self.codeSyntaxHighlighter.highlightCode(self.content, language: self.fenceInfo) .textStyleFont() + .textStyleForegroundColor() } } diff --git a/Sources/MarkdownUI/Views/Environment/Environment+TextStyle.swift b/Sources/MarkdownUI/Views/Environment/Environment+TextStyle.swift index 37de5032..8de1fb99 100644 --- a/Sources/MarkdownUI/Views/Environment/Environment+TextStyle.swift +++ b/Sources/MarkdownUI/Views/Environment/Environment+TextStyle.swift @@ -21,6 +21,12 @@ extension View { } } + func textStyleForegroundColor() -> some View { + TextStyleAttributesReader { attributes in + self.foregroundColor(attributes.foregroundColor) + } + } + func textStyle(_ textStyle: TextStyle) -> some View { self.transformEnvironment(\.textStyle) { $0 = $0.appending(textStyle) From 5f977ba52ddc99a8d891090270b1c5ab1bb9f91d Mon Sep 17 00:00:00 2001 From: Guille Gonzalez Date: Thu, 18 May 2023 08:11:34 +0200 Subject: [PATCH 3/9] Add links to third-party related content --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 35360990..486e9fee 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Display and customize Markdown text in SwiftUI. * [Creating a Markdown view](#creating-a-markdown-view) * [Styling Markdown](#styling-markdown) * [Documentation](#documentation) + * [Related content](#related-content) * [Demo](#demo) * [Installation](#installation) @@ -247,6 +248,13 @@ extension Theme { - [2.1.0](https://swiftpackageindex.com/gonzalezreal/swift-markdown-ui/2.1.0/documentation/markdownui) - [2.0.2](https://swiftpackageindex.com/gonzalezreal/swift-markdown-ui/2.0.2/documentation/markdownui) +### Related content + +You can learn more about MarkdownUI by referring to the following articles and third-party resources: + +- [Better Markdown Rendering in SwiftUI](https://gonzalezreal.github.io/2023/02/18/better-markdown-rendering-in-swiftui.html) +- [Unlock the Power of Markdown in SwiftUI with THIS Hack!](https://youtu.be/gVy06iJQFWQ) by [@Rebeloper](https://twitter.com/Rebeloper) + ## Demo MarkdownUI comes with a few more tricks on the sleeve. You can explore the From a20063b7b51c8c087b5d3d5afc80a807fa375fa6 Mon Sep 17 00:00:00 2001 From: Guille Gonzalez Date: Sun, 3 Sep 2023 12:34:47 +0200 Subject: [PATCH 4/9] Fix code block truncation (#256) * Fix unexpected code block truncation * Remove unused code * Update SnapshotTesting package --- Examples/Demo/Demo/ContentView.swift | 10 ---------- Package.resolved | 4 ++-- Sources/MarkdownUI/Theme/Theme+Basic.swift | 1 + Sources/MarkdownUI/Theme/Theme+DocC.swift | 1 + Sources/MarkdownUI/Theme/Theme+GitHub.swift | 1 + 5 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Examples/Demo/Demo/ContentView.swift b/Examples/Demo/Demo/ContentView.swift index 8f7b1a1b..e2142a46 100644 --- a/Examples/Demo/Demo/ContentView.swift +++ b/Examples/Demo/Demo/ContentView.swift @@ -100,16 +100,6 @@ struct ContentView: View { } } -extension HorizontalAlignment { - private struct RowTitleAlignment: AlignmentID { - static func defaultValue(in context: ViewDimensions) -> CGFloat { - context[HorizontalAlignment.leading] - } - } - - static let rowTitleAligmentGuide = HorizontalAlignment(RowTitleAlignment.self) -} - struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() diff --git a/Package.resolved b/Package.resolved index 20c26b13..23cdd0be 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-snapshot-testing", "state" : { - "revision" : "f29e2014f6230cf7d5138fc899da51c7f513d467", - "version" : "1.10.0" + "revision" : "26ed3a2b4a2df47917ca9b790a57f91285b923fb", + "version" : "1.12.0" } } ], diff --git a/Sources/MarkdownUI/Theme/Theme+Basic.swift b/Sources/MarkdownUI/Theme/Theme+Basic.swift index 96b16a24..b5567b59 100644 --- a/Sources/MarkdownUI/Theme/Theme+Basic.swift +++ b/Sources/MarkdownUI/Theme/Theme+Basic.swift @@ -84,6 +84,7 @@ extension Theme { .codeBlock { configuration in ScrollView(.horizontal) { configuration.label + .fixedSize(horizontal: false, vertical: true) .relativeLineSpacing(.em(0.15)) .relativePadding(.leading, length: .rem(1)) .markdownTextStyle { diff --git a/Sources/MarkdownUI/Theme/Theme+DocC.swift b/Sources/MarkdownUI/Theme/Theme+DocC.swift index 385b0f6e..43cf1939 100644 --- a/Sources/MarkdownUI/Theme/Theme+DocC.swift +++ b/Sources/MarkdownUI/Theme/Theme+DocC.swift @@ -96,6 +96,7 @@ extension Theme { .codeBlock { configuration in ScrollView(.horizontal) { configuration.label + .fixedSize(horizontal: false, vertical: true) .relativeLineSpacing(.em(0.333335)) .markdownTextStyle { FontFamilyVariant(.monospaced) diff --git a/Sources/MarkdownUI/Theme/Theme+GitHub.swift b/Sources/MarkdownUI/Theme/Theme+GitHub.swift index 2f2750c7..90f32ff3 100644 --- a/Sources/MarkdownUI/Theme/Theme+GitHub.swift +++ b/Sources/MarkdownUI/Theme/Theme+GitHub.swift @@ -113,6 +113,7 @@ extension Theme { .codeBlock { configuration in ScrollView(.horizontal) { configuration.label + .fixedSize(horizontal: false, vertical: true) .relativeLineSpacing(.em(0.225)) .markdownTextStyle { FontFamilyVariant(.monospaced) From e599f4ccd53a7503e4dec0ca4771f7047dcbb6e1 Mon Sep 17 00:00:00 2001 From: Armin Shalchian Date: Sun, 3 Sep 2023 17:13:27 +0330 Subject: [PATCH 5/9] visionOS support (new method) (#252) * Changed UIKit OS checks for global use (visionOS) * Added visionOS to package.swift * Removed visionOS version in Package.swift --- Package.swift | 2 +- Sources/MarkdownUI/Extensibility/AssetImageProvider.swift | 2 +- .../Extensibility/DefaultImageView/DefaultImageLoader.swift | 2 +- Sources/MarkdownUI/Extensibility/Image+PlatformImage.swift | 4 ++-- Sources/MarkdownUI/Utility/Color+RGBA.swift | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Package.swift b/Package.swift index 53bc11dd..664e0430 100644 --- a/Package.swift +++ b/Package.swift @@ -8,7 +8,7 @@ let package = Package( .macOS(.v12), .iOS(.v15), .tvOS(.v15), - .watchOS(.v8), + .watchOS(.v8) ], products: [ .library( diff --git a/Sources/MarkdownUI/Extensibility/AssetImageProvider.swift b/Sources/MarkdownUI/Extensibility/AssetImageProvider.swift index fa945d48..8220b1fb 100644 --- a/Sources/MarkdownUI/Extensibility/AssetImageProvider.swift +++ b/Sources/MarkdownUI/Extensibility/AssetImageProvider.swift @@ -44,7 +44,7 @@ public struct AssetImageProvider: ImageProvider { } else { return NSImage(named: self.name(url)) } - #elseif os(iOS) || os(tvOS) || os(watchOS) + #elseif canImport(UIKit) return UIImage(named: self.name(url), in: self.bundle, with: nil) #endif } diff --git a/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageLoader.swift b/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageLoader.swift index cbb464d3..4d46a91d 100644 --- a/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageLoader.swift +++ b/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageLoader.swift @@ -32,7 +32,7 @@ final class DefaultImageLoader { extension PlatformImage { fileprivate static func decode(from data: Data) -> PlatformImage? { - #if os(iOS) || os(tvOS) || os(watchOS) + #if canImport(UIKit) guard let image = UIImage(data: data) else { return nil } diff --git a/Sources/MarkdownUI/Extensibility/Image+PlatformImage.swift b/Sources/MarkdownUI/Extensibility/Image+PlatformImage.swift index 3062444d..a6866c88 100644 --- a/Sources/MarkdownUI/Extensibility/Image+PlatformImage.swift +++ b/Sources/MarkdownUI/Extensibility/Image+PlatformImage.swift @@ -1,6 +1,6 @@ import SwiftUI -#if os(iOS) || os(tvOS) || os(watchOS) +#if canImport(UIKit) typealias PlatformImage = UIImage #elseif os(macOS) typealias PlatformImage = NSImage @@ -8,7 +8,7 @@ import SwiftUI extension Image { init(platformImage: PlatformImage) { - #if os(iOS) || os(tvOS) || os(watchOS) + #if canImport(UIKit) self.init(uiImage: platformImage) #elseif os(macOS) self.init(nsImage: platformImage) diff --git a/Sources/MarkdownUI/Utility/Color+RGBA.swift b/Sources/MarkdownUI/Utility/Color+RGBA.swift index 03742edf..576041ab 100644 --- a/Sources/MarkdownUI/Utility/Color+RGBA.swift +++ b/Sources/MarkdownUI/Utility/Color+RGBA.swift @@ -27,7 +27,9 @@ extension Color { } } ) - #elseif os(iOS) || os(tvOS) + #elseif os(watchOS) + self = dark() + #elseif canImport(UIKit) self.init( uiColor: .init { traitCollection in switch traitCollection.userInterfaceStyle { @@ -40,8 +42,6 @@ extension Color { } } ) - #elseif os(watchOS) - self = dark() #endif } } From f28a72601d5ea7f60e65e9143aca1f4d131e092b Mon Sep 17 00:00:00 2001 From: gonzalezreal Date: Sun, 3 Sep 2023 13:50:38 +0000 Subject: [PATCH 6/9] Run swift format --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 664e0430..53bc11dd 100644 --- a/Package.swift +++ b/Package.swift @@ -8,7 +8,7 @@ let package = Package( .macOS(.v12), .iOS(.v15), .tvOS(.v15), - .watchOS(.v8) + .watchOS(.v8), ], products: [ .library( From 595a488b6815b9c7fe172e7feb4a8d8a7f63f21e Mon Sep 17 00:00:00 2001 From: Guille Gonzalez Date: Sat, 9 Sep 2023 19:57:23 +0200 Subject: [PATCH 7/9] Adopt the NetworkImage package for image loading (#258) --- Package.resolved | 9 +++ Package.swift | 8 ++- .../Extensibility/AssetImageProvider.swift | 16 ++++++ .../Extensibility/DefaultImageProvider.swift | 21 ++++--- .../DefaultImageView/DefaultImageLoader.swift | 56 ------------------- .../DefaultImageView/DefaultImageView.swift | 23 -------- .../DefaultImageViewModel.swift | 33 ----------- .../DefaultInlineImageProvider.swift | 14 ++--- .../Extensibility/Image+PlatformImage.swift | 17 ------ Sources/MarkdownUI/Utility/Deprecations.swift | 16 ++++++ 10 files changed, 63 insertions(+), 150 deletions(-) delete mode 100644 Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageLoader.swift delete mode 100644 Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageView.swift delete mode 100644 Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageViewModel.swift delete mode 100644 Sources/MarkdownUI/Extensibility/Image+PlatformImage.swift diff --git a/Package.resolved b/Package.resolved index 23cdd0be..2d0cd944 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,14 @@ { "pins" : [ + { + "identity" : "networkimage", + "kind" : "remoteSourceControl", + "location" : "https://github.com/gonzalezreal/NetworkImage", + "state" : { + "revision" : "7aff8d1b31148d32c5933d75557d42f6323ee3d1", + "version" : "6.0.0" + } + }, { "identity" : "swift-snapshot-testing", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index 53bc11dd..605c5886 100644 --- a/Package.swift +++ b/Package.swift @@ -17,13 +17,17 @@ let package = Package( ) ], dependencies: [ - .package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.10.0") + .package(url: "https://github.com/gonzalezreal/NetworkImage", from: "6.0.0"), + .package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.10.0"), ], targets: [ .target(name: "cmark-gfm"), .target( name: "MarkdownUI", - dependencies: ["cmark-gfm"] + dependencies: [ + "cmark-gfm", + .product(name: "NetworkImage", package: "NetworkImage"), + ] ), .testTarget( name: "MarkdownUITests", diff --git a/Sources/MarkdownUI/Extensibility/AssetImageProvider.swift b/Sources/MarkdownUI/Extensibility/AssetImageProvider.swift index 8220b1fb..a88387c4 100644 --- a/Sources/MarkdownUI/Extensibility/AssetImageProvider.swift +++ b/Sources/MarkdownUI/Extensibility/AssetImageProvider.swift @@ -58,3 +58,19 @@ extension ImageProvider where Self == AssetImageProvider { .init() } } + +#if canImport(UIKit) + private typealias PlatformImage = UIImage +#elseif os(macOS) + private typealias PlatformImage = NSImage +#endif + +extension Image { + fileprivate init(platformImage: PlatformImage) { + #if canImport(UIKit) + self.init(uiImage: platformImage) + #elseif os(macOS) + self.init(nsImage: platformImage) + #endif + } +} diff --git a/Sources/MarkdownUI/Extensibility/DefaultImageProvider.swift b/Sources/MarkdownUI/Extensibility/DefaultImageProvider.swift index ffc3806d..cce0c086 100644 --- a/Sources/MarkdownUI/Extensibility/DefaultImageProvider.swift +++ b/Sources/MarkdownUI/Extensibility/DefaultImageProvider.swift @@ -1,17 +1,20 @@ +import NetworkImage import SwiftUI /// The default image provider, which loads images from the network. public struct DefaultImageProvider: ImageProvider { - private let urlSession: URLSession - - /// Creates a default image provider. - /// - Parameter urlSession: An `URLSession` instance to load images. - public init(urlSession: URLSession = .shared) { - self.urlSession = urlSession - } - public func makeImage(url: URL?) -> some View { - DefaultImageView(url: url, urlSession: self.urlSession) + NetworkImage(url: url) { state in + switch state { + case .empty, .failure: + Color.clear + .frame(width: 0, height: 0) + case .success(let image, let idealSize): + ResizeToFit(idealSize: idealSize) { + image.resizable() + } + } + } } } diff --git a/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageLoader.swift b/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageLoader.swift deleted file mode 100644 index 4d46a91d..00000000 --- a/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageLoader.swift +++ /dev/null @@ -1,56 +0,0 @@ -import SwiftUI - -final class DefaultImageLoader { - static let shared = DefaultImageLoader() - - private let cache = NSCache() - - private init() {} - - func image(with url: URL, urlSession: URLSession) async throws -> PlatformImage { - if let image = self.cache.object(forKey: url as NSURL) { - return image - } - - let (data, response) = try await urlSession.data(from: url) - - guard let statusCode = (response as? HTTPURLResponse)?.statusCode, - 200..<300 ~= statusCode - else { - throw URLError(.badServerResponse) - } - - guard let image = PlatformImage.decode(from: data) else { - throw URLError(.cannotDecodeContentData) - } - - self.cache.setObject(image, forKey: url as NSURL) - - return image - } -} - -extension PlatformImage { - fileprivate static func decode(from data: Data) -> PlatformImage? { - #if canImport(UIKit) - guard let image = UIImage(data: data) else { - return nil - } - return image - #elseif os(macOS) - guard let bitmapImageRep = NSBitmapImageRep(data: data) else { - return nil - } - - let image = NSImage( - size: NSSize( - width: bitmapImageRep.pixelsWide, - height: bitmapImageRep.pixelsHigh - ) - ) - - image.addRepresentation(bitmapImageRep) - return image - #endif - } -} diff --git a/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageView.swift b/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageView.swift deleted file mode 100644 index 118519f8..00000000 --- a/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageView.swift +++ /dev/null @@ -1,23 +0,0 @@ -import SwiftUI - -struct DefaultImageView: View { - @StateObject private var viewModel = DefaultImageViewModel() - - let url: URL? - let urlSession: URLSession - - var body: some View { - switch self.viewModel.state { - case .notRequested, .loading, .failure: - Color.clear - .frame(width: 0, height: 0) - .task(id: self.url) { - await self.viewModel.task(url: self.url, urlSession: self.urlSession) - } - case .success(let image, let size): - ResizeToFit(idealSize: size) { - image.resizable() - } - } - } -} diff --git a/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageViewModel.swift b/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageViewModel.swift deleted file mode 100644 index 472ad331..00000000 --- a/Sources/MarkdownUI/Extensibility/DefaultImageView/DefaultImageViewModel.swift +++ /dev/null @@ -1,33 +0,0 @@ -import SwiftUI - -final class DefaultImageViewModel: ObservableObject { - enum State: Equatable { - case notRequested - case loading - case success(Image, CGSize) - case failure - } - - @Published private(set) var state: State = .notRequested - private let imageLoader: DefaultImageLoader = .shared - - @MainActor func task(url: URL?, urlSession: URLSession) async { - guard case .notRequested = state else { - return - } - - guard let url = url else { - self.state = .failure - return - } - - self.state = .loading - - do { - let image = try await self.imageLoader.image(with: url, urlSession: urlSession) - self.state = .success(.init(platformImage: image), image.size) - } catch { - self.state = .failure - } - } -} diff --git a/Sources/MarkdownUI/Extensibility/DefaultInlineImageProvider.swift b/Sources/MarkdownUI/Extensibility/DefaultInlineImageProvider.swift index da15910c..a4a266d1 100644 --- a/Sources/MarkdownUI/Extensibility/DefaultInlineImageProvider.swift +++ b/Sources/MarkdownUI/Extensibility/DefaultInlineImageProvider.swift @@ -1,19 +1,13 @@ +import NetworkImage import SwiftUI /// The default inline image provider, which loads images from the network. public struct DefaultInlineImageProvider: InlineImageProvider { - private let urlSession: URLSession - - /// Creates a default inline image provider. - /// - Parameter urlSession: An `URLSession` instance to load images. - public init(urlSession: URLSession = .shared) { - self.urlSession = urlSession - } - public func image(with url: URL, label: String) async throws -> Image { try await Image( - platformImage: DefaultImageLoader.shared - .image(with: url, urlSession: self.urlSession) + DefaultNetworkImageLoader.shared.image(from: url), + scale: 1, + label: Text(label) ) } } diff --git a/Sources/MarkdownUI/Extensibility/Image+PlatformImage.swift b/Sources/MarkdownUI/Extensibility/Image+PlatformImage.swift deleted file mode 100644 index a6866c88..00000000 --- a/Sources/MarkdownUI/Extensibility/Image+PlatformImage.swift +++ /dev/null @@ -1,17 +0,0 @@ -import SwiftUI - -#if canImport(UIKit) - typealias PlatformImage = UIImage -#elseif os(macOS) - typealias PlatformImage = NSImage -#endif - -extension Image { - init(platformImage: PlatformImage) { - #if canImport(UIKit) - self.init(uiImage: platformImage) - #elseif os(macOS) - self.init(nsImage: platformImage) - #endif - } -} diff --git a/Sources/MarkdownUI/Utility/Deprecations.swift b/Sources/MarkdownUI/Utility/Deprecations.swift index a0229ca4..d05a8864 100644 --- a/Sources/MarkdownUI/Utility/Deprecations.swift +++ b/Sources/MarkdownUI/Utility/Deprecations.swift @@ -1,5 +1,21 @@ import SwiftUI +// MARK: - Deprecated after 2.1.0: + +extension DefaultImageProvider { + @available(*, deprecated, message: "Use the 'default' static property") + public init(urlSession: URLSession = .shared) { + self.init() + } +} + +extension DefaultInlineImageProvider { + @available(*, deprecated, message: "Use the 'default' static property") + public init(urlSession: URLSession = .shared) { + self.init() + } +} + // MARK: - Deprecated after 2.0.2: extension BlockStyle where Configuration == BlockConfiguration { From 559dd00a4d236885227824ebf67ac7bde7f99c2c Mon Sep 17 00:00:00 2001 From: Tomas Srna Date: Sun, 10 Sep 2023 08:29:11 +0200 Subject: [PATCH 8/9] Add `MarkdownContent` HTML rendering (#253) --- Sources/MarkdownUI/DSL/Blocks/MarkdownContent.swift | 5 +++++ Sources/MarkdownUI/Parser/MarkdownParser.swift | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/Sources/MarkdownUI/DSL/Blocks/MarkdownContent.swift b/Sources/MarkdownUI/DSL/Blocks/MarkdownContent.swift index 65a60068..7bcf9fa2 100644 --- a/Sources/MarkdownUI/DSL/Blocks/MarkdownContent.swift +++ b/Sources/MarkdownUI/DSL/Blocks/MarkdownContent.swift @@ -108,4 +108,9 @@ public struct MarkdownContent: Equatable, MarkdownContentProtocol { let result = self.blocks.renderPlainText() return result.hasSuffix("\n") ? String(result.dropLast()) : result } + + /// Renders this Markdown content value as HTML code. + public func renderHTML() -> String { + self.blocks.renderHTML() + } } diff --git a/Sources/MarkdownUI/Parser/MarkdownParser.swift b/Sources/MarkdownUI/Parser/MarkdownParser.swift index 45c8165b..ff6b6655 100644 --- a/Sources/MarkdownUI/Parser/MarkdownParser.swift +++ b/Sources/MarkdownUI/Parser/MarkdownParser.swift @@ -20,6 +20,12 @@ extension Array where Element == BlockNode { String(cString: cmark_render_plaintext(document, CMARK_OPT_DEFAULT, 0)) } ?? "" } + + func renderHTML() -> String { + UnsafeNode.makeDocument(self) { document in + String(cString: cmark_render_html(document, CMARK_OPT_DEFAULT, nil)) + } ?? "" + } } extension BlockNode { From 5df8a4adedd6ae4eb2455ef60ff75183984daeb8 Mon Sep 17 00:00:00 2001 From: Guille Gonzalez Date: Sun, 10 Sep 2023 09:35:58 +0200 Subject: [PATCH 9/9] Enable text selection in demo (#259) --- Examples/Demo/Demo/DemoView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Examples/Demo/Demo/DemoView.swift b/Examples/Demo/Demo/DemoView.swift index 6e071c98..ea74b167 100644 --- a/Examples/Demo/Demo/DemoView.swift +++ b/Examples/Demo/Demo/DemoView.swift @@ -67,6 +67,7 @@ struct DemoView: View { } self.content + .textSelection(.enabled) .markdownTheme(self.themeOption.theme) // Some themes may have a custom background color that we need to set as // the row's background color.