From 1dd54b0cb5326c977a6974be4f8b84ce1afeb970 Mon Sep 17 00:00:00 2001 From: phg Date: Wed, 30 Jul 2025 14:58:43 +0200 Subject: [PATCH] Refine modal focus handling: update tab navigation logic and simplify focus setting in SaveConfirmationModal tests --- src/hosts/main.py | 9 +++- src/hosts/tui/save_confirmation_modal.py | 52 +----------------------- tests/test_save_confirmation_modal.py | 17 ++------ 3 files changed, 12 insertions(+), 66 deletions(-) diff --git a/src/hosts/main.py b/src/hosts/main.py index 8754a72..dac9024 100644 --- a/src/hosts/main.py +++ b/src/hosts/main.py @@ -839,11 +839,16 @@ class HostsManagerApp(App): def on_key(self, event) -> None: """Handle key events to override default tab behavior in edit mode.""" - if self.entry_edit_mode and event.key == "tab": + # Only handle custom tab navigation if in entry edit mode AND no modal is open + if self.entry_edit_mode and len(self.screen_stack) == 1 and event.key == "tab": # Prevent default tab behavior and use our custom navigation event.prevent_default() self.action_next_field() - elif self.entry_edit_mode and event.key == "shift+tab": + elif ( + self.entry_edit_mode + and len(self.screen_stack) == 1 + and event.key == "shift+tab" + ): # Prevent default shift+tab behavior and use our custom navigation event.prevent_default() self.action_prev_field() diff --git a/src/hosts/tui/save_confirmation_modal.py b/src/hosts/tui/save_confirmation_modal.py index 1aa38fd..a49f8f1 100644 --- a/src/hosts/tui/save_confirmation_modal.py +++ b/src/hosts/tui/save_confirmation_modal.py @@ -95,59 +95,11 @@ class SaveConfirmationModal(ModalScreen): ) def on_mount(self) -> None: - """Called when the modal is mounted. Set focus and ensure modal captures input.""" - # Set focus to the modal screen itself first - self.focus() - # Then focus on the Save button - self.call_after_refresh(self._focus_save_button) - - def _focus_save_button(self) -> None: - """Focus the save button after refresh.""" + """Called when the modal is mounted. Set focus to the first button.""" + # Focus on the Save button by default save_button = self.query_one("#save-button", Button) save_button.focus() - def on_key(self, event) -> None: - """Handle key events, ensuring tab navigation works within the modal.""" - if event.key == "tab": - # Get all buttons in order - buttons = [ - self.query_one("#save-button", Button), - self.query_one("#discard-button", Button), - self.query_one("#cancel-button", Button), - ] - - # Find currently focused button and move to next - for i, button in enumerate(buttons): - if button.has_focus: - next_button = buttons[(i + 1) % len(buttons)] - next_button.focus() - event.prevent_default() - return - - # If no button has focus, focus the first one - buttons[0].focus() - event.prevent_default() - - elif event.key == "shift+tab": - # Get all buttons in order - buttons = [ - self.query_one("#save-button", Button), - self.query_one("#discard-button", Button), - self.query_one("#cancel-button", Button), - ] - - # Find currently focused button and move to previous - for i, button in enumerate(buttons): - if button.has_focus: - prev_button = buttons[(i - 1) % len(buttons)] - prev_button.focus() - event.prevent_default() - return - - # If no button has focus, focus the last one - buttons[-1].focus() - event.prevent_default() - def on_button_pressed(self, event: Button.Pressed) -> None: """Handle button presses.""" if event.button.id == "save-button": diff --git a/tests/test_save_confirmation_modal.py b/tests/test_save_confirmation_modal.py index d13ed41..c6c268a 100644 --- a/tests/test_save_confirmation_modal.py +++ b/tests/test_save_confirmation_modal.py @@ -56,25 +56,14 @@ class TestSaveConfirmationModal: modal.dismiss.assert_called_once_with("cancel") - @patch.object(SaveConfirmationModal, "call_after_refresh") - @patch.object(SaveConfirmationModal, "focus") - def test_on_mount_sets_focus(self, mock_focus, mock_call_after_refresh): - """Test that on_mount sets focus to the modal and schedules button focus.""" - modal = SaveConfirmationModal() - - modal.on_mount() - - mock_focus.assert_called_once() - mock_call_after_refresh.assert_called_once() - @patch.object(SaveConfirmationModal, "query_one") - def test_focus_save_button(self, mock_query_one): - """Test that _focus_save_button focuses the save button.""" + def test_on_mount_sets_focus(self, mock_query_one): + """Test that on_mount sets focus to the save button.""" modal = SaveConfirmationModal() mock_save_button = Mock() mock_query_one.return_value = mock_save_button - modal._focus_save_button() + modal.on_mount() mock_query_one.assert_called_once_with("#save-button", Button) mock_save_button.focus.assert_called_once()