Skip to content

Commit

Permalink
Fix redo and undo for color attrubutes
Browse files Browse the repository at this point in the history
  • Loading branch information
cp-divyesh-v committed Jan 13, 2025
1 parent a9319e0 commit bc7b8a9
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 54 deletions.
5 changes: 3 additions & 2 deletions Sources/RichEditorSwiftUI/Data/Models/RichAttributes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,10 @@ extension RichAttributes {
size: (att.size != nil ? (byAdding ? att.size! : nil) : self.size),
font: (att.font != nil ? (byAdding ? att.font! : nil) : self.font),
color: (att.color != nil
? (byAdding ? att.color! : nil) : self.color),
? (byAdding ? att.color! : nil) : (att.color == nil && !byAdding) ? nil : self.color),
background: (att.background != nil
? (byAdding ? att.background! : nil) : self.background),
? (byAdding ? att.background! : nil)
: (att.background == nil && !byAdding) ? nil : self.background),
align: (att.align != nil
? (byAdding ? att.align! : nil) : self.align),
///nil link indicates removal as well so removing link if `byAdding == false && att.link == nil`
Expand Down
2 changes: 2 additions & 0 deletions Sources/RichEditorSwiftUI/UI/Context/RichEditorState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ public class RichEditorState: ObservableObject {
public internal(set) var colors = [RichTextColor: ColorRepresentable]() {
willSet { previousColors = colors }
}
@Published
internal var colorScheme: ColorScheme = .light

/// The style to apply when highlighting a range.
@Published
Expand Down
91 changes: 45 additions & 46 deletions Sources/RichEditorSwiftUI/UI/Context/RichTextContext+Color.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,58 @@ import SwiftUI

extension RichEditorState {

/// Get a binding for a certain color.
public func binding(for color: RichTextColor) -> Binding<Color> {
Binding(
get: { Color(self.color(for: color) ?? .clear) },
set: { self.updateStyleFor(color, to: .init($0)) }
)
}
/// Get a binding for a certain color.
public func binding(for color: RichTextColor) -> Binding<Color> {
Binding(
get: { Color(self.color(for: color) ?? .clear) },
set: { self.updateStyleFor(color, to: .init($0)) }
)
}

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

/// Set the value for a certain color.
public func setColor(
_ color: RichTextColor,
to val: ColorRepresentable
) {
guard self.color(for: color) != val else { return }
actionPublisher.send(.setColor(color, val))
setColorInternal(color, to: val)
}
/// Set the value for a certain color.
public func setColor(
_ color: RichTextColor,
to val: ColorRepresentable
) {
actionPublisher.send(.setColor(color, val))
setColorInternal(color, to: val)
}

public func updateStyleFor(
_ color: RichTextColor, to val: ColorRepresentable
) {
let value = Color(val)
switch color {
case .foreground:
updateStyle(style: .color(value))
case .background:
updateStyle(style: .background(value))
case .strikethrough:
return
case .stroke:
return
case .underline:
return
}
public func updateStyleFor(
_ color: RichTextColor, to val: ColorRepresentable
) {
let value = Color(val)
switch color {
case .foreground:
updateStyle(style: .color(value))
case .background:
updateStyle(style: .background(value))
case .strikethrough:
return
case .stroke:
return
case .underline:
return
}
}
}

extension RichEditorState {

/// Set the value for a certain color, or remove it.
func setColorInternal(
_ color: RichTextColor,
to val: ColorRepresentable?
) {
guard let val else {
colors[color] = nil
return
}
colors[color] = val
/// Set the value for a certain color, or remove it.
func setColorInternal(
_ color: RichTextColor,
to val: ColorRepresentable?
) {
guard let val else {
colors[color] = nil
return
}
colors[color] = val
}
}
7 changes: 7 additions & 0 deletions Sources/RichEditorSwiftUI/UI/Editor/RichEditor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
/// For more information, see ``RichTextKeyboardToolbarConfig``
/// and ``RichTextKeyboardToolbarStyle``.
public struct RichTextEditor: ViewRepresentable {
@Environment(\.colorScheme) var colorScheme

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

Expand Down Expand Up @@ -112,6 +113,9 @@
textView.configuration = config
textView.theme = style
viewConfiguration(textView)
DispatchQueue.main.async {
self.context.colorScheme = self.colorScheme
}
return textView
}

Expand All @@ -129,6 +133,9 @@
textView.configuration = config
textView.theme = style
viewConfiguration(textView)
DispatchQueue.main.async {
self.context.colorScheme = self.colorScheme
}
return scrollView
}

Expand Down
22 changes: 16 additions & 6 deletions Sources/RichEditorSwiftUI/UI/Editor/RichEditorState+Spans.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ extension RichEditorState {
- style: is of type RichTextSpanStyle
*/
public func updateStyle(style: RichTextSpanStyle, shouldRegisterUndo: Bool = true) {
let wasStyleActive = activeStyles.contains(style)
setInternalStyles(style: style)
setStyle(style, shouldRegisterUndo: shouldRegisterUndo)
/// 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
setInternalStyles(style: style)
}
}

Expand Down Expand Up @@ -180,19 +180,21 @@ extension RichEditorState {
addStyle = fontName == self.fontName
}
case .color(let color):
if let color, color.toHex() != Color.primary.toHex() {
let defaultColor = RichTextColor.foreground.adjust(nil, for: colorScheme)
if let color, color.toHex() != defaultColor.toHex() {
if let internalColor = self.color(for: .foreground) {
addStyle = Color(internalColor) != color
addStyle = (Color(internalColor) != color)
} else {
addStyle = true
}
} else {
addStyle = false
}
case .background(let bgColor):
if let color = bgColor, color.toHex() != Color.clear.toHex() {
let defaultColor = RichTextColor.background.adjust(nil, for: colorScheme)
if let color = bgColor, color.toHex() != defaultColor.toHex() {
if let internalColor = self.color(for: .background) {
addStyle = Color(internalColor) != color
addStyle = (Color(internalColor) == color)
} else {
addStyle = true
}
Expand Down Expand Up @@ -899,10 +901,18 @@ extension RichEditorState {
case .color(let color):
if let color {
setColor(.foreground, to: .init(color))
} else {
setColor(
.foreground,
to: ColorRepresentable(RichTextColor.foreground.adjust(nil, for: colorScheme)))
}
case .background(let color):
if let color {
setColor(.background, to: .init(color))
} else {
setColor(
.background,
to: ColorRepresentable(RichTextColor.background.adjust(nil, for: colorScheme)))
}
case .align(let alignment):
if let alignment, alignment != self.textAlignment {
Expand Down

0 comments on commit bc7b8a9

Please sign in to comment.