Skip to content
Open
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
10 changes: 6 additions & 4 deletions Examples/Demo/Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -342,7 +342,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 16.2;
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
Expand All @@ -360,14 +360,15 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"Demo/Preview Content\"";
DEVELOPMENT_TEAM = 6Q6JDZK895;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -389,14 +390,15 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"Demo/Preview Content\"";
DEVELOPMENT_TEAM = 6Q6JDZK895;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
38 changes: 33 additions & 5 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 10 additions & 9 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
// swift-tools-version:5.6
// swift-tools-version:6.2

import PackageDescription

let package = Package(
name: "swift-markdown-ui",
platforms: [
.macOS(.v12),
.iOS(.v15),
.tvOS(.v15),
.macCatalyst(.v15),
.watchOS(.v8),
.macOS(.v26),
.iOS(.v26),
.tvOS(.v26),
.macCatalyst(.v26),
.watchOS(.v26),
.visionOS(.v26),
],
products: [
.library(
Expand All @@ -18,9 +19,9 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/gonzalezreal/NetworkImage", from: "6.0.0"),
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.10.0"),
.package(url: "https://github.com/swiftlang/swift-cmark", from: "0.4.0"),
.package(url: "https://github.com/gonzalezreal/NetworkImage", from: "6.0.1"),
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.18.7"),
.package(url: "https://github.com/swiftlang/swift-cmark", from: "0.5.0"),
],
targets: [
.target(
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ You can use the built-in themes, create your own or override specific text and b

You can use MarkdownUI on the following platforms:

- macOS 12.0+
- iOS 15.0+
- tvOS 15.0+
- watchOS 8.0+
- macOS 26.0+
- iOS 26.0+
- tvOS 26.0+
- watchOS 26.0+
- visionOS 26.0+

Some features, like displaying tables or multi-image paragraphs, require macOS 13.0+, iOS 16.0+,
tvOS 16.0+, and watchOS 9.0+.
This library has been updated for Swift 6.2 and the latest Apple platforms (2025).

## Getting started

Expand Down
2 changes: 1 addition & 1 deletion Sources/MarkdownUI/DSL/Inlines/SoftBreak.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public struct SoftBreak: InlineContentProtocol {
}

extension SoftBreak {
public enum Mode {
public enum Mode: Sendable {
/// Treat a soft break as a space
case space

Expand Down
8 changes: 4 additions & 4 deletions Sources/MarkdownUI/Extensibility/AssetImageProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import SwiftUI
/// }
/// .markdownImageProvider(.asset)
/// ```
public struct AssetImageProvider: ImageProvider {
private let name: (URL) -> String
public struct AssetImageProvider: ImageProvider, Sendable {
private let name: @Sendable (URL) -> String
private let bundle: Bundle?

/// Creates an asset image provider.
/// - Parameters:
/// - name: A closure that extracts the image resource name from the URL in the Markdown content.
/// - bundle: The bundle where the image resources are located. Specify `nil` to search the apps main bundle.
/// - bundle: The bundle where the image resources are located. Specify `nil` to search the app's main bundle.
public init(
name: @escaping (URL) -> String = \.lastPathComponent,
name: @escaping @Sendable (URL) -> String = \.lastPathComponent,
bundle: Bundle? = nil
) {
self.name = name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import SwiftUI

/// An inline image provider that loads images from resources located in an app or a module.
public struct AssetInlineImageProvider: InlineImageProvider {
private let name: (URL) -> String
private let name: @Sendable (URL) -> String
private let bundle: Bundle?

/// Creates an asset inline image provider.
/// - Parameters:
/// - name: A closure that extracts the image resource name from the URL in the Markdown content.
/// - bundle: The bundle where the image resources are located. Specify `nil` to search the apps main bundle.
/// - bundle: The bundle where the image resources are located. Specify `nil` to search the app's main bundle.
public init(
name: @escaping (URL) -> String = \.lastPathComponent,
name: @escaping @Sendable (URL) -> String = \.lastPathComponent,
bundle: Bundle? = nil
) {
self.name = name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import SwiftUI
///
/// To configure the current code syntax highlighter for a view hierarchy, use the
/// `markdownCodeSyntaxHighlighter(_:)` modifier.
public protocol CodeSyntaxHighlighter {
public protocol CodeSyntaxHighlighter: Sendable {
/// Returns a text view configured with the syntax highlighted code.
/// - Parameters:
/// - code: The code block.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import NetworkImage
import SwiftUI

/// The default image provider, which loads images from the network.
public struct DefaultImageProvider: ImageProvider {
public struct DefaultImageProvider: ImageProvider, Sendable {
public func makeImage(url: URL?) -> some View {
NetworkImage(url: url) { state in
switch state {
Expand Down
10 changes: 5 additions & 5 deletions Sources/MarkdownUI/Extensibility/ImageProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ public protocol ImageProvider {
@ViewBuilder func makeImage(url: URL?) -> Body
}

struct AnyImageProvider: ImageProvider {
private let _makeImage: (URL?) -> AnyView
struct AnyImageProvider: ImageProvider, @unchecked Sendable {
private let _makeImage: @Sendable (URL?) -> AnyView

init<I: ImageProvider>(_ imageProvider: I) {
self._makeImage = {
AnyView(imageProvider.makeImage(url: $0))
init<I: ImageProvider>(_ imageProvider: I) where I: Sendable {
self._makeImage = { url in
AnyView(imageProvider.makeImage(url: url))
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/MarkdownUI/Extensibility/InlineImageProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import SwiftUI
///
/// To configure the current inline image provider for a view hierarchy,
/// use the `markdownInlineImageProvider(_:)` modifier.
public protocol InlineImageProvider {
public protocol InlineImageProvider: Sendable {
/// Returns an image for the given URL.
///
/// ``Markdown`` views call this method to load images within a line of text.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import SwiftUI
public struct BlockConfiguration {
/// A type-erased view of a Markdown block.
public struct Label: View {
init<L: View>(_ label: L) {
public init<L: View>(_ label: L) {
self.body = AnyView(label)
}

Expand Down
14 changes: 7 additions & 7 deletions Sources/MarkdownUI/Theme/BlockStyle/BlockStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,25 @@ import SwiftUI
/// ```
///
/// ![](CustomBlockquote)
public struct BlockStyle<Configuration> {
private let body: (Configuration) -> AnyView
public struct BlockStyle<Configuration>: @unchecked Sendable {
private let body: @Sendable @MainActor (Configuration) -> AnyView

/// Creates a block style that customizes a block by applying the given body.
/// - Parameter body: A view builder that returns the customized block.
public init<Body: View>(@ViewBuilder body: @escaping (_ configuration: Configuration) -> Body) {
self.body = { AnyView(body($0)) }
public init<Body: View>(@ViewBuilder body: @escaping @Sendable @MainActor (_ configuration: Configuration) -> Body) {
self.body = { @Sendable @MainActor in AnyView(body($0)) }
}

func makeBody(configuration: Configuration) -> AnyView {
@MainActor func makeBody(configuration: Configuration) -> AnyView {
self.body(configuration)
}
}

extension BlockStyle where Configuration == Void {
/// Creates a block style for a block with no content, like a thematic break.
/// - Parameter body: A view builder that returns the customized block.
public init<Body: View>(@ViewBuilder body: @escaping () -> Body) {
self.init { _ in
public init<Body: View>(@ViewBuilder body: @escaping @Sendable @MainActor () -> Body) {
self.init { @Sendable @MainActor _ in
body()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ import SwiftUI
/// ```
///
/// ![](CustomTableBackground)
public struct TableBackgroundStyle {
let background: (_ row: Int, _ column: Int) -> AnyShapeStyle
public struct TableBackgroundStyle: Sendable {
let background: @Sendable (_ row: Int, _ column: Int) -> AnyShapeStyle

/// Creates a table background style that customizes table backgrounds by applying a given closure
/// to the background of each cell.
/// - Parameter background: A closure that returns a shape style for a given table cell location.
public init<S: ShapeStyle>(background: @escaping (_ row: Int, _ column: Int) -> S) {
public init<S: ShapeStyle>(background: @escaping @Sendable (_ row: Int, _ column: Int) -> S) {
self.background = { row, column in
AnyShapeStyle(background(row, column))
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/MarkdownUI/Theme/BlockStyle/TableBorderStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import SwiftUI
/// ```
///
/// ![](CustomTableBorders)
public struct TableBorderStyle {
public struct TableBorderStyle: Sendable {
/// The visible table borders.
public var visibleBorders: TableBorderSelector

Expand Down
Loading