diff --git a/Demo/macOS/AboutCommand.swift b/Demo/macOS/AboutCommand.swift index 5521fcf2b..9cf8b834d 100644 --- a/Demo/macOS/AboutCommand.swift +++ b/Demo/macOS/AboutCommand.swift @@ -16,7 +16,10 @@ struct AboutCommand: Commands { var body: some Commands { CommandGroup(replacing: .appInfo) { Button("About RichTextKit") { - NSApplication.shared.orderFrontStandardAboutPanel(options: .richTextKit) + NSApplication.shared + .orderFrontStandardAboutPanel( + options: .richTextKit + ) } } } diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9e969d3f1..f19608dfd 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -51,6 +51,7 @@ By deprecating these functions, we can simplify the library in 1.0, and focus mo * `RichTextCommand.StyleOptionsGroup` has been deprecated. * `RichTextCommand.SuperscriptOptionsGroup` has been deprecated. * `RichTextContext` replaces individual colors with a single `colors`. +* `RichTextContext` replaces individual styles with a single `styles`. * `RichTextContext` `userActionPublisher` is renamed to `actionPublisher`. * `RichTextCoordinator` functions calling `handle(_:)` have been deprecated. * `RTKL10n.bundle` has been deprecated since we can use the `.module` bundle. diff --git a/Sources/RichTextKit/Context/RichTextContext+Styles.swift b/Sources/RichTextKit/Context/RichTextContext+Styles.swift index ed0351391..d6f4d354d 100644 --- a/Sources/RichTextKit/Context/RichTextContext+Styles.swift +++ b/Sources/RichTextKit/Context/RichTextContext+Styles.swift @@ -14,35 +14,39 @@ public extension RichTextContext { func binding(for style: RichTextStyle) -> Binding { Binding( get: { Bool(self.hasStyle(style)) }, - set: { self.set(style, to: $0) } + set: { self.setStyle(style, to: $0) } ) } /// Check whether or not the context has a certain style. func hasStyle(_ style: RichTextStyle) -> Bool { - switch style { - case .bold: isBold - case .italic: isItalic - case .underlined: isUnderlined - case .strikethrough: isStrikethrough - } + styles[style] == true } /// Set whether or not the context has a certain style. - func set( + func setStyle( _ style: RichTextStyle, to val: Bool ) { - switch style { - case .bold: actionPublisher.send(.setStyle(.bold, val)); isBold = val - case .italic: actionPublisher.send(.setStyle(.italic, val)); isItalic = val - case .underlined: actionPublisher.send(.setStyle(.underlined, val)); isUnderlined = val - case .strikethrough: actionPublisher.send(.setStyle(.strikethrough, val)); isStrikethrough = val - } + guard styles[style] != val else { return } + actionPublisher.send(.setStyle(style, val)) + setStyleInternal(style, to: val) } /// Toggle a certain style for the context. - func toggle(_ style: RichTextStyle) { - set(style, to: !hasStyle(style)) + func toggleStyle(_ style: RichTextStyle) { + setStyle(style, to: !hasStyle(style)) + } +} + +extension RichTextContext { + + /// Set the value for a certain color, or remove it. + func setStyleInternal( + _ style: RichTextStyle, + to val: Bool? + ) { + guard let val else { return styles[style] = nil } + styles[style] = val } } diff --git a/Sources/RichTextKit/Context/RichTextContext.swift b/Sources/RichTextKit/Context/RichTextContext.swift index 3c9ea7ae3..625e0f557 100644 --- a/Sources/RichTextKit/Context/RichTextContext.swift +++ b/Sources/RichTextKit/Context/RichTextContext.swift @@ -75,27 +75,47 @@ public class RichTextContext: ObservableObject { public var highlightedRange: NSRange? - // MARK: - Deprecations (to avoid library warnings) + // MARK: - Deprecated Colors - @Published @available(*, deprecated, renamed: "colors") - public internal(set) var backgroundColor: ColorRepresentable? + public var backgroundColor: ColorRepresentable? { + colors[.background] + } - @Published @available(*, deprecated, renamed: "colors") - public internal(set) var foregroundColor: ColorRepresentable? + public var foregroundColor: ColorRepresentable? { + colors[.foreground] + } - @Published @available(*, deprecated, renamed: "colors") - public internal(set) var strikethroughColor: ColorRepresentable? + public var strikethroughColor: ColorRepresentable? { + colors[.strikethrough] + } - @Published @available(*, deprecated, renamed: "colors") - public internal(set) var strokeColor: ColorRepresentable? + public var strokeColor: ColorRepresentable? { + colors[.stroke] + } - @Published @available(*, deprecated, renamed: "colors") - public internal(set) var underlineColor: ColorRepresentable? + public var underlineColor: ColorRepresentable? { + colors[.underline] + } + + + // MARK: - Deprecated Styles + + @available(*, deprecated, renamed: "styles") + public var isBold: Bool { hasStyle(.bold) } + + @available(*, deprecated, renamed: "styles") + public var isItalic: Bool { hasStyle(.italic) } + + @available(*, deprecated, renamed: "styles") + public var isStrikethrough: Bool { hasStyle(.strikethrough) } + + @available(*, deprecated, renamed: "styles") + public var isUnderlined: Bool { hasStyle(.underlined) } // MARK: - Observable Properties @@ -126,22 +146,9 @@ public class RichTextContext: ObservableObject { /// The style to apply when highlighting a range. @Published public internal(set) var highlightingStyle = RichTextHighlightingStyle.standard - - /// Whether or not the current text is bold. - @Published - public internal(set) var isBold = false - - /// Whether or not the current text is italic. - @Published - public internal(set) var isItalic = false - - /// Whether or not the current text is striked through. - @Published - public internal(set) var isStrikethrough = false - - /// Whether or not the current text is underlined. + @Published - public internal(set) var isUnderlined = false + public internal(set) var styles = [RichTextStyle: Bool]() } public extension RichTextContext { diff --git a/Sources/RichTextKit/Coordinator/RichTextCoordinator.swift b/Sources/RichTextKit/Coordinator/RichTextCoordinator.swift index afb3bcda6..ff543c29b 100644 --- a/Sources/RichTextKit/Coordinator/RichTextCoordinator.swift +++ b/Sources/RichTextKit/Coordinator/RichTextCoordinator.swift @@ -237,24 +237,16 @@ extension RichTextCoordinator { } let isBold = styles.hasStyle(.bold) - if context.isBold != isBold { - context.isBold = isBold - } + context.setStyleInternal(.bold, to: isBold) let isItalic = styles.hasStyle(.italic) - if context.isItalic != isItalic { - context.isItalic = isItalic - } - + context.setStyleInternal(.italic, to: isItalic) + let isStrikethrough = styles.hasStyle(.strikethrough) - if context.isStrikethrough != isStrikethrough { - context.isStrikethrough = isStrikethrough - } - + context.setStyleInternal(.strikethrough, to: isStrikethrough) + let isUnderlined = styles.hasStyle(.underlined) - if context.isUnderlined != isUnderlined { - context.isUnderlined = isUnderlined - } + context.setStyleInternal(.underlined, to: isUnderlined) let isEditingText = textView.isFirstResponder if context.isEditingText != isEditingText { diff --git a/Sources/RichTextKit/_Deprecated/RichTextContext+Deprecated.swift b/Sources/RichTextKit/_Deprecated/RichTextContext+Deprecated.swift index ddccb8b3f..c72c0f8b6 100644 --- a/Sources/RichTextKit/_Deprecated/RichTextContext+Deprecated.swift +++ b/Sources/RichTextKit/_Deprecated/RichTextContext+Deprecated.swift @@ -89,4 +89,14 @@ public extension RichTextContext { ) ) } + + @available(*, deprecated, renamed: "setStyle") + func set(_ style: RichTextStyle, to val: Bool) { + setStyle(style, to: val) + } + + @available(*, deprecated, renamed: "toggleStyle") + func toggle(_ style: RichTextStyle) { + toggleStyle(style) + } } diff --git a/Tests/RichTextKitTests/RichTextCoordinator+SubscriptionsTests.swift b/Tests/RichTextKitTests/RichTextCoordinator+SubscriptionsTests.swift index 4169ce553..6660ab3a3 100644 --- a/Tests/RichTextKitTests/RichTextCoordinator+SubscriptionsTests.swift +++ b/Tests/RichTextKitTests/RichTextCoordinator+SubscriptionsTests.swift @@ -96,25 +96,25 @@ final class RichTextCoordinator_SubscriptionsTests: XCTestCase { func testIsBoldUpdatesTextView() { XCTAssertFalse(textView.richTextStyles.hasStyle(.bold)) - textContext.userActionPublisher.send(.setStyle(.bold, true)) + textContext.actionPublisher.send(.setStyle(.bold, true)) XCTAssertTrue(textView.richTextStyles.hasStyle(.bold)) } func testIsItalicUpdatesTextView() { XCTAssertFalse(textView.richTextStyles.hasStyle(.italic)) - textContext.userActionPublisher.send(.setStyle(.italic, true)) + textContext.actionPublisher.send(.setStyle(.italic, true)) XCTAssertTrue(textView.richTextStyles.hasStyle(.italic)) } func testIsUnderlinedUpdatesTextView() { XCTAssertFalse(textView.richTextStyles.hasStyle(.underlined)) - textContext.userActionPublisher.send(.setStyle(.underlined, true)) + textContext.actionPublisher.send(.setStyle(.underlined, true)) XCTAssertTrue(textView.richTextStyles.hasStyle(.underlined)) } func testIsStrikeThroughUpdatesTextView() { XCTAssertFalse(textView.richTextStyles.hasStyle(.strikethrough)) - textContext.userActionPublisher.send(.setStyle(.strikethrough, true)) + textContext.actionPublisher.send(.setStyle(.strikethrough, true)) XCTAssertTrue(textView.richTextStyles.hasStyle(.strikethrough)) } diff --git a/Tests/RichTextKitTests/RichTextCoordinatorTests.swift b/Tests/RichTextKitTests/RichTextCoordinatorTests.swift index e30166d33..8dfed42df 100644 --- a/Tests/RichTextKitTests/RichTextCoordinatorTests.swift +++ b/Tests/RichTextKitTests/RichTextCoordinatorTests.swift @@ -64,9 +64,9 @@ final class RichTextCoordinatorTests: XCTestCase { let styles = view.richTextStyles XCTAssertEqual(context.fontName, view.richTextFont?.fontName) XCTAssertEqual(context.fontSize, view.richTextFont?.pointSize) - XCTAssertEqual(context.isBold, styles.hasStyle(.bold)) - XCTAssertEqual(context.isItalic, styles.hasStyle(.italic)) - XCTAssertEqual(context.isUnderlined, styles.hasStyle(.underlined)) + XCTAssertEqual(context.styles[.bold], styles.hasStyle(.bold)) + XCTAssertEqual(context.styles[.italic], styles.hasStyle(.italic)) + XCTAssertEqual(context.styles[.underlined], styles.hasStyle(.underlined)) XCTAssertEqual(context.selectedRange, view.selectedRange) #if iOS || os(tvOS) XCTAssertEqual(context.textAlignment, view.richTextAlignment)