Skip to content

Commit c98b319

Browse files
authored
Supported font size customisation (#53)
* Supported font size customization * updated gitlab work flow * updated tool bar and workflow * Fixed warnings
1 parent 97e8871 commit c98b319

33 files changed

+1602
-432
lines changed

.github/workflows/build.yaml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@ jobs:
2121
- uses: maxim-lobanov/setup-xcode@v1
2222
with:
2323
xcode-version: '16.0'
24-
- name: Build all platforms
25-
run: bash scripts/build.sh ${{ github.event.repository.name }}
24+
- name: Build iOS
25+
run: xcodebuild -scheme $SCHEME -derivedDataPath .build -destination 'generic/platform=iOS' | xcpretty --color;
26+
- name: Build macOS
27+
run: xcodebuild -scheme $SCHEME -derivedDataPath .build -destination 'generic/platform=OS X' | xcpretty --color;
28+
- name: Build tvOS
29+
run: xcodebuild -scheme $SCHEME -derivedDataPath .build -destination 'generic/platform=tvOS' | xcpretty --color;
30+
- name: Build watchOS
31+
run: xcodebuild -scheme $SCHEME -derivedDataPath .build -destination 'generic/platform=watchOS' | xcpretty --color;
32+
- name: Build visionOS
33+
run: xcodebuild -scheme $SCHEME -derivedDataPath .build -destination 'generic/platform=xrOS' | xcpretty --color;
2634
- name: Test iOS
27-
run: bash scripts/test.sh ${{ github.event.repository.name }}
35+
run: xcodebuild test -scheme $SCHEME -derivedDataPath .build -destination 'platform=iOS Simulator,name=iPhone 16 Pro,OS=18.0' -enableCodeCoverage YES | xcpretty --color;

RichEditorDemo/RichEditorDemo.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,11 +314,11 @@
314314
PRODUCT_NAME = "$(TARGET_NAME)";
315315
REGISTER_APP_GROUPS = NO;
316316
SDKROOT = auto;
317-
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx";
317+
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx xros xrsimulator";
318318
SUPPORTS_MACCATALYST = NO;
319319
SWIFT_EMIT_LOC_STRINGS = YES;
320320
SWIFT_VERSION = 5.0;
321-
TARGETED_DEVICE_FAMILY = "1,2,3";
321+
TARGETED_DEVICE_FAMILY = "1,2,3,7";
322322
TVOS_DEPLOYMENT_TARGET = 17.0;
323323
};
324324
name = Debug;
@@ -353,11 +353,11 @@
353353
PRODUCT_NAME = "$(TARGET_NAME)";
354354
REGISTER_APP_GROUPS = NO;
355355
SDKROOT = auto;
356-
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx";
356+
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx xros xrsimulator";
357357
SUPPORTS_MACCATALYST = NO;
358358
SWIFT_EMIT_LOC_STRINGS = YES;
359359
SWIFT_VERSION = 5.0;
360-
TARGETED_DEVICE_FAMILY = "1,2,3";
360+
TARGETED_DEVICE_FAMILY = "1,2,3,7";
361361
TVOS_DEPLOYMENT_TARGET = 17.0;
362362
};
363363
name = Release;

RichEditorDemo/RichEditorDemo/ContentView.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ struct ContentView: View {
2929
var body: some View {
3030
NavigationStack {
3131
VStack {
32+
#if os(iOS) || os(macOS) || os(visionOS)
3233
EditorToolBarView(state: state)
34+
#endif
3335

3436
RichTextEditor(
3537
context: _state,
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// RichTextAction+KeyboardShortcutModifier.swift
3+
// RichEditorSwiftUI
4+
//
5+
// Created by Divyesh Vekariya on 30/10/24.
6+
//
7+
8+
import SwiftUI
9+
10+
public extension RichTextAction {
11+
12+
/**
13+
This view modifier can apply keyboard shortcuts for any
14+
``RichTextAction`` to any view.
15+
16+
You can also apply it with the `.keyboardShortcut(for:)`
17+
view modifier.
18+
*/
19+
struct KeyboardShortcutModifier: ViewModifier {
20+
21+
public init(_ action: RichTextAction) {
22+
self.action = action
23+
}
24+
25+
private let action: RichTextAction
26+
27+
public func body(content: Content) -> some View {
28+
content.keyboardShortcut(for: action)
29+
}
30+
}
31+
}
32+
33+
public extension View {
34+
35+
/// Apply a ``RichTextAction/KeyboardShortcutModifier``.
36+
@ViewBuilder
37+
func keyboardShortcut(for action: RichTextAction) -> some View {
38+
#if iOS || macOS || os(visionOS)
39+
switch action {
40+
case .copy: keyboardShortcut("c", modifiers: .command)
41+
case .dismissKeyboard: self
42+
case .print: keyboardShortcut("p", modifiers: .command)
43+
case .redoLatestChange: keyboardShortcut("z", modifiers: [.command, .shift])
44+
// case .setAlignment(let align): keyboardShortcut(for: align)
45+
case .stepFontSize(let points): keyboardShortcut(points < 0 ? "-" : "+", modifiers: .command)
46+
case .stepIndent(let steps): keyboardShortcut(steps < 0 ? "Ö" : "Ä", modifiers: .command)
47+
case .stepSuperscript: self
48+
// case .toggleStyle(let style): keyboardShortcut(for: style)
49+
case .undoLatestChange: keyboardShortcut("z", modifiers: .command)
50+
default: self // TODO: Probably not defined, object to discuss.
51+
}
52+
#else
53+
self
54+
#endif
55+
}
56+
}
57+

Sources/RichEditorSwiftUI/Actions/RichTextAction.swift

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,92 @@ public enum RichTextAction: Identifiable, Equatable {
7878
case undoLatestChange
7979

8080
/// Set HeaderStyle.
81-
case setHeaderStyle(_ style: RichTextStyle, range: NSRange)
81+
case setHeaderStyle(_ style: RichTextStyle)
8282
}
8383

8484
public extension RichTextAction {
8585

8686
typealias Publisher = PassthroughSubject<Self, Never>
8787

8888
/// The action's unique identifier.
89-
var id: String { UUID().uuidString }
89+
var id: String { title }
9090

9191
/// The action's standard icon.
92-
92+
var icon: Image {
93+
switch self {
94+
case .copy: .richTextCopy
95+
case .dismissKeyboard: .richTextDismissKeyboard
96+
// case .pasteImage: .richTextDocuments
97+
// case .pasteImages: .richTextDocuments
98+
// case .pasteText: .richTextDocuments
99+
case .print: .richTextPrint
100+
case .redoLatestChange: .richTextRedo
101+
case .selectRange: .richTextSelection
102+
case .setAlignment(let val): val.icon
103+
case .setAttributedString: .richTextDocument
104+
case .setColor(let color, _): color.icon
105+
case .setHighlightedRange: .richTextAlignmentCenter
106+
case .setHighlightingStyle: .richTextAlignmentCenter
107+
case .setStyle(let style, _): style.icon
108+
case .stepFontSize(let val): .richTextStepFontSize(val)
109+
case .stepIndent(let val): .richTextStepIndent(val)
110+
case .stepLineSpacing(let val): .richTextStepLineSpacing(val)
111+
case .stepSuperscript(let val): .richTextStepSuperscript(val)
112+
case .toggleStyle(let val): val.icon
113+
case .undoLatestChange: .richTextUndo
114+
case .setHeaderStyle: .richTextIgnoreIt
115+
}
116+
}
117+
118+
/// The localized label to use for the action.
119+
var label: some View {
120+
icon.label(title)
121+
}
122+
123+
/// The localized title to use in the main menu.
124+
var menuTitle: String {
125+
menuTitleKey.text
126+
}
127+
128+
/// The localized title key to use in the main menu.
129+
var menuTitleKey: RTEL10n {
130+
switch self {
131+
case .stepIndent(let points): .menuIndent(points)
132+
default: titleKey
133+
}
134+
}
135+
136+
/// The localized action title.
137+
var title: String {
138+
titleKey.text
139+
}
140+
141+
/// The localized action title key.
142+
var titleKey: RTEL10n {
143+
switch self {
144+
case .copy: .actionCopy
145+
case .dismissKeyboard: .actionDismissKeyboard
146+
// case .pasteImage: .pasteImage
147+
// case .pasteImages: .pasteImages
148+
// case .pasteText: .pasteText
149+
case .print: .actionPrint
150+
case .redoLatestChange: .actionRedoLatestChange
151+
case .selectRange: .selectRange
152+
case .setAlignment(let alignment): alignment.titleKey
153+
case .setAttributedString: .setAttributedString
154+
case .setColor(let color, _): color.titleKey
155+
case .setHighlightedRange: .highlightedRange
156+
case .setHighlightingStyle: .highlightingStyle
157+
case .setStyle(let style, _): style.titleKey
158+
case .stepFontSize(let points): .actionStepFontSize(points)
159+
case .stepIndent(let points): .actionStepIndent(points)
160+
case .stepLineSpacing(let points): .actionStepLineSpacing(points)
161+
case .stepSuperscript(let steps): .actionStepSuperscript(steps)
162+
case .toggleStyle(let style): style.titleKey
163+
case .undoLatestChange: .actionUndoLatestChange
164+
case .setHeaderStyle: .ignoreIt
165+
}
166+
}
93167
}
94168

95169
// MARK: - Aliases
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// RichTextActionButton.swift
3+
// RichEditorSwiftUI
4+
//
5+
// Created by Divyesh Vekariya on 29/10/24.
6+
//
7+
8+
import SwiftUI
9+
10+
public extension RichTextAction {
11+
12+
/**
13+
This button can be used to trigger a ``RichTextAction``.
14+
15+
This renders a plain `Button`, which means that you can
16+
use and configure it as a normal button.
17+
*/
18+
struct Button: View {
19+
/**
20+
Create a rich text action button.
21+
22+
- Parameters:
23+
- action: The action to trigger.
24+
- context: The context to affect.
25+
- fillVertically: WhetherP or not fill up vertical space, by default `false`.
26+
*/
27+
public init(
28+
action: RichTextAction,
29+
context: RichEditorState,
30+
fillVertically: Bool = false
31+
) {
32+
self.action = action
33+
self._context = ObservedObject(wrappedValue: context)
34+
self.fillVertically = fillVertically
35+
}
36+
37+
private let action: RichTextAction
38+
private let fillVertically: Bool
39+
40+
@ObservedObject
41+
private var context: RichEditorState
42+
43+
public var body: some View {
44+
SwiftUI.Button(action: triggerAction) {
45+
action.label
46+
.labelStyle(.iconOnly)
47+
.frame(maxHeight: fillVertically ? .infinity : nil)
48+
.contentShape(Rectangle())
49+
}
50+
.keyboardShortcut(for: action)
51+
.disabled(!context.canHandle(action))
52+
}
53+
}
54+
}
55+
56+
private extension RichTextAction.Button {
57+
58+
func triggerAction() {
59+
context.handle(action)
60+
}
61+
}

Sources/RichEditorSwiftUI/Alignment/RichTextAlignment.swift

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,38 +53,54 @@ public extension RichTextAlignment {
5353
var id: String { rawValue }
5454

5555
/// The standard icon to use for the alignment.
56-
// var icon: Image { nativeAlignment.icon }
56+
var icon: Image { nativeAlignment.icon }
5757

5858
/// The standard title to use for the alignment.
59-
// var title: String { nativeAlignment.title }
59+
var title: String { nativeAlignment.title }
6060

6161
/// The standard title key to use for the alignment.
62-
// var titleKey: RTKL10n { nativeAlignment.titleKey }
62+
var titleKey: RTEL10n { nativeAlignment.titleKey }
6363

6464
/// The native alignment of the alignment.
6565
var nativeAlignment: NSTextAlignment {
6666
switch self {
67-
case .left: .left
68-
case .right: .right
69-
case .center: .center
70-
case .justified: .justified
67+
case .left: .left
68+
case .right: .right
69+
case .center: .center
70+
case .justified: .justified
7171
}
7272
}
7373
}
7474

75-
//extension NSTextAlignment: RichTextLabelValue {}
75+
extension NSTextAlignment: RichTextLabelValue {}
7676

7777
public extension NSTextAlignment {
7878

79-
// /// The standard icon to use for the alignment.
80-
// var icon: Image {
81-
// switch self {
82-
// case .left: .richTextAlignmentLeft
83-
// case .right: .richTextAlignmentRight
84-
// case .center: .richTextAlignmentCenter
85-
// case .justified: .richTextAlignmentJustified
86-
// default: .richTextAlignmentLeft
87-
// }
88-
// }
79+
/// The standard icon to use for the alignment.
80+
var icon: Image {
81+
switch self {
82+
case .left: .richTextAlignmentLeft
83+
case .right: .richTextAlignmentRight
84+
case .center: .richTextAlignmentCenter
85+
case .justified: .richTextAlignmentJustified
86+
default: .richTextAlignmentLeft
87+
}
88+
}
89+
90+
/// The standard title to use for the alignment.
91+
var title: String {
92+
titleKey.text
93+
}
8994

95+
/// The standard title key to use for the alignment.
96+
var titleKey: RTEL10n {
97+
switch self {
98+
case .left: .textAlignmentLeft
99+
case .right: .textAlignmentRight
100+
case .center: .textAlignmentCentered
101+
case .justified: .textAlignmentJustified
102+
default: .textAlignmentLeft
103+
}
104+
}
90105
}
106+

Sources/RichEditorSwiftUI/Attributes/RichTextAttributes+RichTextStyle.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import Foundation
99

1010
public extension RichTextAttributes {
11-
1211
/**
1312
Whether or not the attributes has a strikethrough style.
1413
*/

0 commit comments

Comments
 (0)