Releases: kyle-n/HighlightedTextEditor
Markdown headings use a larger font size
New features
- In the Markdown preset, headers display using a larger font size.
Bug fixes
- When typing regular-size text on a line following a line formatted with a large font size, the AppKit editor insertion point no longer jitters (appears large then small)
Emojis appear in the editor
Bug fixes:
- Emojis appear in the editor when typed (thanks to @ceojosef)
A simpler, more powerful HighlightedTextEditor
HighlightedTextEditor is turning 2.0! This is a huge update that gives you even more flexibility and control while dramatically simplifying the package’s code.
Quick overview
New features
.introspect()
modifier allows access to the underlyingUITextView
orNSTextView
NSRegularExpression.all
is pre-made regex for selecting an entire string- Nests some internal HLTE classes inside
HighlightedTextEditor
so they're not polluting your project namespace
Breaking changes
- Removes modifiers now covered by
.introspect()
(full list below) .onCommit()
,.onEditingChanged()
, and.onTextChange()
are now modifiers, notinit()
arguments (just likeTextEditor
!)- Markdown presets are only accessible from
[HighlightRule]
. For example,[HighlightRule].markdown
There are a lot of big changes in here, so here’s why I made them.
Problem: HLTE 1.0 was slowly replicating the API for UITextView
and NSTextView
Under the hood, HLTE uses a UITextView
or an NSTextView
inside an NSScrollView
. I threw a couple modifiers into v1 to set some options on the underlying UIKit/AppKit editor. For example:
HighlightedTextEditor(text: $text, highlightRules: [])
.multilineTextAlignment(.center)
The problem was, those options weren’t enough. A lot of users needed new HLTE modifiers to set special properties on the underlying UIKit/AppKit editor, modifiers I hadn’t thought to make.
That’s not sustainable. That means HLTE was (slowly, poorly) replicating the API for UITextView
and NSTextView
.
Solution: Give users the UITextView
or NSTextView
My solution was inspired by SwiftUI-Introspect, a cool library that lets you "introspect" the underlying UIKit or AppKit elements. It's a great way to write SwiftUI and dip into UIKit or AppKit to customize just one thing.
HighlightedTextEditor 2.0 removes all the previous modifiers that set UIKit or AppKit properties. Now there is only one god, .introspect()
:
HighlightedTextEditor(text: $text, highlightRules: .markdown)
.introspect { internals in
internals.textView.backgroundColor = .red
}
internals
is a struct
containing two properties, textView
and scrollView
. The latter is only used in the AppKit editor and returns nil
in UIKit editors.
public struct Internals {
public let textView: SystemTextView
public let scrollView: SystemScrollView? // always nil in UIKit
}
#if os(macOS)
import AppKit
public typealias SystemTextView = NSTextView
public typealias SystemScrollView = NSScrollView
#else
import UIKit
public typealias SystemTextView = UITextView
public typealias SystemScrollView = UIScrollView
#endif
.introspect()
runs every time SwiftUI redraws the HLTE view.
Now you have access to every property in AppKit and UIKit. Customize away!
Removed modifiers
The following modifiers have been removed. If you were using them, simply set the equivalent UIKit / AppKit property using .introspect()
.
.allowsDocumentBackgroundColorChange(_ allowsChange: Bool)
.autocapitalizationType(_ type: UITextAutocapitalizationType)
.autocorrectionType(_ type: UITextAutocorrectionType)
.backgroundColor(_ color: UIColor)
.defaultColor(_ color: UIColor)
.defaultFont(_ font: UIFont)
.drawsBackground(_ shouldDraw: Bool)
.keyboardType(_ type: UIKeyboardType)
.insertionPointColor(_ color: UIColor)
.multilineTextAlignment(_ alignment: TextAlignment)
Behind the scenes
- Deletes a lot of test code covering the old modifiers
- UIKit tests run on iPhone 12 simulators, up from 11
- Renames source code files to reflect that UIKit runs on the Mac
- Automatic formating and linting thanks to SwiftFormat and SwiftLint
Get the insertion point location with onSelectionChange
This release adds a new modifier, onSelectionChange
. Now whenever the insertion point changes in HighlightedTextEditor, it will run the provided callback.
HighlightedTextEditor(text: $text, highlightRules: .markdown)
.onSelectionChange { (range: NSRange) in
print(range)
}
Thanks to @santi-g-s and @ben-ole for providing the inspiration and assistance for this feature.
Dynamic formatting via callbacks
I've added an exciting, powerful new feature to TextFormattingRule
s that lets you do even more formatting on the fly. Here's an example:
TextFormattingRule(key: .underlineStyle) { content, range in
if content.count > 10 { return NSUnderlineStyle.double.rawValue }
else { return NSUnderlineStyle.single.rawValue }
}
TextFormattingRule
has a new init()
option that, instead of accepting a static value, accepts a callback function. Whatever the callback returns will be applied as the value for the given NSAttributedString.Key
.
This allows things like tappable links where the URL
target matches a URL string inside HighlightedTextEditor
. See the source code for the .url
[HighlightRule]
preset:
public extension Sequence where Iterator.Element == HighlightRule {
static var url: [HighlightRule] {
[
HighlightRule(pattern: _urlRegex, formattingRules: [
TextFormattingRule(key: .underlineStyle, value: NSUnderlineStyle.single.rawValue),
TextFormattingRule(key: .link) { urlString, _ in
URL(string: urlString) as Any
}
])
]
}
}
This doesn't just apply to NSAttributedString.Key.link
, though, it works on any property! Go crazy!
Behind the scenes
This release also contains substantial improvements to HighlightedTextEditor's continuous integration test suite. These changes will help ship features faster, with less brittle tests.
Bug fixes
UIKit Editor
- Editor sets correct initial font if using
.defaultFont()
, does not change fonts after typing the first character (@mikakruschel, #21) .insertionPointColor()
correctly sets insertion point color in Catalyst apps (@Chryb, #19)
Infrastructure
- CI handles branches with
/
in the name - CI boots iOS Simulator in separate step
Fixes bug with multi-stage input languages
Markdown fixes and tests!
User-facing features
Markdown preset
- Adds highlighting for tagged links
[link name][df]
[df]: https://daringfireball.net/
- Adds highlighting for footnotes
This is a footnote[^1].
[1]: Yep.
- Adds highlighting for HTML tags
Regular markdown here.
<aside>Other HTML content here.</aside>
Infrastructure
Adds a test project, Essayist, with a suite of unit and e2e tests. This is only for me but I am very excited to not pull out my iPad and run a test project every time something changes.
As far as I can tell, test code is not included in any app that uses HighlightedTextEditor. Build sizes on Archive are the same with and without the test folder.
CocoaPods support
HighlightedTextEditor may now be installed via CocoaPods. To install, add pod 'HighlightedTextEditor'
to your Podfile
and run pod install
.
This release also adds a GitHub Action to auto-update the HLTE CocoaPod when a new git tag release is pushed.
Presets are static variables on [HighlightRule]
This release makes HighlightRule
presets static variables on [HighlightRule]
. They make more sense there and don't really make sense as static variables on HighlightedTextEditor
.
Recommended syntax for accessing presets is now:
HighlightedTextEditor(text: $text, highlightRules: .markdown)
This release does not remove the static preset variables from HighlightedTextEditor
. Those variables will be removed in a future 2.0.0 breaking release.