SwiftUIBackports/Sources/SwiftUIBackports/iOS/TextEditor/TextEditor.swift

138 lines
5.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
#if os(iOS)
@available(iOS 14.0, *)
extension Backport where Wrapped == Any {
/// A view that can display and edit long-form text.
///
/// A text editor view allows you to display and edit multiline, scrollable text in your apps user interface. By default, the text editor view styles the text using characteristics inherited from the environment, like font(_:), foregroundColor(_:), and multilineTextAlignment(_:).
///
/// You create a text editor by adding a TextEditor instance to the body of your view, and initialize it by passing in a Binding to a string variable in your app.
///
/// To style the text, use the standard view modifiers to configure a system font, set a custom font, or change the color of the views text.
/// In this example, the view renders the editors text in gray with a custom font:
///
/// struct TextEditingView: View {
/// @State private var fullText: String = "This is some editable text..."
///
/// var body: some View {
/// TextEditor(text: $fullText)
/// .foregroundColor(Color.gray)
/// .font(.custom("HelveticaNeue", size: 13))
/// .lineSpacing(5)
/// }
/// }
///
/// > The order of some modifiers matter with this implementation. PLEASE REPORT ISSUES ON THE REPO!
///
/// Specifically, its recommended to place `foregroundColor` modifiers BEFORE `font` modifiers to ensure things work as expected.
///
public struct TextEditor: View {
@Environment(\.self) private var environment
@Binding var text: String
/// Creates a plain text editor.
///
/// Use a TextEditor instance to create a view in which users can enter and edit long-form text.
/// In this example, the text editor renders gray text using the 13 point Helvetica Neue font with 5 points of spacing between each line:
///
/// struct TextEditingView: View {
/// @State private var fullText: String = "This is some editable text..."
///
/// var body: some View {
/// TextEditor(text: $fullText)
/// .foregroundColor(Color.gray)
/// .font(.custom("HelveticaNeue", size: 13))
/// .lineSpacing(5)
/// }
/// }
///
/// You can define the styling for the text within the view, including the text color, font, and line spacing. You define these styles by applying standard view modifiers to the view. The default text editor doesnt support rich text, such as styling of individual elements within the editors view. The styles you set apply globally to all text in the view.
///
/// - Parameter text: A `Binding` to the variable containing the text to edit.
public init(text: Binding<String>) {
_text = text
}
private var isAccented: Bool {
guard let provider = colorProvider(from: environment) else { return false }
return isAccentColor(provider: provider)
}
public var body: some View {
Representable(parent: self)
.blendMode(!environment.isEnabled && isAccented ? .luminosity: .normal)
}
struct Representable: UIViewRepresentable {
let parent: TextEditor
func makeCoordinator() -> Coordinator {
.init(parent: parent)
}
func makeUIView(context: Context) -> UIView {
context.coordinator.view
}
func updateUIView(_ view: UIView, context: Context) {
context.coordinator.update(parent: parent)
}
}
final class Coordinator: NSObject, UITextViewDelegate {
let view = UITextView(frame: .zero)
var parent: TextEditor
init(parent: TextEditor) {
self.parent = parent
}
func update(parent: TextEditor) {
self.parent = parent
guard view.text != parent.text else { return }
view.delegate = self
view.adjustsFontForContentSizeCategory = true
view.autocapitalizationType = .sentences
view.backgroundColor = .clear
view.dataDetectorTypes = []
view.returnKeyType = parent.environment.backportSubmitLabel.returnKeyType
switch parent.environment.autocorrectionDisabled {
case true:
view.autocorrectionType = .yes
case false:
view.autocorrectionType = .no
}
let style = NSMutableParagraphStyle()
style.lineSpacing = parent.environment.lineSpacing
style.alignment = parent.environment.multilineTextAlignment.nsTextAlignment
view.textColor = resolveColor(parent.environment) ?? .label
view.font = resolveFont(parent.environment.font ?? .body)?
.font(with: parent.environment.uiTraitCollection)
?? .preferredFont(forTextStyle: .body)
view.typingAttributes = [
.paragraphStyle: style,
.foregroundColor: view.textColor ?? .label,
.font: view.font ?? .preferredFont(forTextStyle: .body)
]
view.text = parent.text
}
func textViewDidChange(_ textView: UITextView) {
DispatchQueue.main.async { [weak self] in
self?.parent.text = textView.text
}
}
}
}
}
#endif