Skip to content

Commit bc7b8a9

Browse files
committed
Fix redo and undo for color attrubutes
1 parent a9319e0 commit bc7b8a9

File tree

5 files changed

+73
-54
lines changed

5 files changed

+73
-54
lines changed

Sources/RichEditorSwiftUI/Data/Models/RichAttributes.swift

+3-2
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,10 @@ extension RichAttributes {
196196
size: (att.size != nil ? (byAdding ? att.size! : nil) : self.size),
197197
font: (att.font != nil ? (byAdding ? att.font! : nil) : self.font),
198198
color: (att.color != nil
199-
? (byAdding ? att.color! : nil) : self.color),
199+
? (byAdding ? att.color! : nil) : (att.color == nil && !byAdding) ? nil : self.color),
200200
background: (att.background != nil
201-
? (byAdding ? att.background! : nil) : self.background),
201+
? (byAdding ? att.background! : nil)
202+
: (att.background == nil && !byAdding) ? nil : self.background),
202203
align: (att.align != nil
203204
? (byAdding ? att.align! : nil) : self.align),
204205
///nil link indicates removal as well so removing link if `byAdding == false && att.link == nil`

Sources/RichEditorSwiftUI/UI/Context/RichEditorState.swift

+2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ public class RichEditorState: ObservableObject {
108108
public internal(set) var colors = [RichTextColor: ColorRepresentable]() {
109109
willSet { previousColors = colors }
110110
}
111+
@Published
112+
internal var colorScheme: ColorScheme = .light
111113

112114
/// The style to apply when highlighting a range.
113115
@Published

Sources/RichEditorSwiftUI/UI/Context/RichTextContext+Color.swift

+45-46
Original file line numberDiff line numberDiff line change
@@ -9,59 +9,58 @@ import SwiftUI
99

1010
extension RichEditorState {
1111

12-
/// Get a binding for a certain color.
13-
public func binding(for color: RichTextColor) -> Binding<Color> {
14-
Binding(
15-
get: { Color(self.color(for: color) ?? .clear) },
16-
set: { self.updateStyleFor(color, to: .init($0)) }
17-
)
18-
}
12+
/// Get a binding for a certain color.
13+
public func binding(for color: RichTextColor) -> Binding<Color> {
14+
Binding(
15+
get: { Color(self.color(for: color) ?? .clear) },
16+
set: { self.updateStyleFor(color, to: .init($0)) }
17+
)
18+
}
1919

20-
/// Get the value for a certain color.
21-
public func color(for color: RichTextColor) -> ColorRepresentable? {
22-
colors[color]
23-
}
20+
/// Get the value for a certain color.
21+
public func color(for color: RichTextColor) -> ColorRepresentable? {
22+
colors[color]
23+
}
2424

25-
/// Set the value for a certain color.
26-
public func setColor(
27-
_ color: RichTextColor,
28-
to val: ColorRepresentable
29-
) {
30-
guard self.color(for: color) != val else { return }
31-
actionPublisher.send(.setColor(color, val))
32-
setColorInternal(color, to: val)
33-
}
25+
/// Set the value for a certain color.
26+
public func setColor(
27+
_ color: RichTextColor,
28+
to val: ColorRepresentable
29+
) {
30+
actionPublisher.send(.setColor(color, val))
31+
setColorInternal(color, to: val)
32+
}
3433

35-
public func updateStyleFor(
36-
_ color: RichTextColor, to val: ColorRepresentable
37-
) {
38-
let value = Color(val)
39-
switch color {
40-
case .foreground:
41-
updateStyle(style: .color(value))
42-
case .background:
43-
updateStyle(style: .background(value))
44-
case .strikethrough:
45-
return
46-
case .stroke:
47-
return
48-
case .underline:
49-
return
50-
}
34+
public func updateStyleFor(
35+
_ color: RichTextColor, to val: ColorRepresentable
36+
) {
37+
let value = Color(val)
38+
switch color {
39+
case .foreground:
40+
updateStyle(style: .color(value))
41+
case .background:
42+
updateStyle(style: .background(value))
43+
case .strikethrough:
44+
return
45+
case .stroke:
46+
return
47+
case .underline:
48+
return
5149
}
50+
}
5251
}
5352

5453
extension RichEditorState {
5554

56-
/// Set the value for a certain color, or remove it.
57-
func setColorInternal(
58-
_ color: RichTextColor,
59-
to val: ColorRepresentable?
60-
) {
61-
guard let val else {
62-
colors[color] = nil
63-
return
64-
}
65-
colors[color] = val
55+
/// Set the value for a certain color, or remove it.
56+
func setColorInternal(
57+
_ color: RichTextColor,
58+
to val: ColorRepresentable?
59+
) {
60+
guard let val else {
61+
colors[color] = nil
62+
return
6663
}
64+
colors[color] = val
65+
}
6766
}

Sources/RichEditorSwiftUI/UI/Editor/RichEditor.swift

+7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
/// For more information, see ``RichTextKeyboardToolbarConfig``
5252
/// and ``RichTextKeyboardToolbarStyle``.
5353
public struct RichTextEditor: ViewRepresentable {
54+
@Environment(\.colorScheme) var colorScheme
5455

5556
@State var cancellable: Set<AnyCancellable> = []
5657

@@ -112,6 +113,9 @@
112113
textView.configuration = config
113114
textView.theme = style
114115
viewConfiguration(textView)
116+
DispatchQueue.main.async {
117+
self.context.colorScheme = self.colorScheme
118+
}
115119
return textView
116120
}
117121

@@ -129,6 +133,9 @@
129133
textView.configuration = config
130134
textView.theme = style
131135
viewConfiguration(textView)
136+
DispatchQueue.main.async {
137+
self.context.colorScheme = self.colorScheme
138+
}
132139
return scrollView
133140
}
134141

Sources/RichEditorSwiftUI/UI/Editor/RichEditorState+Spans.swift

+16-6
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ extension RichEditorState {
6767
- style: is of type RichTextSpanStyle
6868
*/
6969
public func updateStyle(style: RichTextSpanStyle, shouldRegisterUndo: Bool = true) {
70-
let wasStyleActive = activeStyles.contains(style)
71-
setInternalStyles(style: style)
7270
setStyle(style, shouldRegisterUndo: shouldRegisterUndo)
71+
/// Don't change order of function call as it is comparing active attributes with new one so updating it before applying attribute will break the behavior of undo and redo
72+
setInternalStyles(style: style)
7373
}
7474
}
7575

@@ -180,19 +180,21 @@ extension RichEditorState {
180180
addStyle = fontName == self.fontName
181181
}
182182
case .color(let color):
183-
if let color, color.toHex() != Color.primary.toHex() {
183+
let defaultColor = RichTextColor.foreground.adjust(nil, for: colorScheme)
184+
if let color, color.toHex() != defaultColor.toHex() {
184185
if let internalColor = self.color(for: .foreground) {
185-
addStyle = Color(internalColor) != color
186+
addStyle = (Color(internalColor) != color)
186187
} else {
187188
addStyle = true
188189
}
189190
} else {
190191
addStyle = false
191192
}
192193
case .background(let bgColor):
193-
if let color = bgColor, color.toHex() != Color.clear.toHex() {
194+
let defaultColor = RichTextColor.background.adjust(nil, for: colorScheme)
195+
if let color = bgColor, color.toHex() != defaultColor.toHex() {
194196
if let internalColor = self.color(for: .background) {
195-
addStyle = Color(internalColor) != color
197+
addStyle = (Color(internalColor) == color)
196198
} else {
197199
addStyle = true
198200
}
@@ -899,10 +901,18 @@ extension RichEditorState {
899901
case .color(let color):
900902
if let color {
901903
setColor(.foreground, to: .init(color))
904+
} else {
905+
setColor(
906+
.foreground,
907+
to: ColorRepresentable(RichTextColor.foreground.adjust(nil, for: colorScheme)))
902908
}
903909
case .background(let color):
904910
if let color {
905911
setColor(.background, to: .init(color))
912+
} else {
913+
setColor(
914+
.background,
915+
to: ColorRepresentable(RichTextColor.background.adjust(nil, for: colorScheme)))
906916
}
907917
case .align(let alignment):
908918
if let alignment, alignment != self.textAlignment {

0 commit comments

Comments
 (0)