Introduces a backport for TextInputCapitalization
This commit is contained in:
parent
affe67f2cf
commit
5a294a710f
|
@ -2,22 +2,64 @@ import SwiftUI
|
||||||
import SwiftBackports
|
import SwiftBackports
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
extension Backport where Wrapped: View {
|
@available(iOS, deprecated: 15)
|
||||||
|
public extension Backport where Wrapped: View {
|
||||||
|
/// Sets how often the shift key in the keyboard is automatically enabled.
|
||||||
|
///
|
||||||
|
/// Use `backport.textInputAutocapitalization(_:)` when you need to automatically
|
||||||
|
/// capitalize words, sentences, or other text like proper nouns.
|
||||||
|
///
|
||||||
|
/// In example below, as the user enters text the shift key is
|
||||||
|
/// automatically enabled before every word:
|
||||||
|
///
|
||||||
|
/// TextField("Last, First", text: $fullName)
|
||||||
|
/// .backport.textInputAutocapitalization(.words)
|
||||||
|
///
|
||||||
|
/// The ``TextInputAutocapitalization`` struct defines the available
|
||||||
|
/// autocapitalizing behavior. Providing `nil` to this view modifier does
|
||||||
|
/// not change the autocapitalization behavior. The default is
|
||||||
|
/// `Backport<Any>.TextInputAutocapitalization.sentences`.
|
||||||
|
///
|
||||||
|
/// - Parameter autocapitalization: One of the capitalizing behaviors
|
||||||
|
/// defined in the `Backport<Any>.TextInputAutocapitalization` struct or nil.
|
||||||
|
@ViewBuilder
|
||||||
func textInputAutocapitalization(_ autocapitalization: Backport<Any>.TextInputAutocapitalization?) -> some View {
|
func textInputAutocapitalization(_ autocapitalization: Backport<Any>.TextInputAutocapitalization?) -> some View {
|
||||||
wrapped.modifier(
|
Group {
|
||||||
AutoCapitalizationModifier(
|
if #available(iOS 16, *) {
|
||||||
capitalization: autocapitalization?.capitalization ?? .none
|
var type: SwiftUI.TextInputAutocapitalization {
|
||||||
)
|
switch autocapitalization {
|
||||||
)
|
case .none:
|
||||||
|
return .sentences
|
||||||
|
case .some(let wrapped):
|
||||||
|
switch wrapped {
|
||||||
|
case .never: return .never
|
||||||
|
case .words: return .words
|
||||||
|
case .sentences: return .sentences
|
||||||
|
case .characters: return .characters
|
||||||
|
default: return .sentences
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wrapped.textInputAutocapitalization(type)
|
||||||
|
} else {
|
||||||
|
wrapped.modifier(
|
||||||
|
AutoCapitalizationModifier(
|
||||||
|
capitalization: autocapitalization?.capitalization ?? .none
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.environment(\.textInputAutocapitalization, autocapitalization)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS, introduced: 13, deprecated: 15)
|
@available(iOS, deprecated: 15)
|
||||||
@available(macOS, unavailable)
|
|
||||||
@available(tvOS, unavailable)
|
|
||||||
@available(watchOS, unavailable)
|
|
||||||
extension Backport<Any> {
|
extension Backport<Any> {
|
||||||
public struct TextInputAutocapitalization {
|
/// The kind of autocapitalization behavior applied during text input.
|
||||||
|
///
|
||||||
|
/// Pass an instance of `Backport<Any>.TextInputAutocapitalization` to the
|
||||||
|
/// ``View/backport.textInputAutocapitalization(_:)`` view modifier.
|
||||||
|
public struct TextInputAutocapitalization: Equatable {
|
||||||
internal let capitalization: UITextAutocapitalizationType
|
internal let capitalization: UITextAutocapitalizationType
|
||||||
|
|
||||||
fileprivate init(capitalization: UITextAutocapitalizationType) {
|
fileprivate init(capitalization: UITextAutocapitalizationType) {
|
||||||
|
@ -38,27 +80,41 @@ extension Backport<Any> {
|
||||||
/// Defines an autocapitalizing behavior that will capitalize every letter.
|
/// Defines an autocapitalizing behavior that will capitalize every letter.
|
||||||
public static var characters: TextInputAutocapitalization { .init(capitalization: .allCharacters) }
|
public static var characters: TextInputAutocapitalization { .init(capitalization: .allCharacters) }
|
||||||
|
|
||||||
|
/// Creates a new `Backport<Any>.TextInputAutocapitalization` struct from a
|
||||||
|
/// `UITextAutocapitalizationType` enum.
|
||||||
public init?(_ type: UITextAutocapitalizationType) {
|
public init?(_ type: UITextAutocapitalizationType) {
|
||||||
self.capitalization = type
|
self.capitalization = type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(iOS, deprecated: 15)
|
||||||
private struct AutoCapitalizationModifier: ViewModifier {
|
private struct AutoCapitalizationModifier: ViewModifier {
|
||||||
let capitalization: UITextAutocapitalizationType
|
let capitalization: UITextAutocapitalizationType
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
content
|
content
|
||||||
.inspect { inspector in
|
.inspect { inspector in
|
||||||
inspector.ancestor(ofType: UITextField.self)
|
inspector.any(ofType: UITextField.self)
|
||||||
} customize: { view in
|
} customize: { view in
|
||||||
view.autocapitalizationType = capitalization
|
view.autocapitalizationType = capitalization
|
||||||
}
|
}
|
||||||
.inspect { inspector in
|
.inspect { inspector in
|
||||||
inspector.ancestor(ofType: UITextView.self)
|
inspector.any(ofType: UITextView.self)
|
||||||
} customize: { view in
|
} customize: { view in
|
||||||
view.autocapitalizationType = capitalization
|
view.autocapitalizationType = capitalization
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct AutoCapitalizationEnvironmentKey: EnvironmentKey {
|
||||||
|
static var defaultValue: Backport<Any>.TextInputAutocapitalization? = .sentences
|
||||||
|
}
|
||||||
|
|
||||||
|
internal extension EnvironmentValues {
|
||||||
|
var textInputAutocapitalization: Backport<Any>.TextInputAutocapitalization? {
|
||||||
|
get { self[AutoCapitalizationEnvironmentKey.self] }
|
||||||
|
set { self[AutoCapitalizationEnvironmentKey.self] = newValue }
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,7 +9,7 @@ public extension Backport where Wrapped: View {
|
||||||
/// Different views may have different triggers for the provided action. A TextField, or SecureField will trigger this action when the user hits the hardware or software return key. This modifier may also bind this action to a default action keyboard shortcut. You may set this action on an individual view or an entire view hierarchy.
|
/// Different views may have different triggers for the provided action. A TextField, or SecureField will trigger this action when the user hits the hardware or software return key. This modifier may also bind this action to a default action keyboard shortcut. You may set this action on an individual view or an entire view hierarchy.
|
||||||
///
|
///
|
||||||
/// TextField("Username", text: $username)
|
/// TextField("Username", text: $username)
|
||||||
/// .onSubmit {
|
/// .backport.onSubmit {
|
||||||
/// guard viewModel.validate() else { return }
|
/// guard viewModel.validate() else { return }
|
||||||
/// viewModel.login()
|
/// viewModel.login()
|
||||||
/// }
|
/// }
|
||||||
|
@ -31,7 +31,7 @@ public extension Backport where Wrapped: View {
|
||||||
/// A semantic label describing the label of submission within a view hierarchy.
|
/// A semantic label describing the label of submission within a view hierarchy.
|
||||||
///
|
///
|
||||||
/// A submit label is a description of a submission action provided to a
|
/// A submit label is a description of a submission action provided to a
|
||||||
/// view hierarchy using the ``View/onSubmit(of:_:)`` modifier.
|
/// view hierarchy using the ``View/backport.onSubmit(of:_:)`` modifier.
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func submitLabel(_ label: Backport<Any>.SubmitLabel) -> some View {
|
func submitLabel(_ label: Backport<Any>.SubmitLabel) -> some View {
|
||||||
Group {
|
Group {
|
||||||
|
|
|
@ -18,7 +18,7 @@ extension Backport where Wrapped == Any {
|
||||||
/// @State private var fullText: String = "This is some editable text..."
|
/// @State private var fullText: String = "This is some editable text..."
|
||||||
///
|
///
|
||||||
/// var body: some View {
|
/// var body: some View {
|
||||||
/// TextEditor(text: $fullText)
|
/// Backport.TextEditor(text: $fullText)
|
||||||
/// .foregroundColor(Color.gray)
|
/// .foregroundColor(Color.gray)
|
||||||
/// .font(.custom("HelveticaNeue", size: 13))
|
/// .font(.custom("HelveticaNeue", size: 13))
|
||||||
/// .lineSpacing(5)
|
/// .lineSpacing(5)
|
||||||
|
@ -42,7 +42,7 @@ extension Backport where Wrapped == Any {
|
||||||
/// @State private var fullText: String = "This is some editable text..."
|
/// @State private var fullText: String = "This is some editable text..."
|
||||||
///
|
///
|
||||||
/// var body: some View {
|
/// var body: some View {
|
||||||
/// TextEditor(text: $fullText)
|
/// Backport.TextEditor(text: $fullText)
|
||||||
/// .foregroundColor(Color.gray)
|
/// .foregroundColor(Color.gray)
|
||||||
/// .font(.custom("HelveticaNeue", size: 13))
|
/// .font(.custom("HelveticaNeue", size: 13))
|
||||||
/// .lineSpacing(5)
|
/// .lineSpacing(5)
|
||||||
|
@ -100,6 +100,7 @@ extension Backport where Wrapped == Any {
|
||||||
view.backgroundColor = .clear
|
view.backgroundColor = .clear
|
||||||
view.dataDetectorTypes = []
|
view.dataDetectorTypes = []
|
||||||
view.returnKeyType = parent.environment.backportSubmitLabel.returnKeyType
|
view.returnKeyType = parent.environment.backportSubmitLabel.returnKeyType
|
||||||
|
view.autocapitalizationType = parent.environment.textInputAutocapitalization?.capitalization ?? .sentences
|
||||||
|
|
||||||
switch parent.environment.autocorrectionDisabled {
|
switch parent.environment.autocorrectionDisabled {
|
||||||
case true:
|
case true:
|
||||||
|
|
Loading…
Reference in New Issue