Task edition improvements (#9)
This PR contains the work done to improve upon the editing experience on the **Task list item and the **New task** views. Reviewed-on: rock-n-code/todos-app#9 Co-authored-by: Javier Cicchelli <javier@rock-n-code.com> Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This commit was merged in pull request #9.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import SwiftUI
|
||||
|
||||
/// A view modifier that clears text and removes focus when return is pressed on empty content.
|
||||
///
|
||||
/// This modifier monitors text changes and provides smart handling of newlines:
|
||||
/// - Empty text is allowed normally
|
||||
/// - Newlines at the end of whitespace-only text clear the field and remove focus
|
||||
/// - Multi-line content with actual text is preserved normally
|
||||
struct OnEmptyNewlineResignFocusModifier<Field: Hashable>: ViewModifier {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
/// Binding to the text being edited.
|
||||
@Binding
|
||||
private var text: String
|
||||
|
||||
/// Binding to the focus state.
|
||||
private let focusState: FocusState<Field?>.Binding
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
/// Creates a modifier that clears text on empty newline.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - text: A binding to the text being edited.
|
||||
/// - focusState: A binding to the focus state.
|
||||
init(
|
||||
text: Binding<String>,
|
||||
focusState: FocusState<Field?>.Binding
|
||||
) {
|
||||
self._text = text
|
||||
self.focusState = focusState
|
||||
}
|
||||
|
||||
// MARK: Body
|
||||
|
||||
/// The content and behavior of the view modifier.
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.onChange(of: text) { oldValue, newValue in
|
||||
guard newValue.isEmpty == false else {
|
||||
return
|
||||
}
|
||||
|
||||
if newValue.last == .newline {
|
||||
if newValue.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
text = ""
|
||||
focusState.wrappedValue = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - View Extension
|
||||
|
||||
extension View {
|
||||
|
||||
/// Clears the text and removes focus when return is pressed on empty content.
|
||||
///
|
||||
/// This modifier allows users to dismiss an optional text field by pressing return
|
||||
/// when the field is empty or contains only whitespace. Multi-line content is preserved normally.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - focusState: A binding to the focus state.
|
||||
/// - text: A binding to the text being edited.
|
||||
/// - Returns: A modified view with clear-on-empty behavior.
|
||||
func onEmptyNewlineResignFocus<Field: Hashable>(
|
||||
text: Binding<String>,
|
||||
from focusState: FocusState<Field?>.Binding
|
||||
) -> some View {
|
||||
modifier(
|
||||
OnEmptyNewlineResignFocusModifier(
|
||||
text: text,
|
||||
focusState: focusState
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user