Skip to content

Commit 4493c14

Browse files
Merge remote-tracking branch 'refs/remotes/origin/main'
Conflicts: Sources/FlexibleAttributedText/FlexibleAttributedTextImpl+iOS.swift
2 parents a030a52 + 15490b3 commit 4493c14

File tree

11 files changed

+96
-83
lines changed

11 files changed

+96
-83
lines changed

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
FlexibleAttributedText is a Swift µpackage that provides `NSAttributedString` rendering in SwiftUI by wrapping either an `NSTextView` or a `UITextView` depending on the platform, which supports flexible views.
44

5+
56
## Supported Platforms
67

78
* macOS 11.0+
@@ -10,12 +11,12 @@ FlexibleAttributedText is a Swift µpackage that provides `NSAttributedString` r
1011

1112
## Usage
1213
```swift
13-
import AttributedText
14+
import FlexibleAttributedText
1415
import SwiftUI
1516

1617
struct ContentView: View {
1718
var body: some View {
18-
AttributedText {
19+
FlexibleAttributedText {
1920
let result = NSMutableAttributedString(
2021
string: """
2122
After the Big Bang
@@ -63,14 +64,14 @@ struct ContentView: View {
6364
}
6465
```
6566

66-
An `AttributedText` view takes all the available width and adjusts its height to fit the contents.
67+
An `FlexibleAttributedText` view takes all the available width and adjusts its height to fit the contents.
6768

6869
To use dynamic width, pass down an argument `flexibleWidth` with value `true` to enable flexible width.
6970

7071
To change the text alignment or line break mode, you need to add a `.paragraphStyle` attribute to the attributed string.
7172

7273
## Installation
73-
You can add AttributedText to an Xcode project by adding it as a package dependency.
74+
You can add FlexibleAttributedText to an Xcode project by adding it as a package dependency.
7475
1. From the **File** menu, select **Swift Packages › Add Package Dependency…**
75-
1. Enter `https://github.com/gonzalezreal/AttributedText` into the package repository URL text field
76-
1. Link **AttributedText** to your application target
76+
1. Enter `https://github.com/wilmaplus/FlexibleAttributedText` into the package repository URL text field
77+
1. Link **FlexibleAttributedText** to your application target

Sources/FlexibleAttributedText/FlexibleAttributedText.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ public struct FlexibleAttributedText: View {
1414
/// - onOpenLink: The action to perform when the user opens a link in the text. When not specified,
1515
/// the view opens the links using the `OpenURLAction` from the environment.
1616
/// - flexibleWidth: Flexible Width
17-
public init(_ attributedText: NSAttributedString, onOpenLink: ((URL) -> Void)? = nil, flexibleWidth: Bool = false) {
17+
public init(
18+
_ attributedText: NSAttributedString, onOpenLink: ((URL) -> Void)? = nil,
19+
flexibleWidth: Bool = false
20+
) {
1821
self.attributedText = attributedText
1922
self.onOpenLink = onOpenLink
20-
self.flexibleWidth = flexibleWidth
23+
self.flexibleWidth = flexibleWidth
2124
}
2225

2326
/// Creates an attributed text view.
@@ -26,7 +29,10 @@ public struct FlexibleAttributedText: View {
2629
/// - onOpenLink: The action to perform when the user opens a link in the text. When not specified,
2730
/// the view opens the links using the `OpenURLAction` from the environment.
2831
/// - flexibleWidth: Flexible Width
29-
public init(attributedText: () -> NSAttributedString, onOpenLink: ((URL) -> Void)? = nil, flexibleWidth: Bool = false) {
32+
public init(
33+
attributedText: () -> NSAttributedString, onOpenLink: ((URL) -> Void)? = nil,
34+
flexibleWidth: Bool = false
35+
) {
3036
self.init(attributedText(), onOpenLink: onOpenLink, flexibleWidth: flexibleWidth)
3137
}
3238

Sources/FlexibleAttributedText/FlexibleAttributedTextImpl+iOS.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
uiView.textContainer.lineBreakMode = NSLineBreakMode(
1414
truncationMode: context.environment.truncationMode
1515
)
16+
1617
uiView.openLink = onOpenLink ?? { context.environment.openURL($0) }
1718
uiView.invalidateIntrinsicContentSize()
1819
uiView.updateFrame()
@@ -61,9 +62,10 @@
6162

6263
override var intrinsicContentSize: CGSize {
6364
guard maxLayoutWidth > 0 else {
64-
let fixedWidth = frame.size.width
65-
let newSize = self.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
66-
return CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
65+
let fixedWidth = frame.size.width
66+
let newSize = self.sizeThatFits(
67+
CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
68+
return CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
6769
}
6870

6971
return sizeThatFits(CGSize(width: maxLayoutWidth, height: .greatestFiniteMagnitude))

Sources/FlexibleAttributedText/FlexibleAttributedTextImpl+macOS.swift

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
nsView.textContainer?.lineFragmentPadding = 0
1313
// we are setting the container's width manually
1414
nsView.textContainer?.widthTracksTextView = false
15-
nsView.delegate = context.coordinator
15+
nsView.delegate = context.coordinator
1616

1717
return nsView
1818
}
@@ -34,45 +34,46 @@
3434
}
3535
}
3636

37-
extension FlexibleAttributedTextImpl {
37+
extension FlexibleAttributedTextImpl {
3838
final class TextView: NSTextView {
39-
var maxLayoutWidth: CGFloat {
40-
get { textContainer?.containerSize.width ?? 0 }
41-
set {
42-
guard textContainer?.containerSize.width != newValue else { return }
43-
textContainer?.containerSize.width = newValue
44-
invalidateIntrinsicContentSize()
45-
}
39+
var maxLayoutWidth: CGFloat {
40+
get { textContainer?.containerSize.width ?? 0 }
41+
set {
42+
guard textContainer?.containerSize.width != newValue else { return }
43+
textContainer?.containerSize.width = newValue
44+
invalidateIntrinsicContentSize()
4645
}
47-
48-
override var intrinsicContentSize: CGSize {
49-
guard maxLayoutWidth > 0,
50-
let textContainer = self.textContainer,
51-
let layoutManager = self.layoutManager
52-
else {
53-
let fixedWidth = frame.size.width
54-
let newSize = self.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
55-
return CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
56-
}
57-
58-
layoutManager.ensureLayout(for: textContainer)
59-
return layoutManager.usedRect(for: textContainer).size
46+
}
47+
48+
override var intrinsicContentSize: CGSize {
49+
guard maxLayoutWidth > 0,
50+
let textContainer = self.textContainer,
51+
let layoutManager = self.layoutManager
52+
else {
53+
let fixedWidth = frame.size.width
54+
let newSize = self.sizeThatFits(
55+
CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
56+
return CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
6057
}
61-
62-
final class Coordinator: NSObject, NSTextViewDelegate {
63-
var openLink: ((URL) -> Void)?
64-
65-
func textView(_: NSTextView, clickedOnLink link: Any, at _: Int) -> Bool {
66-
guard let openLink = self.openLink,
67-
let url = (link as? URL) ?? (link as? String).flatMap(URL.init(string:))
68-
else {
69-
return false
70-
}
71-
72-
openLink(url)
73-
return true
74-
}
58+
59+
layoutManager.ensureLayout(for: textContainer)
60+
return layoutManager.usedRect(for: textContainer).size
61+
}
62+
63+
final class Coordinator: NSObject, NSTextViewDelegate {
64+
var openLink: ((URL) -> Void)?
65+
66+
func textView(_: NSTextView, clickedOnLink link: Any, at _: Int) -> Bool {
67+
guard let openLink = self.openLink,
68+
let url = (link as? URL) ?? (link as? String).flatMap(URL.init(string:))
69+
else {
70+
return false
71+
}
72+
73+
openLink(url)
74+
return true
7575
}
76+
}
7677
}
77-
}
78+
}
7879
#endif

Sources/FlexibleAttributedText/FlexibleAttributedTextImpl+tvOS.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242

4343
override var intrinsicContentSize: CGSize {
4444
guard maxLayoutWidth > 0 else {
45-
return sizeThatFits(CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
45+
return sizeThatFits(
46+
CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
4647
}
4748

4849
return sizeThatFits(CGSize(width: maxLayoutWidth, height: .greatestFiniteMagnitude))

Tests/FlexibleAttributedTextTests/FlexibleAttributedTextTests.swift

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,28 @@
77

88
final class FlexibleAttributedTextTests: XCTestCase {
99
struct TestView: View {
10-
var flexible: Bool = false
10+
var flexible: Bool = false
1111
var body: some View {
12-
FlexibleAttributedText(attributedText: {
13-
let result = NSMutableAttributedString(
14-
string: """
15-
Sherlock Holmes
16-
I had called upon my friend, Mr. Sherlock Holmes.
17-
"""
18-
)
12+
FlexibleAttributedText(
13+
attributedText: {
14+
let result = NSMutableAttributedString(
15+
string: """
16+
Sherlock Holmes
17+
I had called upon my friend, Mr. Sherlock Holmes.
18+
"""
19+
)
1920

20-
result.addAttributes(
21-
[.font: UIFont.preferredFont(forTextStyle: .title2)],
22-
range: NSRange(location: 0, length: 15)
23-
)
24-
result.addAttributes(
25-
[.font: UIFont.preferredFont(forTextStyle: .body)],
26-
range: NSRange(location: 15, length: 49)
27-
)
28-
return result
29-
}, onOpenLink: nil, flexibleWidth: flexible)
21+
result.addAttributes(
22+
[.font: UIFont.preferredFont(forTextStyle: .title2)],
23+
range: NSRange(location: 0, length: 15)
24+
)
25+
result.addAttributes(
26+
[.font: UIFont.preferredFont(forTextStyle: .body)],
27+
range: NSRange(location: 15, length: 49)
28+
)
29+
return result
30+
}, onOpenLink: nil, flexibleWidth: flexible
31+
)
3032
.background(Color.gray.opacity(0.5))
3133
.padding()
3234
}
@@ -62,21 +64,21 @@
6264
assertSnapshot(
6365
matching: view, as: .image(precision: precision, layout: layout), named: platformName)
6466
}
65-
66-
func testFlexible() {
67-
let view = TestView(flexible: true)
68-
.frame(minWidth: 0, maxWidth: .infinity).background(Color.red)
69-
assertSnapshot(
70-
matching: view, as: .image(precision: precision, layout: layout), named: platformName)
71-
}
72-
73-
func testFlexibleWidthWithAlignment() {
74-
let view = VStack(alignment: .leading) {
75-
TestView(flexible: true)
76-
}.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading).background(Color.red)
7767

78-
assertSnapshot(
79-
matching: view, as: .image(precision: precision, layout: layout), named: platformName)
80-
}
68+
func testFlexible() {
69+
let view = TestView(flexible: true)
70+
.frame(minWidth: 0, maxWidth: .infinity).background(Color.red)
71+
assertSnapshot(
72+
matching: view, as: .image(precision: precision, layout: layout), named: platformName)
73+
}
74+
75+
func testFlexibleWidthWithAlignment() {
76+
let view = VStack(alignment: .leading) {
77+
TestView(flexible: true)
78+
}.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading).background(Color.red)
79+
80+
assertSnapshot(
81+
matching: view, as: .image(precision: precision, layout: layout), named: platformName)
82+
}
8183
}
8284
#endif
72.5 KB
Loading
73.4 KB
Loading
71.6 KB
Loading
69.3 KB
Loading

0 commit comments

Comments
 (0)