From 85b3b60ec2b06607f4366adb9a12bb6556f01ac6 Mon Sep 17 00:00:00 2001 From: Daniel Saidi Date: Wed, 17 Jan 2024 09:22:55 +0100 Subject: [PATCH] Move RichTextAction views into enum namespace --- Demo/macOS/EditorScreen.swift | 2 +- .../Actions/RichTextAction+Button.swift | 119 ++++++++++++++++++ .../Actions/RichTextAction+ButtonGroup.swift | 102 +++++++++++++++ .../Actions/RichTextAction+ButtonStack.swift | 80 ++++++++++++ ...hTextAction+KeyboardShortcutModifier.swift | 2 +- .../RichTextKit/Actions/RichTextAction.swift | 2 +- .../Actions/RichTextActionButton.swift | 116 ----------------- .../Actions/RichTextActionButtonGroup.swift | 99 --------------- .../Actions/RichTextActionButtonStack.swift | 77 ------------ .../Fonts/RichTextFontSizePickerStack.swift | 4 +- .../Format/RichTextFormatSheet.swift | 2 +- .../Format/RichTextFormatSidebar.swift | 2 +- .../Keyboard/RichTextKeyboardToolbar.swift | 4 +- .../RichTextKit.docc/RichTextKit.md | 3 - .../RichTextAction+Deprecated.swift | 9 ++ 15 files changed, 319 insertions(+), 304 deletions(-) create mode 100644 Sources/RichTextKit/Actions/RichTextAction+Button.swift create mode 100644 Sources/RichTextKit/Actions/RichTextAction+ButtonGroup.swift create mode 100644 Sources/RichTextKit/Actions/RichTextAction+ButtonStack.swift delete mode 100644 Sources/RichTextKit/Actions/RichTextActionButton.swift delete mode 100644 Sources/RichTextKit/Actions/RichTextActionButtonGroup.swift delete mode 100644 Sources/RichTextKit/Actions/RichTextActionButtonStack.swift diff --git a/Demo/macOS/EditorScreen.swift b/Demo/macOS/EditorScreen.swift index 202d880d3..d117e7ba7 100644 --- a/Demo/macOS/EditorScreen.swift +++ b/Demo/macOS/EditorScreen.swift @@ -32,7 +32,7 @@ struct EditorScreen: View { } .toolbar { ToolbarItem(placement: .automatic) { - RichTextActionButtonStack( + RichTextAction.ButtonStack( context: context, actions: [.undo, .redo, .copy] ) diff --git a/Sources/RichTextKit/Actions/RichTextAction+Button.swift b/Sources/RichTextKit/Actions/RichTextAction+Button.swift new file mode 100644 index 000000000..18e422315 --- /dev/null +++ b/Sources/RichTextKit/Actions/RichTextAction+Button.swift @@ -0,0 +1,119 @@ +// +// RichTextActionButton.swift +// RichTextKit +// +// Created by Daniel Saidi on 2022-12-08. +// Copyright © 2022-2024 Daniel Saidi. All rights reserved. +// + +import SwiftUI + +public extension RichTextAction { + + /** + This button can be used to trigger a ``RichTextAction``. + + This renders a plain `Button`, which means that you can + use and configure it as a normal button. + */ + struct Button: View { + + /** + Create a rich text action button. + + - Parameters: + - action: The action to trigger. + - context: The context to affect. + - fillVertically: WhetherP or not fill up vertical space, by default `false`. + */ + public init( + action: RichTextAction, + context: RichTextContext, + fillVertically: Bool = false + ) { + self.action = action + self._context = ObservedObject(wrappedValue: context) + self.fillVertically = fillVertically + } + + private let action: RichTextAction + private let fillVertically: Bool + + @ObservedObject + private var context: RichTextContext + + public var body: some View { + SwiftUI.Button(action: triggerAction) { + action.icon + .frame(maxHeight: fillVertically ? .infinity : nil) + .contentShape(Rectangle()) + } + .keyboardShortcut(for: action) + .accessibilityLabel(action.title) + .disabled(!context.canHandle(action)) + } + } +} + +private extension RichTextAction.Button { + + func triggerAction() { + context.handle(action) + } +} + +struct RichTextAction_Button_Previews: PreviewProvider { + + struct Preview: View { + + @StateObject + private var context = RichTextContext() + + var body: some View { + HStack { + RichTextAction.Button( + action: .copy, + context: context, + fillVertically: true + ) + RichTextAction.Button( + action: .redoLatestChange, + context: context, + fillVertically: true + ) + RichTextAction.Button( + action: .undoLatestChange, + context: context, + fillVertically: true + ) + RichTextAction.Button( + action: .stepFontSize(points: 1), + context: context, + fillVertically: true + ) + RichTextAction.Button( + action: .stepFontSize(points: -1), + context: context, + fillVertically: true + ) + RichTextAction.Button( + action: .decreaseIndent(), + context: context, + fillVertically: true + ) + RichTextAction.Button( + action: .increaseIndent(), + context: context, + fillVertically: true + ) + } + .fixedSize(horizontal: false, vertical: true) + .padding() + .buttonStyle(.bordered) + } + } + + static var previews: some View { + Preview() + } +} diff --git a/Sources/RichTextKit/Actions/RichTextAction+ButtonGroup.swift b/Sources/RichTextKit/Actions/RichTextAction+ButtonGroup.swift new file mode 100644 index 000000000..33866cbba --- /dev/null +++ b/Sources/RichTextKit/Actions/RichTextAction+ButtonGroup.swift @@ -0,0 +1,102 @@ +// +// RichTextActionButtonGroup.swift +// RichTextKit +// +// Created by Daniel Saidi on 2022-12-08. +// Copyright © 2022-2024 Daniel Saidi. All rights reserved. +// + +#if iOS || macOS || os(visionOS) +import SwiftUI + +public extension RichTextAction { + + /** + This view lists ``RichTextAction`` buttons in a group. + + Since this view uses multiple values, it binds directly + to a ``RichTextContext`` instead of individual values. + */ + struct ButtonGroup: View { + + /** + Create a rich text action button stack. + + - Parameters: + - context: The context to affect. + - actions: The actions to list, by default all non-size actions. + - greedy: Whether or not the group is horizontally greedy, by default `true`. + */ + public init( + context: RichTextContext, + actions: [RichTextAction], + greedy: Bool = true + ) { + self._context = ObservedObject(wrappedValue: context) + self.actions = actions + self.isGreedy = greedy + } + + private let actions: [RichTextAction] + private let isGreedy: Bool + + @ObservedObject + private var context: RichTextContext + + public var body: some View { + ControlGroup { + ForEach(actions) { + RichTextAction.Button( + action: $0, + context: context, + fillVertically: true + ) + } + } + .frame(width: groupWidth) + } + } +} + +private extension RichTextAction.ButtonGroup { + + var groupWidth: CGFloat? { + if isGreedy { return nil } + let count = Double(actions.count) + #if macOS + return 30 * count + #else + return 50 * count + #endif + } +} + +struct RichTextAction_ButtonGroup_Previews: PreviewProvider { + + struct Preview: View { + + @StateObject + private var context = RichTextContext() + + func group(greedy: Bool) -> some View { + RichTextAction.ButtonGroup( + context: context, + actions: [.undoLatestChange, .redoLatestChange, .copy], + greedy: greedy + ) + } + + var body: some View { + VStack { + group(greedy: true) + group(greedy: false) + } + .padding() + } + } + + static var previews: some View { + Preview() + } +} +#endif diff --git a/Sources/RichTextKit/Actions/RichTextAction+ButtonStack.swift b/Sources/RichTextKit/Actions/RichTextAction+ButtonStack.swift new file mode 100644 index 000000000..b00b37590 --- /dev/null +++ b/Sources/RichTextKit/Actions/RichTextAction+ButtonStack.swift @@ -0,0 +1,80 @@ +// +// RichTextAction+ButtonStack.swift +// RichTextKit +// +// Created by Daniel Saidi on 2023-06-01. +// Copyright © 2023-2024 Daniel Saidi. All rights reserved. +// + +import SwiftUI + +public extension RichTextAction { + + /** + This view lists ``RichTextAction`` buttons in a stack. + + Since this view controls multiple values, it binds directly + to a ``RichTextContext`` instead of to individual values. + */ + struct ButtonStack: View { + + /** + Create a rich text action button stack. + + - Parameters: + - context: The context to affect. + - actions: The actions to list, by default all non-size actions. + - spacing: The spacing to apply to stack items, by default `5`. + */ + public init( + context: RichTextContext, + actions: [RichTextAction], + spacing: Double = 5 + ) { + self._context = ObservedObject(wrappedValue: context) + self.actions = actions + self.spacing = spacing + } + + private let actions: [RichTextAction] + private let spacing: Double + + @ObservedObject + private var context: RichTextContext + + public var body: some View { + HStack(spacing: spacing) { + ForEach(actions) { + RichTextAction.Button( + action: $0, + context: context, + fillVertically: true + ).frame(maxHeight: .infinity) + } + } + .fixedSize(horizontal: false, vertical: true) + } + } +} + +struct RichTextAction_ButtonStack_Previews: PreviewProvider { + + struct Preview: View { + + @StateObject + private var context = RichTextContext() + + var body: some View { + RichTextAction.ButtonStack( + context: context, + actions: [.undoLatestChange, .redoLatestChange, .copy] + ) + .buttonStyle(.bordered) + .padding() + } + } + + static var previews: some View { + Preview() + } +} diff --git a/Sources/RichTextKit/Actions/RichTextAction+KeyboardShortcutModifier.swift b/Sources/RichTextKit/Actions/RichTextAction+KeyboardShortcutModifier.swift index 9f3de77b5..9b8efde16 100644 --- a/Sources/RichTextKit/Actions/RichTextAction+KeyboardShortcutModifier.swift +++ b/Sources/RichTextKit/Actions/RichTextAction+KeyboardShortcutModifier.swift @@ -3,7 +3,7 @@ // RichTextKit // // Created by Daniel Saidi on 2022-12-13. -// Copyright © 2022-2023 Daniel Saidi. All rights reserved. +// Copyright © 2022-2024 Daniel Saidi. All rights reserved. // import SwiftUI diff --git a/Sources/RichTextKit/Actions/RichTextAction.swift b/Sources/RichTextKit/Actions/RichTextAction.swift index cf989a99a..b23783579 100644 --- a/Sources/RichTextKit/Actions/RichTextAction.swift +++ b/Sources/RichTextKit/Actions/RichTextAction.swift @@ -3,7 +3,7 @@ // RichTextKit // // Created by Daniel Saidi on 2022-12-08. -// Copyright © 2022-2023 Daniel Saidi. All rights reserved. +// Copyright © 2022-2024 Daniel Saidi. All rights reserved. // import SwiftUI diff --git a/Sources/RichTextKit/Actions/RichTextActionButton.swift b/Sources/RichTextKit/Actions/RichTextActionButton.swift deleted file mode 100644 index e4d96045a..000000000 --- a/Sources/RichTextKit/Actions/RichTextActionButton.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// RichTextActionButton.swift -// RichTextKit -// -// Created by Daniel Saidi on 2022-12-08. -// Copyright © 2022-2023 Daniel Saidi. All rights reserved. -// - -import SwiftUI - -/** - This button can be used to trigger a ``RichTextAction``. - - This renders a plain `Button`, which means that you can use - and configure it as normal. - */ -public struct RichTextActionButton: View { - - /** - Create a rich text action button. - - - Parameters: - - action: The action to trigger. - - context: The context to affect. - - fillVertically: Whether or not fill up vertical space, by default `false`. - */ - public init( - action: RichTextAction, - context: RichTextContext, - fillVertically: Bool = false - ) { - self.action = action - self._context = ObservedObject(wrappedValue: context) - self.fillVertically = fillVertically - } - - private let action: RichTextAction - private let fillVertically: Bool - - @ObservedObject - private var context: RichTextContext - - public var body: some View { - Button(action: triggerAction) { - action.icon - .frame(maxHeight: fillVertically ? .infinity : nil) - .contentShape(Rectangle()) - } - .keyboardShortcut(for: action) - .accessibilityLabel(action.title) - .disabled(!context.canHandle(action)) - } -} - -private extension RichTextActionButton { - - func triggerAction() { - context.handle(action) - } -} - -struct RichTextActionButton_Previews: PreviewProvider { - - struct Preview: View { - - @StateObject - private var context = RichTextContext() - - var body: some View { - HStack { - RichTextActionButton( - action: .copy, - context: context, - fillVertically: true - ) - RichTextActionButton( - action: .redoLatestChange, - context: context, - fillVertically: true - ) - RichTextActionButton( - action: .undoLatestChange, - context: context, - fillVertically: true - ) - RichTextActionButton( - action: .stepFontSize(points: 1), - context: context, - fillVertically: true - ) - RichTextActionButton( - action: .stepFontSize(points: -1), - context: context, - fillVertically: true - ) - RichTextActionButton( - action: .decreaseIndent(), - context: context, - fillVertically: true - ) - RichTextActionButton( - action: .increaseIndent(), - context: context, - fillVertically: true - ) - } - .fixedSize(horizontal: false, vertical: true) - .padding() - .buttonStyle(.bordered) - } - } - - static var previews: some View { - Preview() - } -} diff --git a/Sources/RichTextKit/Actions/RichTextActionButtonGroup.swift b/Sources/RichTextKit/Actions/RichTextActionButtonGroup.swift deleted file mode 100644 index e715a8307..000000000 --- a/Sources/RichTextKit/Actions/RichTextActionButtonGroup.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// RichTextActionButtonGroup.swift -// RichTextKit -// -// Created by Daniel Saidi on 2022-12-08. -// Copyright © 2022-2023 Daniel Saidi. All rights reserved. -// - -#if iOS || macOS || os(visionOS) -import SwiftUI - -/** - This view lists ``RichTextAction`` buttons in a solid group. - - Since this view controls multiple values, it binds directly - to a ``RichTextContext`` instead of to individual values. - */ -public struct RichTextActionButtonGroup: View { - - /** - Create a rich text action button stack. - - - Parameters: - - context: The context to affect. - - actions: The actions to list, by default all non-size actions. - - greedy: Whether or not the group is horizontally greedy, by default `true`. - */ - public init( - context: RichTextContext, - actions: [RichTextAction], - greedy: Bool = true - ) { - self._context = ObservedObject(wrappedValue: context) - self.actions = actions - self.isGreedy = greedy - } - - private let actions: [RichTextAction] - private let isGreedy: Bool - - @ObservedObject - private var context: RichTextContext - - public var body: some View { - ControlGroup { - ForEach(actions) { - RichTextActionButton( - action: $0, - context: context, - fillVertically: true - ) - } - } - .frame(width: groupWidth) - } -} - -private extension RichTextActionButtonGroup { - - var groupWidth: CGFloat? { - if isGreedy { return nil } - let count = Double(actions.count) - #if macOS - return 30 * count - #else - return 50 * count - #endif - } -} - -struct RichTextActionButtonGroup_Previews: PreviewProvider { - - struct Preview: View { - - @StateObject - private var context = RichTextContext() - - func group(greedy: Bool) -> some View { - RichTextActionButtonGroup( - context: context, - actions: [.undoLatestChange, .redoLatestChange, .copy], - greedy: greedy - ) - } - - var body: some View { - VStack { - group(greedy: true) - group(greedy: false) - } - .padding() - } - } - - static var previews: some View { - Preview() - } -} -#endif diff --git a/Sources/RichTextKit/Actions/RichTextActionButtonStack.swift b/Sources/RichTextKit/Actions/RichTextActionButtonStack.swift deleted file mode 100644 index 48d6562bb..000000000 --- a/Sources/RichTextKit/Actions/RichTextActionButtonStack.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// RichTextActionButtonStack.swift -// RichTextKit -// -// Created by Daniel Saidi on 2023-06-01. -// Copyright © 2023 Daniel Saidi. All rights reserved. -// - -import SwiftUI - -/** - This view lists ``RichTextAction`` buttons in a stack. - - Since this view controls multiple values, it binds directly - to a ``RichTextContext`` instead of to individual values. - */ -public struct RichTextActionButtonStack: View { - - /** - Create a rich text action button stack. - - - Parameters: - - context: The context to affect. - - actions: The actions to list, by default all non-size actions. - - spacing: The spacing to apply to stack items, by default `5`. - */ - public init( - context: RichTextContext, - actions: [RichTextAction], - spacing: Double = 5 - ) { - self._context = ObservedObject(wrappedValue: context) - self.actions = actions - self.spacing = spacing - } - - private let actions: [RichTextAction] - private let spacing: Double - - @ObservedObject - private var context: RichTextContext - - public var body: some View { - HStack(spacing: spacing) { - ForEach(actions) { - RichTextActionButton( - action: $0, - context: context, - fillVertically: true - ).frame(maxHeight: .infinity) - } - } - .fixedSize(horizontal: false, vertical: true) - } -} - -struct RichTextActionButtonStack_Previews: PreviewProvider { - - struct Preview: View { - - @StateObject - private var context = RichTextContext() - - var body: some View { - RichTextActionButtonStack( - context: context, - actions: [.undoLatestChange, .redoLatestChange, .copy] - ) - .buttonStyle(.bordered) - .padding() - } - } - - static var previews: some View { - Preview() - } -} diff --git a/Sources/RichTextKit/Fonts/RichTextFontSizePickerStack.swift b/Sources/RichTextKit/Fonts/RichTextFontSizePickerStack.swift index 4f7aedcdf..404d03907 100644 --- a/Sources/RichTextKit/Fonts/RichTextFontSizePickerStack.swift +++ b/Sources/RichTextKit/Fonts/RichTextFontSizePickerStack.swift @@ -70,7 +70,7 @@ private extension RichTextFontSizePickerStack { } var decreaseButton: some View { - RichTextActionButton( + RichTextAction.Button( action: .decreaseFontSize(), context: context, fillVertically: true @@ -78,7 +78,7 @@ private extension RichTextFontSizePickerStack { } var increaseButton: some View { - RichTextActionButton( + RichTextAction.Button( action: .increaseFontSize(), context: context, fillVertically: true diff --git a/Sources/RichTextKit/Format/RichTextFormatSheet.swift b/Sources/RichTextKit/Format/RichTextFormatSheet.swift index 125919466..4987e6425 100644 --- a/Sources/RichTextKit/Format/RichTextFormatSheet.swift +++ b/Sources/RichTextKit/Format/RichTextFormatSheet.swift @@ -125,7 +125,7 @@ private extension RichTextFormatSheet { @ViewBuilder var indentButtons: some View { - RichTextActionButtonGroup( + RichTextAction.ButtonGroup( context: context, actions: [.decreaseIndent(), .increaseIndent()], greedy: false diff --git a/Sources/RichTextKit/Format/RichTextFormatSidebar.swift b/Sources/RichTextKit/Format/RichTextFormatSidebar.swift index 0db1b2c4e..9f9882bf4 100644 --- a/Sources/RichTextKit/Format/RichTextFormatSidebar.swift +++ b/Sources/RichTextKit/Format/RichTextFormatSidebar.swift @@ -56,7 +56,7 @@ public struct RichTextFormatSidebar: View { SidebarSection(title: nil) { RichTextAlignmentPicker(selection: $context.textAlignment) .pickerStyle(.segmented) - RichTextActionButtonGroup( + RichTextAction.ButtonGroup( context: context, actions: [.decreaseIndent(), .increaseIndent()] ) diff --git a/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar.swift b/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar.swift index a7b94ce3e..f483f70b4 100644 --- a/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar.swift +++ b/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar.swift @@ -175,7 +175,7 @@ private extension RichTextKeyboardToolbar { @ViewBuilder var leadingViews: some View { - RichTextActionButtonStack( + RichTextAction.ButtonStack( context: context, actions: leadingActions, spacing: style.itemSpacing @@ -206,7 +206,7 @@ private extension RichTextKeyboardToolbar { trailingButtons() - RichTextActionButtonStack( + RichTextAction.ButtonStack( context: context, actions: trailingActions, spacing: style.itemSpacing diff --git a/Sources/RichTextKit/RichTextKit.docc/RichTextKit.md b/Sources/RichTextKit/RichTextKit.docc/RichTextKit.md index 15e117f7b..e7b3703ba 100644 --- a/Sources/RichTextKit/RichTextKit.docc/RichTextKit.md +++ b/Sources/RichTextKit/RichTextKit.docc/RichTextKit.md @@ -67,9 +67,6 @@ RichTextKit is available under the MIT license. See the [LICENSE][License] file ### Actions - ``RichTextAction`` -- ``RichTextActionButton`` -- ``RichTextActionButtonGroup`` -- ``RichTextActionButtonStack`` ### Alignment diff --git a/Sources/RichTextKit/_Deprecated/RichTextAction+Deprecated.swift b/Sources/RichTextKit/_Deprecated/RichTextAction+Deprecated.swift index 7a6422d97..4dc4c4698 100644 --- a/Sources/RichTextKit/_Deprecated/RichTextAction+Deprecated.swift +++ b/Sources/RichTextKit/_Deprecated/RichTextAction+Deprecated.swift @@ -38,3 +38,12 @@ public extension RichTextAction { decreaseSuperscript() } } + +@available(*, deprecated, renamed: "RichTextAction.Button") +public typealias RichTextActionButton = RichTextAction.Button + +@available(*, deprecated, renamed: "RichTextAction.ButtonGroup") +public typealias RichTextActionButtonGroup = RichTextAction.ButtonGroup + +@available(*, deprecated, renamed: "RichTextAction.ButtonStack") +public typealias RichTextActionButtonStack = RichTextAction.ButtonStack