diff --git a/Sources/RichTextKit/Component/RichTextViewComponent.swift b/Sources/RichTextKit/Component/RichTextViewComponent.swift index f51bc73c4..ff78777a6 100644 --- a/Sources/RichTextKit/Component/RichTextViewComponent.swift +++ b/Sources/RichTextKit/Component/RichTextViewComponent.swift @@ -133,22 +133,3 @@ public extension RichTextViewComponent { format.supportsImages ? .enabled : .disabled } } - -extension RichTextViewComponent { - - /// This can be called to setup the initial font size. - func setupInitialFontSize() { - let font = FontRepresentable.standardRichTextFont - let size = font.pointSize - setRichTextFontSize(size) - } - - /// This can be called to setup an initial text color. - func trySetupInitialTextColor( - for text: NSAttributedString, - _ action: () -> Void - ) { - guard text.string.isEmpty else { return } - action() - } -} diff --git a/Sources/RichTextKit/Coordinator/RichTextCoordinator+Subscriptions.swift b/Sources/RichTextKit/Coordinator/RichTextCoordinator+Subscriptions.swift index 758cd0b01..8cbef2bc5 100644 --- a/Sources/RichTextKit/Coordinator/RichTextCoordinator+Subscriptions.swift +++ b/Sources/RichTextKit/Coordinator/RichTextCoordinator+Subscriptions.swift @@ -191,7 +191,7 @@ extension RichTextCoordinator { extension ColorRepresentable { #if iOS || os(tvOS) || os(visionOS) - static var textColor: ColorRepresentable { .label } + public static var textColor: ColorRepresentable { .label } #endif } #endif diff --git a/Sources/RichTextKit/RichTextView+Config.swift b/Sources/RichTextKit/RichTextView+Config.swift index fc250f8e2..c2ca3599c 100644 --- a/Sources/RichTextKit/RichTextView+Config.swift +++ b/Sources/RichTextKit/RichTextView+Config.swift @@ -1,41 +1,13 @@ // // RichTextView+Config.swift -// RichTextKit // -// Created by Daniel Saidi on 2024-01-16. -// Copyright © 2024 Daniel Saidi. All rights reserved. +// +// Created by Dominik Bucher on 13.02.2024. // -#if iOS || macOS || os(tvOS) || os(visionOS) -import SwiftUI - -public extension RichTextView { - - /** - This type can be used to configure a ``RichTextEditor``. - */ - struct Configuration { - - /** - Create a custom configuration. - - - Parameters: - - isScrollingEnabled: Whether or not the editor should scroll, by default `true`. - */ - public init( - isScrollingEnabled: Bool = true - ) { - self.isScrollingEnabled = isScrollingEnabled - } - - /// Whether or not the editor should scroll. - public var isScrollingEnabled: Bool - } -} +import Foundation public extension RichTextView.Configuration { - /// Get a standard rich text editor configuration. static var standard: Self { .init() } } -#endif diff --git a/Sources/RichTextKit/RichTextView+Config_AppKit.swift b/Sources/RichTextKit/RichTextView+Config_AppKit.swift new file mode 100644 index 000000000..3052f117e --- /dev/null +++ b/Sources/RichTextKit/RichTextView+Config_AppKit.swift @@ -0,0 +1,36 @@ +// +// RichTextView+Config_AppKit.swift +// +// +// Created by Dominik Bucher on 13.02.2024. +// + +#if macOS +import Foundation + +public extension RichTextView { + + /** + This type can be used to configure a ``RichTextEditor``. + */ + struct Configuration { + + /// Create a custom configuration + /// - Parameters: + /// - isScrollingEnabled: Whether or not the editor should scroll, by default `true`. + /// - isContinuousSpellCheckingEnabled: Whether the editor spell-checks in realtime. Defaults to `true`. + public init( + isScrollingEnabled: Bool = true, + isContinuousSpellCheckingEnabled: Bool = true + ) { + self.isScrollingEnabled = isScrollingEnabled + self.isContinuousSpellCheckingEnabled = isContinuousSpellCheckingEnabled + } + + /// Whether or not the editor should scroll. + public var isScrollingEnabled: Bool + /// Whether the editor spell-checks in realtime. + public var isContinuousSpellCheckingEnabled: Bool + } +} +#endif diff --git a/Sources/RichTextKit/RichTextView+Config_UIKit.swift b/Sources/RichTextKit/RichTextView+Config_UIKit.swift new file mode 100644 index 000000000..765f75355 --- /dev/null +++ b/Sources/RichTextKit/RichTextView+Config_UIKit.swift @@ -0,0 +1,50 @@ +// +// RichTextView+Config_UIKit.swift +// RichTextKit +// +// Created by Daniel Saidi on 2024-01-16. +// Copyright © 2024 Daniel Saidi. All rights reserved. +// + +#if iOS || os(tvOS) || os(visionOS) +import SwiftUI + +public extension RichTextView { + + /** + This type can be used to configure a ``RichTextEditor``. + */ + struct Configuration { + + /** + Create a custom configuration. + + - Parameters: + - isScrollingEnabled: Whether or not the editor should scroll, by default `true`. + - allowsEditingTextAttributes: If editor allows editing text attributes, by default `true`. + - autocapitalizationType: Type of Auto capitalization, default is to `.sentences`. + - spellCheckingType: Whether textView spell-Checks, default is `.no`. + */ + public init( + isScrollingEnabled: Bool = true, + allowsEditingTextAttributes: Bool = true, + autocapitalizationType: UITextAutocapitalizationType = .sentences, + spellCheckingType: UITextSpellCheckingType = .no + ) { + self.isScrollingEnabled = isScrollingEnabled + self.allowsEditingTextAttributes = allowsEditingTextAttributes + self.autocapitalizationType = autocapitalizationType + self.spellCheckingType = spellCheckingType + } + + /// Whether or not the editor should scroll. + public var isScrollingEnabled: Bool + /// Whether textView allows editting text attributes + public var allowsEditingTextAttributes: Bool + /// Kind of auto capitalization + public var autocapitalizationType: UITextAutocapitalizationType + /// If TextView spell-checks the text. + public var spellCheckingType: UITextSpellCheckingType + } +} +#endif diff --git a/Sources/RichTextKit/RichTextView+Theme.swift b/Sources/RichTextKit/RichTextView+Theme.swift new file mode 100644 index 000000000..6a563203a --- /dev/null +++ b/Sources/RichTextKit/RichTextView+Theme.swift @@ -0,0 +1,47 @@ +// +// RichTextView+Theme.swift +// RichTextKit +// +// Created by Dominik Bucher on 13.02.2024. +// + +#if iOS || macOS || os(tvOS) || os(visionOS) +import SwiftUI + +public extension RichTextView { + + /** + This type can be used to configure a ``RichTextEditor``'s current color properties. + */ + struct Theme { + + /** + Create a custom configuration. + + - Parameters: + - font: default `.systemFont` of point size `16` (this differs on iOS and macOS). + - fontColor: default `.textColor`. + - backgroundColor: Color of whole textView default `.clear`. + */ + public init( + font: FontRepresentable = .systemFont(ofSize: 16), + fontColor: ColorRepresentable = .textColor, + backgroundColor: ColorRepresentable = .clear + ) { + self.font = font + self.fontColor = fontColor + self.backgroundColor = backgroundColor + } + + public let font: FontRepresentable + public let fontColor: ColorRepresentable + public let backgroundColor: ColorRepresentable + } +} + +public extension RichTextView.Theme { + + /// Get a standard rich text editor configuration. + static var standard: Self { .init() } +} +#endif diff --git a/Sources/RichTextKit/RichTextView_AppKit.swift b/Sources/RichTextKit/RichTextView_AppKit.swift index 49c4a7b19..5e224bc60 100644 --- a/Sources/RichTextKit/RichTextView_AppKit.swift +++ b/Sources/RichTextKit/RichTextView_AppKit.swift @@ -30,6 +30,9 @@ open class RichTextView: NSTextView, RichTextViewComponent { /// The configuration to use by the rich text view. public var configuration: Configuration = .standard + /// The theme for coloring and setting style to text view. + public var theme: Theme = .standard + /// The style to use when highlighting text in the view. public var highlightingStyle: RichTextHighlightingStyle = .standard @@ -107,17 +110,26 @@ open class RichTextView: NSTextView, RichTextViewComponent { format: RichTextDataFormat ) { attributedString = .empty - setupInitialFontSize() attributedString = text allowsImageEditing = true allowsUndo = true - backgroundColor = .clear - trySetupInitialTextColor(for: text) { - textColor = .textColor - } imageConfiguration = standardImageConfiguration(for: format) layoutManager?.defaultAttachmentScaling = NSImageScaling.scaleProportionallyDown setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + setupConfiguration() + setupTheme() + } + + // MARK: - Internal + + func setupConfiguration() { + isContinuousSpellCheckingEnabled = configuration.isContinuousSpellCheckingEnabled + } + + func setupTheme() { + font = theme.font + textColor = theme.fontColor + backgroundColor = theme.backgroundColor } // MARK: - Open Functionality diff --git a/Sources/RichTextKit/RichTextView_UIKit.swift b/Sources/RichTextKit/RichTextView_UIKit.swift index 436317e44..f654b9a0c 100644 --- a/Sources/RichTextKit/RichTextView_UIKit.swift +++ b/Sources/RichTextKit/RichTextView_UIKit.swift @@ -50,6 +50,15 @@ open class RichTextView: UITextView, RichTextViewComponent { public var configuration: Configuration = .standard { didSet { isScrollEnabled = configuration.isScrollingEnabled + allowsEditingTextAttributes = configuration.allowsEditingTextAttributes + autocapitalizationType = configuration.autocapitalizationType + spellCheckingType = configuration.spellCheckingType + } + } + + public var theme: Theme = .standard { + didSet { + setupTheme() } } @@ -154,19 +163,22 @@ open class RichTextView: UITextView, RichTextViewComponent { format: RichTextDataFormat ) { attributedString = .empty - setupInitialFontSize() imageConfiguration = standardImageConfiguration(for: format) text.autosizeImageAttachments(maxSize: imageAttachmentMaxSize) attributedString = text - allowsEditingTextAttributes = false - autocapitalizationType = .sentences - backgroundColor = .clear richTextDataFormat = format - spellCheckingType = .no - trySetupInitialTextColor(for: text) { - textColor = .label - } setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + setupTheme() + } + + // MARK: - Internal functionality + + func setupTheme() { + if text.isEmpty { + font = theme.font + textColor = theme.fontColor + } + backgroundColor = theme.backgroundColor } // MARK: - Open Functionality diff --git a/Tests/RichTextKitTests/RichTextViewRepresentableTests.swift b/Tests/RichTextKitTests/RichTextViewRepresentableTests.swift index 9b1a707e4..1a61d16d8 100644 --- a/Tests/RichTextKitTests/RichTextViewRepresentableTests.swift +++ b/Tests/RichTextKitTests/RichTextViewRepresentableTests.swift @@ -45,9 +45,10 @@ final class RichTextViewComponentTests: XCTestCase { func testSettingUpWithEmptyTextWorks() { let string = NSAttributedString(string: "") view.setup(with: string, format: .rtf) + view.configuration = .standard XCTAssertEqual(view.richText.string, "") #if iOS || os(tvOS) - XCTAssertFalse(view.allowsEditingTextAttributes) + XCTAssertTrue(view.allowsEditingTextAttributes) XCTAssertEqual(view.autocapitalizationType, .sentences) #endif XCTAssertEqual(view.backgroundColor, .clear) @@ -63,9 +64,11 @@ final class RichTextViewComponentTests: XCTestCase { func testSettingUpWithNonEmptyTextWorks() { let string = NSAttributedString(string: "foo bar baz") view.setup(with: string, format: .rtf) + view.configuration = .standard + view.theme = .standard XCTAssertEqual(view.richText.string, "foo bar baz") #if iOS || os(tvOS) - XCTAssertFalse(view.allowsEditingTextAttributes) + XCTAssertTrue(view.allowsEditingTextAttributes) XCTAssertEqual(view.autocapitalizationType, .sentences) #endif XCTAssertEqual(view.backgroundColor, .clear)