From ee3134bf90cc9a0a79833757de4a595d7bb72b6d Mon Sep 17 00:00:00 2001 From: Daniel Saidi Date: Mon, 4 Mar 2024 15:44:15 +0100 Subject: [PATCH] Add font picker config environment value --- RELEASE_NOTES.md | 9 +- .../Editor/RichTextEditor+Config.swift | 2 +- .../Editor/RichTextEditor+Style.swift | 2 +- .../Editor/RichTextView+Config.swift | 6 +- .../Editor/RichTextView+Theme.swift | 8 +- .../Fonts/RichTextFont+ForEachPicker.swift | 48 ++++++----- .../Fonts/RichTextFont+ListPicker.swift | 42 +++++---- .../Fonts/RichTextFont+Picker.swift | 35 +++++--- .../Fonts/RichTextFont+PickerConfig.swift | 85 +++++++++++++++++++ .../RichTextFormatToolbar+Configuration.swift | 4 +- .../Format/RichTextFormatToolbarBase.swift | 5 +- .../RichTextKeyboardToolbar+Config.swift | 4 +- .../RichTextKeyboardToolbar+Style.swift | 8 +- .../Pdf/PdfPageConfiguration.swift | 10 +-- .../Styles/RichTextHighlightingStyle.swift | 11 +-- 15 files changed, 196 insertions(+), 83 deletions(-) create mode 100644 Sources/RichTextKit/Fonts/RichTextFont+PickerConfig.swift diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 194ad276f..157c8a2f3 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -19,9 +19,12 @@ This release removes all deprecated code and cleans up the library. * All previously deprecated code has been deleted. -* `RichTextContextFocusedValueKey` is renamed to `RichTextContext.FocusedValueKey` -* `RichTextEditor` is configured with view modifiers instead of the initializer. -* `RichTextKeyboardToolbar` is configured with view modifiers instead of the initializer. +* `RichTextContextFocusedValueKey` has been renamed to `RichTextContext.FocusedValueKey` +* `RichTextEditor` is now configured and styled with view modifiers instead of with the initializer. +* `RichTextFont` pickers are now configured with a shared view modifier instead of with the initializer. +* `RichTextKeyboardToolbar` is now configured and styled with view modifiers instead of with the initializer. + + diff --git a/Sources/RichTextKit/Editor/RichTextEditor+Config.swift b/Sources/RichTextKit/Editor/RichTextEditor+Config.swift index 34cbc199d..fffdb927b 100644 --- a/Sources/RichTextKit/Editor/RichTextEditor+Config.swift +++ b/Sources/RichTextKit/Editor/RichTextEditor+Config.swift @@ -22,7 +22,7 @@ public extension View { } } -extension RichTextEditorConfig { +private extension RichTextEditorConfig { struct Key: EnvironmentKey { diff --git a/Sources/RichTextKit/Editor/RichTextEditor+Style.swift b/Sources/RichTextKit/Editor/RichTextEditor+Style.swift index da3c9c214..2c5543f62 100644 --- a/Sources/RichTextKit/Editor/RichTextEditor+Style.swift +++ b/Sources/RichTextKit/Editor/RichTextEditor+Style.swift @@ -22,7 +22,7 @@ public extension View { } } -extension RichTextEditorStyle { +private extension RichTextEditorStyle { struct Key: EnvironmentKey { diff --git a/Sources/RichTextKit/Editor/RichTextView+Config.swift b/Sources/RichTextKit/Editor/RichTextView+Config.swift index 46df9e4df..3cda45ada 100644 --- a/Sources/RichTextKit/Editor/RichTextView+Config.swift +++ b/Sources/RichTextKit/Editor/RichTextView+Config.swift @@ -10,7 +10,9 @@ import Foundation #if iOS || macOS || os(tvOS) || os(visionOS) public extension RichTextView.Configuration { - /// Get a standard rich text editor configuration. - static var standard: Self { .init() } + /// The standard rich text view configuration. + /// + /// You can set a new value to change the global default. + static var standard = Self() } #endif diff --git a/Sources/RichTextKit/Editor/RichTextView+Theme.swift b/Sources/RichTextKit/Editor/RichTextView+Theme.swift index 2b8edfaab..51e6c6665 100644 --- a/Sources/RichTextKit/Editor/RichTextView+Theme.swift +++ b/Sources/RichTextKit/Editor/RichTextView+Theme.swift @@ -40,8 +40,10 @@ public extension RichTextView { } public extension RichTextView.Theme { - - /// Get a standard rich text editor configuration. - static var standard: Self { .init() } + + /// The standard rich text view theme. + /// + /// You can set a new value to change the global default. + static var standard = Self() } #endif diff --git a/Sources/RichTextKit/Fonts/RichTextFont+ForEachPicker.swift b/Sources/RichTextKit/Fonts/RichTextFont+ForEachPicker.swift index 76cb8f5de..4ee41a7b5 100644 --- a/Sources/RichTextKit/Fonts/RichTextFont+ForEachPicker.swift +++ b/Sources/RichTextKit/Fonts/RichTextFont+ForEachPicker.swift @@ -14,8 +14,20 @@ public extension RichTextFont { This view uses a plain `ForEach` to list a set of fonts, of which one can be selected. - Unlike ``RichTextFont/Picker`` this view displays fonts - on all platforms. It must be actively added & presented. + Unlike ``RichTextFont/Picker`` this picker presents all + pickers with proper previews on all platforms. You must + therefore add it ina way that gives it space. + + You can configure this picker by applying a config view + modifier to your view hierarchy: + + ```swift + VStack { + RichTextFont.ForEachPicker(...) + ... + } + .richTextFontPickerConfig(...) + ``` */ struct ForEachPicker: View { @@ -24,24 +36,15 @@ public extension RichTextFont { - Parameters: - selection: The selected font name. - - selectionTopmost: Whether or not to place the selected font topmost. - - fonts: The fonts to display in the list, by default `all`. - - fontSize: The font size to use in the list items. - - dismissAfterPick: Whether or not to dismiss the picker after a font has been selected, by default `false`. */ public init( - selection: Binding, - selectionTopmost: Bool = true, - fonts: [Font] = .all, - fontSize: CGFloat = 20, - dismissAfterPick: Bool = false + selection: Binding ) { self._selection = selection - self.fonts = fonts - self.fontSize = fontSize - self.dismissAfterPick = dismissAfterPick - if selectionTopmost { - self.fonts = self.fonts.moveTopmost(selection.wrappedValue) + self.fonts = .all + self.fonts = config.fonts + if config.moveSelectionTopmost { + self.fonts = config.fonts.moveTopmost(selection.wrappedValue) } } @@ -49,11 +52,12 @@ public extension RichTextFont { public typealias FontName = String private var fonts: [Font] - private let fontSize: CGFloat - private let dismissAfterPick: Bool @Binding private var selection: FontName + + @Environment(\.richTextFontPickerConfig) + private var config public var body: some View { let font = Binding( @@ -64,11 +68,11 @@ public extension RichTextFont { RichTextKit.ForEachPicker( items: fonts, selection: font, - dismissAfterPick: dismissAfterPick + dismissAfterPick: config.dismissAfterPick ) { font, isSelected in RichTextFont.PickerItem( font: font, - fontSize: fontSize, + fontSize: config.fontSize, isSelected: isSelected ) } @@ -87,12 +91,12 @@ struct RichTextFont_ForEachPicker_Previews: PreviewProvider { NavigationView { List { RichTextFont.ForEachPicker( - selection: $selection, - selectionTopmost: false + selection: $selection ) } .withTitle("Pick a font") } + .richTextFontPickerConfig(.init(moveSelectionTopmost: true)) } } diff --git a/Sources/RichTextKit/Fonts/RichTextFont+ListPicker.swift b/Sources/RichTextKit/Fonts/RichTextFont+ListPicker.swift index aca1730b3..69529eb56 100644 --- a/Sources/RichTextKit/Fonts/RichTextFont+ListPicker.swift +++ b/Sources/RichTextKit/Fonts/RichTextFont+ListPicker.swift @@ -13,21 +13,29 @@ public extension RichTextFont { /** This view uses a `List` to list a set of fonts of which one can be selected. - - Unlike ``RichTextFont/Picker`` this view displays fonts - on all platforms. It must be actively added & presented. + + Unlike ``RichTextFont/Picker`` this picker presents all + pickers with proper previews on all platforms. You must + therefore add it ina way that gives it space. + + You can configure this picker by applying a config view + modifier to your view hierarchy: + + ```swift + VStack { + RichTextFont.ListPicker(...) + ... + } + .richTextFontPickerConfig(...) + ``` */ struct ListPicker: View { /** - Create a font picker. + Create a font list picker. - Parameters: - selection: The selected font name. - - selectionTopmost: Whether or not to place the selected font topmost. - - fonts: The fonts to display in the list, by default `all`. - - fontSize: The font size to use in the list items. - - dismissAfterPick: Whether or not to dismiss the picker after a font has been selected, by default `true`. */ public init( selection: Binding, @@ -37,11 +45,10 @@ public extension RichTextFont { dismissAfterPick: Bool = true ) { self._selection = selection - self.fonts = fonts ?? .all - self.fontSize = fontSize - self.dismissAfterPick = dismissAfterPick - if selectionTopmost { - self.fonts = self.fonts.moveTopmost(selection.wrappedValue) + self.fonts = .all + self.fonts = config.fonts + if config.moveSelectionTopmost { + self.fonts = config.fonts.moveTopmost(selection.wrappedValue) } } @@ -49,11 +56,12 @@ public extension RichTextFont { public typealias FontName = String private var fonts: [Font] - private let fontSize: CGFloat - private let dismissAfterPick: Bool @Binding private var selection: FontName + + @Environment(\.richTextFontPickerConfig) + private var config public var body: some View { let font = Binding( @@ -64,11 +72,11 @@ public extension RichTextFont { RichTextKit.ListPicker( items: fonts, selection: font, - dismissAfterPick: dismissAfterPick + dismissAfterPick: config.dismissAfterPick ) { font, isSelected in RichTextFont.PickerItem( font: font, - fontSize: fontSize, + fontSize: config.fontSize, isSelected: isSelected ) } diff --git a/Sources/RichTextKit/Fonts/RichTextFont+Picker.swift b/Sources/RichTextKit/Fonts/RichTextFont+Picker.swift index 682e0f012..9471a4c56 100644 --- a/Sources/RichTextKit/Fonts/RichTextFont+Picker.swift +++ b/Sources/RichTextKit/Fonts/RichTextFont+Picker.swift @@ -18,6 +18,19 @@ public extension RichTextFont { macOS, but not on iOS. To render fonts correctly on all platforms, you can use a ``RichTextFont/ListPicker`` or a ``RichTextFont/ForEachPicker``. + + You can configure this picker by applying a config view + modifier to your view hierarchy: + + ```swift + VStack { + RichTextFont.Picker(...) + ... + } + .richTextFontPickerConfig(...) + ``` + + Note that this picker will not apply all configurations. */ struct Picker: View { @@ -26,36 +39,32 @@ public extension RichTextFont { - Parameters: - selection: The selected font name. - - fonts: The fonts to display in the list, by default `all`. - - fontSize: The font size to use in the list items. */ public init( - selection: Binding, - fonts: [Font] = .all, - fontSize: CGFloat = 20 + selection: Binding ) { self._selection = selection - self.fonts = fonts - self.itemFontSize = fontSize - self.selectedFont = fonts.last { $0.matches(selection.wrappedValue) } + self.selectedFont = nil + self.selectedFont = config.fonts.last { $0.matches(selection.wrappedValue) } } public typealias Font = RichTextFont.PickerFont public typealias FontName = String - private let fonts: [Font] - private let itemFontSize: CGFloat - private let selectedFont: Font? + private var selectedFont: Font? @Binding private var selection: FontName + + @Environment(\.richTextFontPickerConfig) + private var config public var body: some View { SwiftUI.Picker(selection: $selection) { - ForEach(fonts) { font in + ForEach(config.fonts) { font in RichTextFont.PickerItem( font: font, - fontSize: itemFontSize, + fontSize: config.fontSize, isSelected: false ) .tag(font.tag(for: selectedFont, selectedName: selection)) diff --git a/Sources/RichTextKit/Fonts/RichTextFont+PickerConfig.swift b/Sources/RichTextKit/Fonts/RichTextFont+PickerConfig.swift new file mode 100644 index 000000000..84fd51030 --- /dev/null +++ b/Sources/RichTextKit/Fonts/RichTextFont+PickerConfig.swift @@ -0,0 +1,85 @@ +// +// RichTextFont+PickerConfig.swift +// RichTextKit +// +// Created by Daniel Saidi on 2024-03-04. +// Copyright © 2024 Daniel Saidi. All rights reserved. +// + +import SwiftUI + +public extension RichTextFont { + + /// This struct can configure a ``RichTextFont/Picker``. + /// + /// This configuration contains configuration properties + /// for many different font pickers types. Some of these + /// properties are not used in some pickers. + struct PickerConfig { + + /// Create a custom rich text font picker config. + /// + /// - Parameters: + /// - fonts: The fonts to display in the list, by default `all`. + /// - fontSize: The font size to use in the list items, by default `20`. + /// - dismissAfterPick: Whether or not to dismiss the picker after a font is selected, by default `false`. + /// - moveSelectionTopmost: Whether or not to place the selected font topmost, by default `true`. + public init( + fonts: [RichTextFont.PickerFont] = .all, + fontSize: CGFloat = 20, + dismissAfterPick: Bool = false, + moveSelectionTopmost: Bool = true + ) { + self.fonts = fonts + self.fontSize = fontSize + self.dismissAfterPick = dismissAfterPick + self.moveSelectionTopmost = moveSelectionTopmost + } + + /// The fonts to display in the list. + public var fonts: [RichTextFont.PickerFont] + + /// The font size to use in the list items. + public var fontSize: CGFloat + + /// Whether or not to dismiss the picker after a font is selected. + public var dismissAfterPick: Bool + + /// Whether or not to move the selected font topmost + public var moveSelectionTopmost: Bool + } +} + +public extension RichTextFont.PickerConfig { + + /// The standard rich text font picker configuration. + /// + /// You can set a new value to change the global default. + static var standard = Self() +} + +public extension View { + + /// Apply a ``RichTextFont`` picker configuration. + func richTextFontPickerConfig( + _ config: RichTextFont.PickerConfig + ) -> some View { + self.environment(\.richTextFontPickerConfig, config) + } +} + +private extension RichTextFont.PickerConfig { + + struct Key: EnvironmentKey { + + public static var defaultValue: RichTextFont.PickerConfig = .standard + } +} + +public extension EnvironmentValues { + + var richTextFontPickerConfig: RichTextFont.PickerConfig { + get { self [RichTextFont.PickerConfig.Key.self] } + set { self [RichTextFont.PickerConfig.Key.self] = newValue } + } +} diff --git a/Sources/RichTextKit/Format/RichTextFormatToolbar+Configuration.swift b/Sources/RichTextKit/Format/RichTextFormatToolbar+Configuration.swift index 93c37fd01..5744361e8 100644 --- a/Sources/RichTextKit/Format/RichTextFormatToolbar+Configuration.swift +++ b/Sources/RichTextKit/Format/RichTextFormatToolbar+Configuration.swift @@ -55,6 +55,8 @@ public extension RichTextFormatToolbar { public extension RichTextFormatToolbar.Configuration { /// The standard rich text format toolbar configuration. - static var standard = Self.init() + /// + /// You can set a new value to change the global default. + static var standard = Self() } #endif diff --git a/Sources/RichTextKit/Format/RichTextFormatToolbarBase.swift b/Sources/RichTextKit/Format/RichTextFormatToolbarBase.swift index c30769454..57453d85b 100644 --- a/Sources/RichTextKit/Format/RichTextFormatToolbarBase.swift +++ b/Sources/RichTextKit/Format/RichTextFormatToolbarBase.swift @@ -102,7 +102,10 @@ extension RichTextFormatToolbarBase { value: Binding ) -> some View { if config.fontPicker { - RichTextFont.Picker(selection: value, fontSize: 12) + RichTextFont.Picker( + selection: value + ) + .richTextFontPickerConfig(.init(fontSize: 12)) } } diff --git a/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar+Config.swift b/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar+Config.swift index 766b8858e..29e2c5f17 100644 --- a/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar+Config.swift +++ b/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar+Config.swift @@ -40,7 +40,7 @@ public struct RichTextKeyboardToolbarConfig { public extension RichTextKeyboardToolbarConfig { - /// A standard rich text keyboard toolbar configuration. + /// The standard rich text keyboard toolbar config. /// /// You can override this to change the global default. static var standard = RichTextKeyboardToolbarConfig() @@ -56,7 +56,7 @@ public extension View { } } -extension RichTextKeyboardToolbarConfig { +private extension RichTextKeyboardToolbarConfig { struct Key: EnvironmentKey { diff --git a/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar+Style.swift b/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar+Style.swift index 650a870d4..34806e8a3 100644 --- a/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar+Style.swift +++ b/Sources/RichTextKit/Keyboard/RichTextKeyboardToolbar+Style.swift @@ -46,10 +46,10 @@ public struct RichTextKeyboardToolbarStyle { public extension RichTextKeyboardToolbarStyle { - /// A standard rich text keyboard toolbar style. + /// The standard rich text keyboard toolbar style. /// - /// You can override this to change the global default. - static var standard = RichTextKeyboardToolbarStyle() + /// You can set a new value to change the global default. + static var standard = Self() } public extension View { @@ -62,7 +62,7 @@ public extension View { } } -extension RichTextKeyboardToolbarStyle { +private extension RichTextKeyboardToolbarStyle { struct Key: EnvironmentKey { diff --git a/Sources/RichTextKit/Pdf/PdfPageConfiguration.swift b/Sources/RichTextKit/Pdf/PdfPageConfiguration.swift index 5285294fd..5fb7f3d3d 100644 --- a/Sources/RichTextKit/Pdf/PdfPageConfiguration.swift +++ b/Sources/RichTextKit/Pdf/PdfPageConfiguration.swift @@ -34,12 +34,10 @@ public struct PdfPageConfiguration: Equatable { public extension PdfPageConfiguration { - /** - The standard PDF page configuration. - - You can override this value to change the global config. - */ - static var standard = PdfPageConfiguration() + /// The standard PDF page configuration. + /// + /// You can override this to change the global default. + static var standard = Self() } public extension PdfPageConfiguration { diff --git a/Sources/RichTextKit/Styles/RichTextHighlightingStyle.swift b/Sources/RichTextKit/Styles/RichTextHighlightingStyle.swift index 7585a361c..d10ee1c63 100644 --- a/Sources/RichTextKit/Styles/RichTextHighlightingStyle.swift +++ b/Sources/RichTextKit/Styles/RichTextHighlightingStyle.swift @@ -37,11 +37,8 @@ public struct RichTextHighlightingStyle: Equatable, Hashable { public extension RichTextHighlightingStyle { - /** - The standard rich text highlighting style, which uses a - clear background color and an accent foreground color. - - You can override this value to change the global style. - */ - static var standard = RichTextHighlightingStyle() + /// The standard rich text highlighting style. + /// + /// You can set a new value to change the global default. + static var standard = Self() }