-
-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
31c259f
commit 5ab1087
Showing
7 changed files
with
397 additions
and
377 deletions.
There are no files selected for viewing
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
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,182 @@ | ||
// | ||
// RichTextFormat+Sheet.swift | ||
// RichTextKit | ||
// | ||
// Created by Daniel Saidi on 2022-12-13. | ||
// Copyright © 2022-2024 Daniel Saidi. All rights reserved. | ||
// | ||
|
||
#if iOS || macOS || os(visionOS) | ||
import SwiftUI | ||
|
||
public extension RichTextFormat { | ||
|
||
/** | ||
This sheet contains a font picker and a bottom toolbar. | ||
|
||
You can configure and style the view by applying config | ||
and style view modifiers to your view hierarchy: | ||
|
||
```swift | ||
VStack { | ||
... | ||
} | ||
.richTextFormatSheetStyle(...) | ||
.richTextFormatSheetConfig(...) | ||
``` | ||
*/ | ||
struct Sheet: RichTextFormatToolbarBase { | ||
|
||
/** | ||
Create a rich text format sheet. | ||
|
||
- Parameters: | ||
- context: The context to apply changes to. | ||
*/ | ||
public init( | ||
context: RichTextContext | ||
) { | ||
self._context = ObservedObject(wrappedValue: context) | ||
} | ||
|
||
public typealias Config = RichTextFormatToolbar.Config | ||
public typealias Style = RichTextFormatToolbar.Style | ||
|
||
@ObservedObject | ||
private var context: RichTextContext | ||
|
||
@Environment(\.richTextFormatSheetConfig) | ||
var config | ||
|
||
@Environment(\.richTextFormatSheetStyle) | ||
var style | ||
|
||
@Environment(\.dismiss) | ||
private var dismiss | ||
|
||
@Environment(\.horizontalSizeClass) | ||
private var horizontalSizeClass | ||
|
||
public var body: some View { | ||
NavigationView { | ||
VStack(spacing: 0) { | ||
RichTextFont.ListPicker( | ||
selection: $context.fontName | ||
) | ||
Divider() | ||
RichTextFormatToolbar( | ||
context: context | ||
) | ||
.richTextFormatToolbarConfig(config) | ||
} | ||
.padding(.top, -35) | ||
.toolbar { | ||
ToolbarItem(placement: .confirmationAction) { | ||
Button(RTKL10n.done.text) { | ||
dismiss() | ||
} | ||
} | ||
} | ||
.navigationTitle("") | ||
#if iOS | ||
.navigationBarTitleDisplayMode(.inline) | ||
#endif | ||
} | ||
#if iOS | ||
.navigationViewStyle(.stack) | ||
#endif | ||
} | ||
} | ||
} | ||
|
||
public extension View { | ||
|
||
/// Apply a rich text format sheet config. | ||
func richTextFormatSheetConfig( | ||
_ value: RichTextFormat.Sheet.Config | ||
) -> some View { | ||
self.environment(\.richTextFormatSheetConfig, value) | ||
} | ||
|
||
/// Apply a rich text format sheet style. | ||
func richTextFormatSheetStyle( | ||
_ value: RichTextFormat.Sheet.Style | ||
) -> some View { | ||
self.environment(\.richTextFormatSheetStyle, value) | ||
} | ||
} | ||
|
||
private extension RichTextFormat.Sheet.Config { | ||
|
||
struct Key: EnvironmentKey { | ||
|
||
static let defaultValue = RichTextFormat.Sheet.Config() | ||
} | ||
} | ||
|
||
private extension RichTextFormat.Sheet.Style { | ||
|
||
struct Key: EnvironmentKey { | ||
|
||
static let defaultValue = RichTextFormat.Sheet.Style() | ||
} | ||
} | ||
|
||
public extension EnvironmentValues { | ||
|
||
/// This value can bind to a format sheet config. | ||
var richTextFormatSheetConfig: RichTextFormat.Sheet.Config { | ||
get { self [RichTextFormat.Sheet.Config.Key.self] } | ||
set { self [RichTextFormat.Sheet.Config.Key.self] = newValue } | ||
} | ||
|
||
/// This value can bind to a format sheet style. | ||
var richTextFormatSheetStyle: RichTextFormat.Sheet.Style { | ||
get { self [RichTextFormat.Sheet.Style.Key.self] } | ||
set { self [RichTextFormat.Sheet.Style.Key.self] = newValue } | ||
} | ||
} | ||
|
||
struct RichTextFormat_Sheet_Previews: PreviewProvider { | ||
|
||
struct Preview: View { | ||
|
||
@StateObject | ||
private var context = RichTextContext() | ||
|
||
@State | ||
private var isSheetPresented = false | ||
|
||
var body: some View { | ||
VStack(spacing: 0) { | ||
Color.red | ||
Button("Toggle sheet") { | ||
isSheetPresented.toggle() | ||
} | ||
} | ||
.sheet(isPresented: $isSheetPresented) { | ||
RichTextFormat.Sheet( | ||
context: context | ||
) | ||
.richTextFormatSheetConfig(.init( | ||
alignments: .all, | ||
colorPickers: [.foreground, .background], | ||
colorPickersDisclosed: [.stroke], | ||
fontPicker: true, | ||
fontSizePicker: false, | ||
indentButtons: true, | ||
styles: .all | ||
)) | ||
} | ||
.richTextFormatToolbarStyle(.init( | ||
padding: 10, | ||
spacing: 10 | ||
)) | ||
} | ||
} | ||
|
||
static var previews: some View { | ||
Preview() | ||
} | ||
} | ||
#endif |
193 changes: 193 additions & 0 deletions
193
Sources/RichTextKit/Format/RichTextFormat+Sidebar.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,193 @@ | ||
// | ||
// RichTextFormat+Sidebar.swift | ||
// RichTextKit | ||
// | ||
// Created by Daniel Saidi on 2022-12-13. | ||
// Copyright © 2022-2024 Daniel Saidi. All rights reserved. | ||
// | ||
|
||
#if iOS || macOS || os(visionOS) | ||
import SwiftUI | ||
|
||
public extension RichTextFormat { | ||
|
||
/** | ||
This sidebar view provides various text format options, and | ||
is meant to be used on macOS, in a trailing sidebar. | ||
|
||
You can configure and style the view by applying its config | ||
and style view modifiers to your view hierarchy: | ||
|
||
```swift | ||
VStack { | ||
... | ||
} | ||
.richTextFormatSidebarStyle(...) | ||
.richTextFormatSidebarConfig(...) | ||
``` | ||
|
||
> Note: The sidebar is currently designed for macOS, but it | ||
should also be made to look good on iPadOS in landscape, to | ||
let us use it instead of the ``RichTextFormatSheet``. | ||
*/ | ||
struct Sidebar: RichTextFormatToolbarBase { | ||
|
||
/** | ||
Create a rich text format sheet. | ||
|
||
- Parameters: | ||
- context: The context to apply changes to. | ||
*/ | ||
public init( | ||
context: RichTextContext | ||
) { | ||
self._context = ObservedObject(wrappedValue: context) | ||
} | ||
|
||
public typealias Config = RichTextFormatToolbar.Config | ||
public typealias Style = RichTextFormatToolbar.Style | ||
|
||
@ObservedObject | ||
private var context: RichTextContext | ||
|
||
@Environment(\.richTextFormatSidebarConfig) | ||
var config | ||
|
||
@Environment(\.richTextFormatSidebarStyle) | ||
var style | ||
|
||
public var body: some View { | ||
VStack(alignment: .leading, spacing: style.spacing) { | ||
SidebarSection { | ||
fontPicker(value: $context.fontName) | ||
HStack { | ||
styleToggleGroup(for: context) | ||
Spacer() | ||
fontSizePicker(for: context) | ||
} | ||
} | ||
|
||
Divider() | ||
|
||
SidebarSection { | ||
alignmentPicker(value: $context.textAlignment) | ||
HStack { | ||
lineSpacingPicker(for: context) | ||
} | ||
HStack { | ||
indentButtons(for: context, greedy: true) | ||
superscriptButtons(for: context, greedy: true) | ||
} | ||
} | ||
|
||
Divider() | ||
|
||
if hasColorPickers { | ||
SidebarSection { | ||
colorPickers(for: context) | ||
} | ||
.padding(.trailing, -8) | ||
Divider() | ||
} | ||
|
||
Spacer() | ||
} | ||
.padding(style.padding - 2) | ||
.background(Color.white.opacity(0.05)) | ||
} | ||
} | ||
} | ||
|
||
private struct SidebarSection<Content: View>: View { | ||
|
||
@ViewBuilder | ||
let content: () -> Content | ||
|
||
@Environment(\.richTextFormatToolbarStyle) | ||
var style | ||
|
||
var body: some View { | ||
VStack(alignment: .leading, spacing: style.spacing) { | ||
content() | ||
} | ||
} | ||
} | ||
|
||
public extension View { | ||
|
||
/// Apply a rich text format sidebar config. | ||
func richTextFormatSidebarConfig( | ||
_ value: RichTextFormat.Sidebar.Config | ||
) -> some View { | ||
self.environment(\.richTextFormatSidebarConfig, value) | ||
} | ||
|
||
/// Apply a rich text format sidebar style. | ||
func richTextFormatSidebarStyle( | ||
_ value: RichTextFormat.Sidebar.Style | ||
) -> some View { | ||
self.environment(\.richTextFormatSidebarStyle, value) | ||
} | ||
} | ||
|
||
private extension RichTextFormat.Sidebar.Config { | ||
|
||
struct Key: EnvironmentKey { | ||
|
||
static let defaultValue = RichTextFormat.Sidebar.Config() | ||
} | ||
} | ||
|
||
private extension RichTextFormat.Sidebar.Style { | ||
|
||
struct Key: EnvironmentKey { | ||
|
||
static let defaultValue = RichTextFormat.Sidebar.Style() | ||
} | ||
} | ||
|
||
public extension EnvironmentValues { | ||
|
||
/// This value can bind to a format sidebar config. | ||
var richTextFormatSidebarConfig: RichTextFormat.Sidebar.Config { | ||
get { self [RichTextFormat.Sidebar.Config.Key.self] } | ||
set { self [RichTextFormat.Sidebar.Config.Key.self] = newValue } | ||
} | ||
|
||
/// This value can bind to a format sidebar style. | ||
var richTextFormatSidebarStyle: RichTextFormat.Sidebar.Style { | ||
get { self [RichTextFormat.Sidebar.Style.Key.self] } | ||
set { self [RichTextFormat.Sidebar.Style.Key.self] = newValue } | ||
} | ||
} | ||
|
||
struct RichTextFormat_Sidebar_Previews: PreviewProvider { | ||
|
||
struct Preview: View { | ||
|
||
@StateObject | ||
private var context = RichTextContext() | ||
|
||
var body: some View { | ||
RichTextFormat.Sidebar( | ||
context: context | ||
) | ||
.richTextFormatSidebarConfig(.init( | ||
alignments: [.left, .right], | ||
colorPickers: [.foreground], | ||
colorPickersDisclosed: [], | ||
fontPicker: false, | ||
fontSizePicker: true, | ||
indentButtons: true, | ||
styles: .all, | ||
superscriptButtons: true | ||
)) | ||
} | ||
} | ||
|
||
static var previews: some View { | ||
Preview() | ||
.frame(minWidth: 350) | ||
} | ||
} | ||
#endif |
Oops, something went wrong.