-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support font color customization (#55)
- Loading branch information
1 parent
c98b319
commit 8573289
Showing
25 changed files
with
1,934 additions
and
196 deletions.
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
Sources/RichEditorSwiftUI/Alignment/RichTextAlignment+Picker.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// | ||
// RichTextAlignment+Picker.swift | ||
// RichEditorSwiftUI | ||
// | ||
// Created by Divyesh Vekariya on 18/11/24. | ||
// | ||
|
||
import SwiftUI | ||
|
||
public extension RichTextAlignment { | ||
|
||
/// This picker can be used to pick a text alignment. | ||
/// | ||
/// This view returns a plain SwiftUI `Picker` view that | ||
/// can be styled and configured with a `PickerStyle`. | ||
struct Picker: View { | ||
|
||
/// Create a rich text alignment picker. | ||
/// | ||
/// - Parameters: | ||
/// - selection: The binding to update with the picker. | ||
/// - values: The pickable alignments, by default `.allCases`. | ||
public init( | ||
selection: Binding<RichTextAlignment>, | ||
values: [RichTextAlignment] = RichTextAlignment.allCases | ||
) { | ||
self._selection = selection | ||
self.values = values | ||
} | ||
|
||
let values: [RichTextAlignment] | ||
|
||
@Binding | ||
private var selection: RichTextAlignment | ||
|
||
public var body: some View { | ||
SwiftUI.Picker(RTEL10n.textAlignment.text, selection: $selection) { | ||
ForEach(values) { value in | ||
value.label | ||
.labelStyle(.iconOnly) | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
200 changes: 200 additions & 0 deletions
200
Sources/RichEditorSwiftUI/Colors/RichTextColor+Picker.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
// | ||
// RichTextColor+Picker.swift | ||
// RichEditorSwiftUI | ||
// | ||
// Created by Divyesh Vekariya on 18/11/24. | ||
// | ||
|
||
import SwiftUI | ||
|
||
public extension RichTextColor { | ||
|
||
/** | ||
This picker can be used to select a rich text color. | ||
This picker renders an icon next to the color picker as | ||
well as an optional list of quick colors. | ||
The quick color list is empty by default. You can add a | ||
custom set of colors, for instance `.quickPickerColors`. | ||
*/ | ||
struct Picker: View { | ||
|
||
/** | ||
Create a rich text color picker that binds to a color. | ||
- Parameters: | ||
- type: The type of color to pick. | ||
- icon: The icon to show, if any, by default the `type` icon. | ||
- value: The value to bind to. | ||
- quickColors: Colors to show in the trailing list, by default no colors. | ||
*/ | ||
public init( | ||
type: RichTextColor, | ||
icon: Image? = nil, | ||
value: Binding<Color>, | ||
quickColors: [Color] = [] | ||
) { | ||
self.type = type | ||
self.icon = icon ?? type.icon | ||
self._value = value | ||
self.quickColors = quickColors | ||
} | ||
|
||
private let type: RichTextColor | ||
private let icon: Image? | ||
private let quickColors: [Color] | ||
|
||
@Binding | ||
private var value: Color | ||
|
||
private let spacing = 10.0 | ||
|
||
@Environment(\.colorScheme) | ||
private var colorScheme | ||
|
||
public var body: some View { | ||
HStack(spacing: 0) { | ||
iconView | ||
picker | ||
if hasColors { | ||
HStack(spacing: spacing) { | ||
quickPickerDivider | ||
quickPickerButton(for: nil) | ||
quickPickerDivider | ||
} | ||
quickPicker | ||
} | ||
} | ||
.labelsHidden() | ||
} | ||
} | ||
} | ||
|
||
private extension RichTextColor.Picker { | ||
|
||
var hasColors: Bool { | ||
!quickColors.isEmpty | ||
} | ||
} | ||
|
||
public extension Color { | ||
|
||
/// Get a curated list of quick color picker colors. | ||
static var quickPickerColors: [Self] { | ||
[ | ||
.black, .gray, .white, | ||
.red, .pink, .orange, .yellow, | ||
.indigo, .purple, .blue, .cyan, .teal, .mint, | ||
.green, .brown | ||
] | ||
} | ||
} | ||
|
||
public extension Collection where Element == Color { | ||
|
||
/// Get a curated list of quick color picker colors. | ||
static var quickPickerColors: [Element] { | ||
Element.quickPickerColors | ||
} | ||
} | ||
|
||
private extension RichTextColor.Picker { | ||
|
||
@ViewBuilder | ||
var iconView: some View { | ||
if let icon { | ||
icon.frame(minWidth: 30) | ||
} | ||
} | ||
|
||
@ViewBuilder | ||
var picker: some View { | ||
#if iOS || macOS || os(visionOS) | ||
ColorPicker("", selection: $value) | ||
.fixedSize() | ||
.padding(.horizontal, spacing) | ||
#endif | ||
} | ||
|
||
var quickPicker: some View { | ||
ScrollView(.horizontal, showsIndicators: false) { | ||
HStack(spacing: spacing) { | ||
ForEach(Array(quickColors.enumerated()), id: \.offset) { | ||
quickPickerButton(for: $0.element) | ||
} | ||
} | ||
.padding(.horizontal, spacing) | ||
.padding(.vertical, 2) | ||
}.frame(maxWidth: .infinity) | ||
} | ||
|
||
func quickPickerButton(for color: Color?) -> some View { | ||
Button { | ||
value = type.adjust(color, for: colorScheme) | ||
} label: { | ||
if let color { | ||
color | ||
} else { | ||
Image.richTextColorReset | ||
} | ||
} | ||
.buttonStyle(ColorButtonStyle()) | ||
} | ||
|
||
var quickPickerDivider: some View { | ||
Divider() | ||
.padding(0) | ||
.frame(maxHeight: 30) | ||
} | ||
} | ||
|
||
private struct ColorButtonStyle: ButtonStyle { | ||
|
||
func makeBody(configuration: Configuration) -> some View { | ||
configuration.label | ||
.frame(width: 20, height: 20) | ||
.clipShape(Circle()) | ||
.shadow(radius: 1, x: 0, y: 1) | ||
} | ||
} | ||
|
||
#Preview { | ||
|
||
struct Preview: View { | ||
@State | ||
private var foregroundColor = Color.black | ||
|
||
@State | ||
private var backgroundColor = Color.white | ||
|
||
var body: some View { | ||
VStack(alignment: .leading, spacing: 10) { | ||
Text("Preview") | ||
.foregroundStyle(foregroundColor) | ||
.padding() | ||
.background(backgroundColor) | ||
.frame(maxWidth: .infinity) | ||
.border(Color.black) | ||
.background(Color.red) | ||
.padding() | ||
|
||
RichTextColor.Picker( | ||
type: .foreground, | ||
value: $foregroundColor, | ||
quickColors: [.white, .black, .red, .green, .blue] | ||
) | ||
.padding(.leading) | ||
|
||
RichTextColor.Picker( | ||
type: .background, | ||
value: $backgroundColor, | ||
quickColors: [.white, .black, .red, .green, .blue] | ||
) | ||
.padding(.leading) | ||
} | ||
} | ||
} | ||
|
||
return Preview() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
Sources/RichEditorSwiftUI/Fonts/RichTextFont+ListPicker.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// | ||
// RichTextFont+ListPicker.swift | ||
// RichEditorSwiftUI | ||
// | ||
// Created by Divyesh Vekariya on 18/11/24. | ||
// | ||
|
||
import SwiftUI | ||
|
||
public extension RichTextFont { | ||
|
||
/** | ||
This view uses a `List` to list a set of fonts of which | ||
one can be selected. | ||
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 list picker. | ||
- Parameters: | ||
- selection: The selected font name. | ||
*/ | ||
public init( | ||
selection: Binding<FontName> | ||
) { | ||
self._selection = selection | ||
} | ||
|
||
public typealias Config = RichTextFont.PickerConfig | ||
public typealias Font = Config.Font | ||
public typealias FontName = Config.FontName | ||
|
||
@Binding | ||
private var selection: FontName | ||
|
||
@Environment(\.richTextFontPickerConfig) | ||
private var config | ||
|
||
public var body: some View { | ||
let font = Binding( | ||
get: { Font(fontName: selection) }, | ||
set: { selection = $0.fontName } | ||
) | ||
|
||
RichEditorSwiftUI.ListPicker( | ||
items: config.fontsToList(for: selection), | ||
selection: font, | ||
dismissAfterPick: config.dismissAfterPick | ||
) { font, isSelected in | ||
RichTextFont.PickerItem( | ||
font: font, | ||
fontSize: config.fontSize, | ||
isSelected: isSelected | ||
) | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.