Skip to content

Commit 85a5b4b

Browse files
committed
Fix color issue of text view with theme change
1 parent e3a99d0 commit 85a5b4b

File tree

10 files changed

+231
-82
lines changed

10 files changed

+231
-82
lines changed

RichEditorDemo/RichEditorDemo/ContentView.swift

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct ContentView: View {
4646

4747
}
4848
)
49+
.background(colorScheme == .dark ? .gray.opacity(0.3) : Color.white)
4950
.cornerRadius(10)
5051

5152
#if os(iOS)

RichEditorDemo/RichEditorDemo/Sample_json.json

+103-48
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,177 @@
11
{
22
"spans": [
33
{
4-
"insert": "RichEditor",
4+
"insert": "RichEditorSwiftUI",
55
"attributes": {
6-
"bold": true,
7-
"header": 1
6+
"color": "#FF9500",
7+
"size": 24,
8+
"font": "Academy Engraved LET"
89
}
910
},
1011
{
11-
"insert": "\niOS ",
12-
"attributes": {}
12+
"attributes": {},
13+
"insert": "\n\nIt’s Support "
1314
},
1415
{
15-
"insert": "RichEditorSwiftUI ",
16+
"insert": "bold",
1617
"attributes": {
17-
"bold": true,
18-
"italic": true
18+
"bold": true
1919
}
2020
},
2121
{
22-
"insert": "Rich editor for ",
23-
"attributes": {}
22+
"attributes": {},
23+
"insert": ", "
24+
},
25+
{
26+
"attributes": {
27+
"italic": true
28+
},
29+
"insert": "italic"
30+
},
31+
{
32+
"attributes": {},
33+
"insert": ", "
2434
},
2535
{
26-
"insert": "SwiftUI.\n\n",
2736
"attributes": {
28-
"bold": true,
2937
"underline": true
30-
}
38+
},
39+
"insert": "underline"
3140
},
3241
{
33-
"insert": "Features",
42+
"attributes": {},
43+
"insert": " and "
44+
},
45+
{
46+
"insert": "striketrhough",
3447
"attributes": {
35-
"bold": true,
36-
"header": 3
48+
"strike": true
3749
}
3850
},
3951
{
40-
"insert": "\nThe editor offers the following ",
41-
"attributes": {}
52+
"attributes": {},
53+
"insert": " formats.\n\nWe have different headings\n"
4254
},
4355
{
44-
"insert": "options:\n",
56+
"insert": "Heading 1\n",
4557
"attributes": {
46-
"bold": true,
47-
"italic": true,
48-
"underline": true
58+
"header": 1
4959
}
5060
},
5161
{
52-
"insert": "\n",
53-
"attributes": {}
62+
"insert": "Heading 2",
63+
"attributes": {
64+
"header": 2
65+
}
66+
},
67+
{
68+
"attributes": {},
69+
"insert": "\n"
5470
},
5571
{
56-
"insert": "Bold\n",
72+
"insert": "Heading 3\n",
5773
"attributes": {
58-
"bold": true
74+
"header": 3
5975
}
6076
},
6177
{
62-
"insert": "Italic\n",
78+
"insert": "Heading 4\n",
6379
"attributes": {
64-
"italic": true
80+
"header": 4
6581
}
6682
},
6783
{
68-
"insert": "Underline\n",
84+
"insert": "Heading 5\n",
6985
"attributes": {
70-
"underline": true
86+
"header": 5
87+
}
88+
},
89+
{
90+
"insert": "Heading 6\n",
91+
"attributes": {
92+
"header": 6
7193
}
7294
},
7395
{
74-
"insert": "Different ",
96+
"insert": "\nHere we have ",
7597
"attributes": {}
7698
},
7799
{
78-
"insert": "Headings\n\n",
79100
"attributes": {
80-
"bold": true,
81-
"italic": true,
82-
"underline": true
101+
"size": 24
102+
},
103+
"insert": "large"
104+
},
105+
{
106+
"attributes": {},
107+
"insert": " and "
108+
},
109+
{
110+
"attributes": {
111+
"size": 10
112+
},
113+
"insert": "small"
114+
},
115+
{
116+
"attributes": {},
117+
"insert": " text and "
118+
},
119+
{
120+
"insert": "custom fonts",
121+
"attributes": {
122+
"font": "ChalkboardSE-Light",
123+
"color": "#007AFF"
83124
}
84125
},
85126
{
86-
"insert": "\n",
127+
"insert": " as well.\n\nYou can align text differently\nHere is the left align\n",
87128
"attributes": {}
88129
},
89130
{
90-
"insert": "Credits",
91131
"attributes": {
92-
"bold": true,
93-
"header": 3
132+
"align": "center"
133+
},
134+
"insert": "This is center align\n"
135+
},
136+
{
137+
"insert": "This is right align\n",
138+
"attributes": {
139+
"align": "right"
94140
}
95141
},
96142
{
97-
"insert": "\n\n",
143+
"attributes": {},
144+
"insert": "\nDifferent font "
145+
},
146+
{
147+
"insert": "color",
148+
"attributes": {
149+
"color": "#34C759"
150+
}
151+
},
152+
{
153+
"insert": " and ",
98154
"attributes": {}
99155
},
100156
{
101-
"insert": "RichEditor ",
157+
"insert": "background",
102158
"attributes": {
103-
"bold": true
159+
"background": "#32ADE6"
104160
}
105161
},
106162
{
107-
"insert": "for SwiftUI is developed and maintained by the ",
163+
"insert": "\n\nThank You! Team ",
108164
"attributes": {}
109165
},
110166
{
111-
"insert": "Canopas Team.",
112167
"attributes": {
113168
"bold": true,
114-
"italic": true,
115-
"underline": true
116-
}
169+
"color": "#F67C8E"
170+
},
171+
"insert": "Canopas"
117172
},
118173
{
119-
"insert": "\n\nThank You! 😊\n\n",
174+
"insert": " 😊",
120175
"attributes": {}
121176
}
122177
]

Sources/RichEditorSwiftUI/BaseFoundation/RichTextCoordinator.swift

+6
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,12 @@ extension RichTextCoordinator {
238238
sync(&context.paragraphStyle, with: textView.richTextParagraphStyle ?? .default)
239239
sync(&context.textAlignment, with: textView.richTextAlignment ?? .left)
240240

241+
RichTextColor.allCases.forEach {
242+
if let color = textView.richTextColor($0) {
243+
context.setColor($0, to: color)
244+
}
245+
}
246+
241247
let styles = textView.richTextStyles
242248
RichTextStyle.allCases.forEach {
243249
let style = styles.hasStyle($0)

Sources/RichEditorSwiftUI/Components/RichTextViewComponent.swift

+15-9
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,15 @@ public protocol RichTextViewComponent: AnyObject,
6161
var typingAttributes: RichTextAttributes { get set }
6262

6363
// MARK: - Setup
64-
6564
/// Setup the view with a text and data format.
66-
func setup()
65+
func setup(
66+
with text: NSAttributedString,
67+
format: RichTextDataFormat?
68+
)
69+
70+
func setup(
71+
with text: RichText
72+
)
6773

6874
// MARK: - Functions
6975

@@ -111,13 +117,13 @@ public extension RichTextViewComponent {
111117
}
112118

113119
/// Setup the view with data and a data format.
114-
// func setup(
115-
// with data: Data,
116-
// format: RichTextDataFormat
117-
// ) throws {
118-
// let string = try NSAttributedString(data: data, format: format)
119-
// setup(with: string, format: format)
120-
// }
120+
func setup(
121+
with data: Data,
122+
format: RichTextDataFormat
123+
) throws {
124+
let string = try NSAttributedString(data: data, format: format)
125+
setup(with: string, format: format)
126+
}
121127

122128
/// Get the image configuration for a certain format.
123129
// func standardImageConfiguration(

Sources/RichEditorSwiftUI/UI/Context/RichEditorState.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,13 @@ public class RichEditorState: ObservableObject {
134134
return internalSpans.map({ .init(insert: getStringWith(from: $0.from, to: $0.to), attributes: $0.attributes) })
135135
}
136136

137+
var internalRichText: RichText = .init()
137138
//MARK: - Initializers
138139
/**
139140
Init with richText which is of type RichText
140141
*/
141142
public init(richText: RichText) {
143+
internalRichText = richText
142144
let input = richText.spans.map({ $0.insert }).joined()
143145
var tempSpans: [RichTextSpanInternal] = []
144146
var text = ""
@@ -154,6 +156,9 @@ public class RichEditorState: ObservableObject {
154156

155157
tempSpans.forEach { span in
156158
str.addAttributes(span.attributes?.toAttributes(font: .standardRichTextFont) ?? [:], range: span.spanRange)
159+
if span.attributes?.color == nil {
160+
str.addAttributes([.foregroundColor: RichTextView.Theme.standard.fontColor], range: span.spanRange)
161+
}
157162
}
158163

159164
self.attributedString = str
@@ -186,7 +191,6 @@ public class RichEditorState: ObservableObject {
186191

187192
rawText = input
188193
}
189-
190194
}
191195

192196
public extension RichEditorState {

Sources/RichEditorSwiftUI/UI/Editor/RichEditor.swift

+6-7
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ public struct RichTextEditor: ViewRepresentable {
6565
/// - viewConfiguration: A platform-specific view configuration, if any.
6666
public init(
6767
context: ObservedObject<RichEditorState>,
68+
format: RichTextDataFormat = .archivedData,
6869
viewConfiguration: @escaping ViewConfiguration = { _ in }
6970
) {
7071
self._context = context
72+
self.format = format
7173
self.viewConfiguration = viewConfiguration
7274
}
7375

@@ -78,6 +80,8 @@ public struct RichTextEditor: ViewRepresentable {
7880

7981
private var viewConfiguration: ViewConfiguration
8082

83+
private var format: RichTextDataFormat
84+
8185
@Environment(\.richTextEditorConfig)
8286
private var config
8387

@@ -106,7 +110,7 @@ public struct RichTextEditor: ViewRepresentable {
106110

107111
#if iOS || os(tvOS) || os(visionOS)
108112
public func makeUIView(context: Context) -> some UIView {
109-
textView.setup()
113+
textView.setup(with: self.context.attributedString, format: format)
110114
textView.configuration = config
111115
textView.theme = style
112116
viewConfiguration(textView)
@@ -119,15 +123,10 @@ public struct RichTextEditor: ViewRepresentable {
119123
self.textView.typingAttributes = [.font: style.font]
120124
}
121125
}
122-
123126
#else
124127

125128
public func makeNSView(context: Context) -> some NSView {
126-
if self.context.internalSpans.isEmpty {
127-
textView.setup()
128-
} else {
129-
textView.setup()
130-
}
129+
textView.setup(with: self.context.attributedString, format: format)
131130
textView.configuration = config
132131
textView.theme = style
133132
viewConfiguration(textView)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// NSAttributedString+Empty.swift
3+
// RichEditorSwiftUI
4+
//
5+
// Created by Divyesh Vekariya on 13/12/24.
6+
//
7+
8+
import Foundation
9+
10+
public extension NSAttributedString {
11+
12+
/// Create an empty attributed string.
13+
static var empty: NSAttributedString {
14+
.init(string: "")
15+
}
16+
}

0 commit comments

Comments
 (0)