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:
2026-02-12 01:21:19 +00:00
committed by javier
parent bbd7ec264b
commit 52376695a4
11 changed files with 355 additions and 47 deletions
@@ -0,0 +1,86 @@
import SwiftUI
/// A view modifier that intercepts newlines in a text field and transfers focus to another field.
///
/// This modifier monitors text changes in a `TextField` component and prevents newlines
/// from being added. Instead, when a newline is detected, it updates the focus state to move to
/// a specified field.
struct OnNewlineFocusModifier<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
/// The field to focus when a newline is detected.
private let targetField: Field
// MARK: Initializers
/// Creates a modifier that transfers focus on newline.
///
/// - Parameters:
/// - text: A binding to the text being edited.
/// - focusState: A binding to the focus state.
/// - targetField: The field to focus when a newline is detected.
init(
text: Binding<String>,
focusState: FocusState<Field?>.Binding,
targetField: Field
) {
self._text = text
self.focusState = focusState
self.targetField = targetField
}
// 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.contains(.newline) else {
return
}
text = oldValue
focusState.wrappedValue = targetField
}
}
}
// MARK: - View Extension
extension View {
/// Transfers focus to another field when the user presses return in a text field.
///
/// This modifier prevents newlines from being added and instead moves keyboard focus
/// to the specified field. Useful for creating a form-like flow between text fields.
///
/// - Parameters:
/// - text: A binding to the text being edited.
/// - field: The field to focus when return is pressed.
/// - focusState: A binding to the focus state.
/// - Returns: A modified view with focus transfer behavior.
func onNewlineFocus<Field: Hashable>(
_ text: Binding<String>,
to field: Field,
on focusState: FocusState<Field?>.Binding
) -> some View {
modifier(
OnNewlineFocusModifier(
text: text,
focusState: focusState,
targetField: field
)
)
}
}