Skip to content

Commit c51f1a1

Browse files
authored
Add Markdown content to block configuration (#220)
* Add methods to access child content and render plain text * Add the Markdown content to the block configuration * Fix building with Swift 5.8 * Deprecate block-style methods with a label closure * Fix deprecation warnings * Update documentation
1 parent b12b137 commit c51f1a1

37 files changed

+640
-222
lines changed

Examples/Demo/Demo/HeadingsView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ struct HeadingsView: View {
2525
Section("Customization Example") {
2626
Markdown("# One Big Header")
2727
}
28-
.markdownBlockStyle(\.heading1) { label in
29-
label
28+
.markdownBlockStyle(\.heading1) { configuration in
29+
configuration.label
3030
.markdownMargin(top: .em(1), bottom: .em(1))
3131
.markdownTextStyle {
3232
FontFamily(.custom("Trebuchet MS"))

Examples/Demo/Demo/ImagesView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ struct ImagesView: View {
4343
Section("Customization Example") {
4444
Markdown(self.content)
4545
}
46-
.markdownBlockStyle(\.image) { label in
47-
label
46+
.markdownBlockStyle(\.image) { configuration in
47+
configuration.label
4848
.clipShape(RoundedRectangle(cornerRadius: 8))
4949
.shadow(radius: 8, y: 8)
5050
.markdownMargin(top: .em(1.6), bottom: .em(1.6))

Examples/Demo/Demo/QuotesView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ struct QuotesView: View {
1818
Section("Customization Example") {
1919
Markdown(self.content)
2020
}
21-
.markdownBlockStyle(\.blockquote) { label in
22-
label
21+
.markdownBlockStyle(\.blockquote) { configuration in
22+
configuration.label
2323
.padding()
2424
.markdownTextStyle {
2525
FontCapsVariant(.lowercaseSmallCaps)

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,13 +226,14 @@ extension Theme {
226226
ForegroundColor(.purple)
227227
}
228228
// More text styles...
229-
.paragraph { label in
230-
label
229+
.paragraph { configuration in
230+
configuration.label
231231
.relativeLineSpacing(.em(0.25))
232232
.markdownMargin(top: 0, bottom: 16)
233233
}
234-
.listItem { label in
235-
label.markdownMargin(top: .em(0.25))
234+
.listItem { configuration in
235+
configuration.label
236+
.markdownMargin(top: .em(0.25))
236237
}
237238
// More block styles...
238239
}

Sources/MarkdownUI/DSL/Blocks/MarkdownContent.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,27 @@ public protocol MarkdownContentProtocol {
6060
/// }
6161
/// ```
6262
public struct MarkdownContent: Equatable, MarkdownContentProtocol {
63+
/// Returns a Markdown content value with the sum of the contents of all the container blocks
64+
/// present in this content.
65+
///
66+
/// You can use this property to access the contents of a blockquote or a list. Returns `nil` if
67+
/// there are no container blocks.
68+
public var childContent: MarkdownContent? {
69+
let children = self.blocks.map(\.children).flatMap { $0 }
70+
return children.isEmpty ? nil : .init(blocks: children)
71+
}
72+
6373
public var _markdownContent: MarkdownContent { self }
6474
let blocks: [BlockNode]
6575

6676
init(blocks: [BlockNode] = []) {
6777
self.blocks = blocks
6878
}
6979

80+
init(block: BlockNode) {
81+
self.init(blocks: [block])
82+
}
83+
7084
init(_ components: [MarkdownContentProtocol]) {
7185
self.init(blocks: components.map(\._markdownContent).flatMap(\.blocks))
7286
}
@@ -88,4 +102,10 @@ public struct MarkdownContent: Equatable, MarkdownContentProtocol {
88102
let result = self.blocks.renderMarkdown()
89103
return result.hasSuffix("\n") ? String(result.dropLast()) : result
90104
}
105+
106+
/// Renders this Markdown content value as plain text.
107+
public func renderPlainText() -> String {
108+
let result = self.blocks.renderPlainText()
109+
return result.hasSuffix("\n") ? String(result.dropLast()) : result
110+
}
91111
}

Sources/MarkdownUI/Documentation.docc/Articles/GettingStarted.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,14 @@ extension Theme {
183183
ForegroundColor(.purple)
184184
}
185185
// More text styles...
186-
.paragraph { label in
187-
label
186+
.paragraph { configuration in
187+
configuration.label
188188
.relativeLineSpacing(.em(0.25))
189189
.markdownMargin(top: 0, bottom: 16)
190190
}
191-
.listItem { label in
192-
label.markdownMargin(top: .em(0.25))
191+
.listItem { configuration in
192+
configuration.label
193+
.markdownMargin(top: .em(0.25))
193194
}
194195
// More block styles...
195196
}

Sources/MarkdownUI/Parser/BlockNode.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ enum BlockNode: Hashable {
1414
}
1515

1616
extension BlockNode {
17+
var children: [BlockNode] {
18+
switch self {
19+
case .blockquote(let children):
20+
return children
21+
case .bulletedList(_, let items):
22+
return items.map(\.children).flatMap { $0 }
23+
case .numberedList(_, _, let items):
24+
return items.map(\.children).flatMap { $0 }
25+
case .taskList(_, let items):
26+
return items.map(\.children).flatMap { $0 }
27+
default:
28+
return []
29+
}
30+
}
31+
1732
var isParagraph: Bool {
1833
guard case .paragraph = self else { return false }
1934
return true

Sources/MarkdownUI/Parser/MarkdownParser.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ extension Array where Element == BlockNode {
1414
String(cString: cmark_render_commonmark(document, CMARK_OPT_DEFAULT, 0))
1515
} ?? ""
1616
}
17+
18+
func renderPlainText() -> String {
19+
UnsafeNode.makeDocument(self) { document in
20+
String(cString: cmark_render_plaintext(document, CMARK_OPT_DEFAULT, 0))
21+
} ?? ""
22+
}
1723
}
1824

1925
extension BlockNode {

Sources/MarkdownUI/Theme/BlockStyle/BlockConfiguration.swift

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,14 @@ public struct BlockConfiguration {
1515
public let body: AnyView
1616
}
1717

18-
/// The Markdown block content.
18+
/// The Markdown block view.
1919
public let label: Label
20-
}
2120

22-
extension BlockStyle where Configuration == BlockConfiguration {
23-
/// Creates a block style that customizes a block by applying the given body.
24-
/// - Parameter body: A view builder that returns the customized block.
25-
public init<Body: View>(
26-
@ViewBuilder body: @escaping (_ label: BlockConfiguration.Label) -> Body
27-
) {
28-
self.init { configuration in
29-
body(configuration.label)
30-
}
31-
}
32-
33-
/// Creates a block style that returns the block content without applying any customization.
34-
public init() {
35-
self.init { $0 }
36-
}
21+
/// The content of the Markdown block.
22+
///
23+
/// This property provides access to different representations of the block content.
24+
/// For example, you can use ``MarkdownContent/renderMarkdown()``
25+
/// to get the Markdown formatted text or ``MarkdownContent/renderPlainText()``
26+
/// to get the plain text of the block content.
27+
public let content: MarkdownContent
3728
}

Sources/MarkdownUI/Theme/BlockStyle/TableCellConfiguration.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ public struct TableCellConfiguration {
2020
/// The table cell column index.
2121
public let column: Int
2222

23-
/// The table cell content.
23+
/// The table cell view.
2424
public let label: Label
25+
26+
/// The table cell content.
27+
public let content: MarkdownContent
2528
}

0 commit comments

Comments
 (0)