From 3ff3373b27069486f7bb3f39cf3e06ea6d89857e Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 1 Jul 2026 17:10:54 +0200 Subject: [PATCH] Improve email suggestion handling and keyboard navigation Enhanced the email suggestion feature by adding keyboard navigation support (`ArrowUp`, `ArrowDown`, `Enter`, `Escape`) and introducing `_selectedReceiverEmailSuggestion` to track the current selection. Updated methods to synchronize input and suggestions, pre-select matching suggestions, and reset the state when the popup is opened or closed. Improved error handling and ensured clean state management for better user experience. --- .../Pages/EnvelopeSenderEditorPage.razor | 73 +++++++++++++++++-- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor index 71bce201..41dbd89a 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeSenderEditorPage.razor @@ -281,12 +281,14 @@
E-Mail-Adresse
- +
+ +
@if (_receiverEmailSuggestions.Count > 0) @@ -295,7 +297,7 @@ @@ -355,6 +357,7 @@ bool _receiverPopupVisible; string _receiverDraftName = string.Empty; string _receiverDraftEmail = string.Empty; + string? _selectedReceiverEmailSuggestion; string? _receiverPopupValidationMessage; bool _isReceiverEmailSearchRunning; List _receiverEmailSuggestions = []; @@ -473,6 +476,7 @@ { _receiverDraftName = string.Empty; _receiverDraftEmail = string.Empty; + _selectedReceiverEmailSuggestion = null; _receiverPopupValidationMessage = null; _receiverEmailSuggestions.Clear(); _receiverPopupVisible = true; @@ -482,6 +486,7 @@ { _receiverPopupVisible = false; _receiverPopupValidationMessage = null; + _selectedReceiverEmailSuggestion = null; _isReceiverEmailSearchRunning = false; } @@ -491,12 +496,56 @@ _receiverPopupValidationMessage = null; } + async Task OnReceiverEmailKeyDownAsync(KeyboardEventArgs e) + { + if (_receiverEmailSuggestions.Count == 0) + { + if (e.Key == "Escape") + _selectedReceiverEmailSuggestion = null; + + return; + } + + var currentIndex = _selectedReceiverEmailSuggestion is null + ? -1 + : _receiverEmailSuggestions.FindIndex(email => string.Equals(email, _selectedReceiverEmailSuggestion, StringComparison.OrdinalIgnoreCase)); + + if (e.Key == "ArrowDown") + { + var nextIndex = currentIndex < _receiverEmailSuggestions.Count - 1 ? currentIndex + 1 : 0; + await OnReceiverEmailSuggestionSelectedAsync(_receiverEmailSuggestions[nextIndex]); + } + else if (e.Key == "ArrowUp") + { + var nextIndex = currentIndex > 0 ? currentIndex - 1 : _receiverEmailSuggestions.Count - 1; + await OnReceiverEmailSuggestionSelectedAsync(_receiverEmailSuggestions[nextIndex]); + } + else if (e.Key == "Enter") + { + var selectedValue = currentIndex >= 0 && currentIndex < _receiverEmailSuggestions.Count + ? _receiverEmailSuggestions[currentIndex] + : _receiverEmailSuggestions.FirstOrDefault(); + + if (!string.IsNullOrWhiteSpace(selectedValue)) + { + await OnReceiverEmailSuggestionSelectedAsync(selectedValue); + _receiverEmailSuggestions.Clear(); + } + } + else if (e.Key == "Escape") + { + _receiverEmailSuggestions.Clear(); + _selectedReceiverEmailSuggestion = null; + } + } + Task OnReceiverEmailSuggestionSelectedAsync(string? value) { if (string.IsNullOrWhiteSpace(value)) return Task.CompletedTask; - _receiverDraftEmail = value.Trim(); + _selectedReceiverEmailSuggestion = value.Trim(); + _receiverDraftEmail = _selectedReceiverEmailSuggestion; _receiverPopupValidationMessage = null; return Task.CompletedTask; } @@ -504,6 +553,7 @@ async Task OnReceiverEmailTextChangedAsync(string? value) { _receiverDraftEmail = value?.Trim() ?? string.Empty; + _selectedReceiverEmailSuggestion = _receiverDraftEmail; _receiverPopupValidationMessage = null; var searchVersion = ++_receiverEmailSearchVersion; @@ -511,6 +561,7 @@ if (string.IsNullOrWhiteSpace(_receiverDraftEmail) || _receiverDraftEmail.Length < 2) { _receiverEmailSuggestions.Clear(); + _selectedReceiverEmailSuggestion = null; _isReceiverEmailSearchRunning = false; return; } @@ -530,12 +581,18 @@ .OrderBy(email => email) .Take(12) .ToList(); + + _selectedReceiverEmailSuggestion = _receiverEmailSuggestions.FirstOrDefault(email => + string.Equals(email, _receiverDraftEmail, StringComparison.OrdinalIgnoreCase)); } catch (Exception ex) { Logger.LogWarning(ex, "Failed to load receiver email suggestions for {SearchTerm}", _receiverDraftEmail); if (searchVersion == _receiverEmailSearchVersion) + { _receiverEmailSuggestions.Clear(); + _selectedReceiverEmailSuggestion = null; + } } finally {