Skip to content
Merged
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
4 changes: 2 additions & 2 deletions Examples/Demo/Demo/HeadingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ struct HeadingsView: View {
Section("Customization Example") {
Markdown("# One Big Header")
}
.markdownBlockStyle(\.heading1) { label in
label
.markdownBlockStyle(\.heading1) { configuration in
configuration.label
.markdownMargin(top: .em(1), bottom: .em(1))
.markdownTextStyle {
FontFamily(.custom("Trebuchet MS"))
Expand Down
4 changes: 2 additions & 2 deletions Examples/Demo/Demo/ImagesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ struct ImagesView: View {
Section("Customization Example") {
Markdown(self.content)
}
.markdownBlockStyle(\.image) { label in
label
.markdownBlockStyle(\.image) { configuration in
configuration.label
.clipShape(RoundedRectangle(cornerRadius: 8))
.shadow(radius: 8, y: 8)
.markdownMargin(top: .em(1.6), bottom: .em(1.6))
Expand Down
4 changes: 2 additions & 2 deletions Examples/Demo/Demo/QuotesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ struct QuotesView: View {
Section("Customization Example") {
Markdown(self.content)
}
.markdownBlockStyle(\.blockquote) { label in
label
.markdownBlockStyle(\.blockquote) { configuration in
configuration.label
.padding()
.markdownTextStyle {
FontCapsVariant(.lowercaseSmallCaps)
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,14 @@ extension Theme {
ForegroundColor(.purple)
}
// More text styles...
.paragraph { label in
label
.paragraph { configuration in
configuration.label
.relativeLineSpacing(.em(0.25))
.markdownMargin(top: 0, bottom: 16)
}
.listItem { label in
label.markdownMargin(top: .em(0.25))
.listItem { configuration in
configuration.label
.markdownMargin(top: .em(0.25))
}
// More block styles...
}
Expand Down
20 changes: 20 additions & 0 deletions Sources/MarkdownUI/DSL/Blocks/MarkdownContent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,27 @@ public protocol MarkdownContentProtocol {
/// }
/// ```
public struct MarkdownContent: Equatable, MarkdownContentProtocol {
/// Returns a Markdown content value with the sum of the contents of all the container blocks
/// present in this content.
///
/// You can use this property to access the contents of a blockquote or a list. Returns `nil` if
/// there are no container blocks.
public var childContent: MarkdownContent? {
let children = self.blocks.map(\.children).flatMap { $0 }
return children.isEmpty ? nil : .init(blocks: children)
}

public var _markdownContent: MarkdownContent { self }
let blocks: [BlockNode]

init(blocks: [BlockNode] = []) {
self.blocks = blocks
}

init(block: BlockNode) {
self.init(blocks: [block])
}

init(_ components: [MarkdownContentProtocol]) {
self.init(blocks: components.map(\._markdownContent).flatMap(\.blocks))
}
Expand All @@ -88,4 +102,10 @@ public struct MarkdownContent: Equatable, MarkdownContentProtocol {
let result = self.blocks.renderMarkdown()
return result.hasSuffix("\n") ? String(result.dropLast()) : result
}

/// Renders this Markdown content value as plain text.
public func renderPlainText() -> String {
let result = self.blocks.renderPlainText()
return result.hasSuffix("\n") ? String(result.dropLast()) : result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,14 @@ extension Theme {
ForegroundColor(.purple)
}
// More text styles...
.paragraph { label in
label
.paragraph { configuration in
configuration.label
.relativeLineSpacing(.em(0.25))
.markdownMargin(top: 0, bottom: 16)
}
.listItem { label in
label.markdownMargin(top: .em(0.25))
.listItem { configuration in
configuration.label
.markdownMargin(top: .em(0.25))
}
// More block styles...
}
Expand Down
15 changes: 15 additions & 0 deletions Sources/MarkdownUI/Parser/BlockNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ enum BlockNode: Hashable {
}

extension BlockNode {
var children: [BlockNode] {
switch self {
case .blockquote(let children):
return children
case .bulletedList(_, let items):
return items.map(\.children).flatMap { $0 }
case .numberedList(_, _, let items):
return items.map(\.children).flatMap { $0 }
case .taskList(_, let items):
return items.map(\.children).flatMap { $0 }
default:
return []
}
}

var isParagraph: Bool {
guard case .paragraph = self else { return false }
return true
Expand Down
6 changes: 6 additions & 0 deletions Sources/MarkdownUI/Parser/MarkdownParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ extension Array where Element == BlockNode {
String(cString: cmark_render_commonmark(document, CMARK_OPT_DEFAULT, 0))
} ?? ""
}

func renderPlainText() -> String {
UnsafeNode.makeDocument(self) { document in
String(cString: cmark_render_plaintext(document, CMARK_OPT_DEFAULT, 0))
} ?? ""
}
}

extension BlockNode {
Expand Down
25 changes: 8 additions & 17 deletions Sources/MarkdownUI/Theme/BlockStyle/BlockConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,14 @@ public struct BlockConfiguration {
public let body: AnyView
}

/// The Markdown block content.
/// The Markdown block view.
public let label: Label
}

extension BlockStyle where Configuration == BlockConfiguration {
/// 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 (_ label: BlockConfiguration.Label) -> Body
) {
self.init { configuration in
body(configuration.label)
}
}

/// Creates a block style that returns the block content without applying any customization.
public init() {
self.init { $0 }
}
/// The content of the Markdown block.
///
/// This property provides access to different representations of the block content.
/// For example, you can use ``MarkdownContent/renderMarkdown()``
/// to get the Markdown formatted text or ``MarkdownContent/renderPlainText()``
/// to get the plain text of the block content.
public let content: MarkdownContent
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public struct TableCellConfiguration {
/// The table cell column index.
public let column: Int

/// The table cell content.
/// The table cell view.
public let label: Label

/// The table cell content.
public let content: MarkdownContent
}
37 changes: 19 additions & 18 deletions Sources/MarkdownUI/Theme/Theme+Basic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,61 +19,61 @@ extension Theme {
FontFamilyVariant(.monospaced)
FontSize(.em(0.94))
}
.heading1 { label in
label
.heading1 { configuration in
configuration.label
.markdownMargin(top: .rem(1.5), bottom: .rem(1))
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(2))
}
}
.heading2 { label in
label
.heading2 { configuration in
configuration.label
.markdownMargin(top: .rem(1.5), bottom: .rem(1))
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(1.5))
}
}
.heading3 { label in
label
.heading3 { configuration in
configuration.label
.markdownMargin(top: .rem(1.5), bottom: .rem(1))
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(1.17))
}
}
.heading4 { label in
label
.heading4 { configuration in
configuration.label
.markdownMargin(top: .rem(1.5), bottom: .rem(1))
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(1))
}
}
.heading5 { label in
label
.heading5 { configuration in
configuration.label
.markdownMargin(top: .rem(1.5), bottom: .rem(1))
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(0.83))
}
}
.heading6 { label in
label
.heading6 { configuration in
configuration.label
.markdownMargin(top: .rem(1.5), bottom: .rem(1))
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(0.67))
}
}
.paragraph { label in
label
.paragraph { configuration in
configuration.label
.relativeLineSpacing(.em(0.15))
.markdownMargin(top: .zero, bottom: .em(1))
}
.blockquote { label in
label
.blockquote { configuration in
configuration.label
.markdownTextStyle {
FontStyle(.italic)
}
Expand All @@ -92,8 +92,9 @@ extension Theme {
}
.markdownMargin(top: .zero, bottom: .em(1))
}
.table { label in
label.markdownMargin(top: .zero, bottom: .em(1))
.table { configuration in
configuration.label
.markdownMargin(top: .zero, bottom: .em(1))
}
.tableCell { configuration in
configuration.label
Expand Down
45 changes: 23 additions & 22 deletions Sources/MarkdownUI/Theme/Theme+DocC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,65 +21,65 @@ extension Theme {
.link {
ForegroundColor(.link)
}
.heading1 { label in
label
.heading1 { configuration in
configuration.label
.markdownMargin(top: .em(0.8), bottom: .zero)
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(2))
}
}
.heading2 { label in
label
.heading2 { configuration in
configuration.label
.relativeLineSpacing(.em(0.0625))
.markdownMargin(top: .em(1.6), bottom: .zero)
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(1.88235))
}
}
.heading3 { label in
label
.heading3 { configuration in
configuration.label
.relativeLineSpacing(.em(0.07143))
.markdownMargin(top: .em(1.6), bottom: .zero)
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(1.64706))
}
}
.heading4 { label in
label
.heading4 { configuration in
configuration.label
.relativeLineSpacing(.em(0.083335))
.markdownMargin(top: .em(1.6), bottom: .zero)
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(1.41176))
}
}
.heading5 { label in
label
.heading5 { configuration in
configuration.label
.relativeLineSpacing(.em(0.09091))
.markdownMargin(top: .em(1.6), bottom: .zero)
.markdownTextStyle {
FontWeight(.semibold)
FontSize(.em(1.29412))
}
}
.heading6 { label in
label
.heading6 { configuration in
configuration.label
.relativeLineSpacing(.em(0.235295))
.markdownMargin(top: .em(1.6), bottom: .zero)
.markdownTextStyle {
FontWeight(.semibold)
}
}
.paragraph { label in
label
.paragraph { configuration in
configuration.label
.relativeLineSpacing(.em(0.235295))
.markdownMargin(top: .em(0.8), bottom: .zero)
}
.blockquote { label in
label
.blockquote { configuration in
configuration.label
.relativePadding(length: .rem(0.94118))
.frame(maxWidth: .infinity, alignment: .leading)
.background {
Expand Down Expand Up @@ -107,21 +107,22 @@ extension Theme {
.clipShape(.container)
.markdownMargin(top: .em(0.8), bottom: .zero)
}
.image { label in
label
.image { configuration in
configuration.label
.frame(maxWidth: .infinity)
.markdownMargin(top: .em(1.6), bottom: .em(1.6))
}
.listItem { label in
label.markdownMargin(top: .em(0.8))
.listItem { configuration in
configuration.label
.markdownMargin(top: .em(0.8))
}
.taskListMarker { _ in
// DocC renders task lists as bullet lists
ListBullet.disc
.relativeFrame(minWidth: .em(1.5), alignment: .trailing)
}
.table { label in
label
.table { configuration in
configuration.label
.markdownTableBorderStyle(.init(.horizontalBorders, color: .grid))
.markdownMargin(top: .em(1.6), bottom: .zero)
}
Expand Down
Loading