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.
This commit is contained in:
@@ -281,12 +281,14 @@
|
|||||||
|
|
||||||
<div class="sender-receiver-popup__field">
|
<div class="sender-receiver-popup__field">
|
||||||
<div class="sender-receiver-popup__label">E-Mail-Adresse</div>
|
<div class="sender-receiver-popup__label">E-Mail-Adresse</div>
|
||||||
<DxTextBox Text="@_receiverDraftEmail"
|
<div @onkeydown="OnReceiverEmailKeyDownAsync">
|
||||||
TextChanged="OnReceiverEmailTextChangedAsync"
|
<DxTextBox Text="@_receiverDraftEmail"
|
||||||
NullText="name@beispiel.de"
|
TextChanged="OnReceiverEmailTextChangedAsync"
|
||||||
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
|
NullText="name@beispiel.de"
|
||||||
BindValueMode="BindValueMode.OnInput"
|
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
|
||||||
CssClass="w-100" />
|
BindValueMode="BindValueMode.OnInput"
|
||||||
|
CssClass="w-100" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="sender-receiver-popup__suggestions-shell">
|
<div class="sender-receiver-popup__suggestions-shell">
|
||||||
@if (_receiverEmailSuggestions.Count > 0)
|
@if (_receiverEmailSuggestions.Count > 0)
|
||||||
@@ -295,7 +297,7 @@
|
|||||||
<DxListBox TData="string"
|
<DxListBox TData="string"
|
||||||
TValue="string"
|
TValue="string"
|
||||||
Data="@_receiverEmailSuggestions"
|
Data="@_receiverEmailSuggestions"
|
||||||
Value="@_receiverDraftEmail"
|
Value="@_selectedReceiverEmailSuggestion"
|
||||||
ValueChanged="OnReceiverEmailSuggestionSelectedAsync"
|
ValueChanged="OnReceiverEmailSuggestionSelectedAsync"
|
||||||
SelectionMode="ListBoxSelectionMode.Single"
|
SelectionMode="ListBoxSelectionMode.Single"
|
||||||
CssClass="w-100" />
|
CssClass="w-100" />
|
||||||
@@ -355,6 +357,7 @@
|
|||||||
bool _receiverPopupVisible;
|
bool _receiverPopupVisible;
|
||||||
string _receiverDraftName = string.Empty;
|
string _receiverDraftName = string.Empty;
|
||||||
string _receiverDraftEmail = string.Empty;
|
string _receiverDraftEmail = string.Empty;
|
||||||
|
string? _selectedReceiverEmailSuggestion;
|
||||||
string? _receiverPopupValidationMessage;
|
string? _receiverPopupValidationMessage;
|
||||||
bool _isReceiverEmailSearchRunning;
|
bool _isReceiverEmailSearchRunning;
|
||||||
List<string> _receiverEmailSuggestions = [];
|
List<string> _receiverEmailSuggestions = [];
|
||||||
@@ -473,6 +476,7 @@
|
|||||||
{
|
{
|
||||||
_receiverDraftName = string.Empty;
|
_receiverDraftName = string.Empty;
|
||||||
_receiverDraftEmail = string.Empty;
|
_receiverDraftEmail = string.Empty;
|
||||||
|
_selectedReceiverEmailSuggestion = null;
|
||||||
_receiverPopupValidationMessage = null;
|
_receiverPopupValidationMessage = null;
|
||||||
_receiverEmailSuggestions.Clear();
|
_receiverEmailSuggestions.Clear();
|
||||||
_receiverPopupVisible = true;
|
_receiverPopupVisible = true;
|
||||||
@@ -482,6 +486,7 @@
|
|||||||
{
|
{
|
||||||
_receiverPopupVisible = false;
|
_receiverPopupVisible = false;
|
||||||
_receiverPopupValidationMessage = null;
|
_receiverPopupValidationMessage = null;
|
||||||
|
_selectedReceiverEmailSuggestion = null;
|
||||||
_isReceiverEmailSearchRunning = false;
|
_isReceiverEmailSearchRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,12 +496,56 @@
|
|||||||
_receiverPopupValidationMessage = null;
|
_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)
|
Task OnReceiverEmailSuggestionSelectedAsync(string? value)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(value))
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
_receiverDraftEmail = value.Trim();
|
_selectedReceiverEmailSuggestion = value.Trim();
|
||||||
|
_receiverDraftEmail = _selectedReceiverEmailSuggestion;
|
||||||
_receiverPopupValidationMessage = null;
|
_receiverPopupValidationMessage = null;
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -504,6 +553,7 @@
|
|||||||
async Task OnReceiverEmailTextChangedAsync(string? value)
|
async Task OnReceiverEmailTextChangedAsync(string? value)
|
||||||
{
|
{
|
||||||
_receiverDraftEmail = value?.Trim() ?? string.Empty;
|
_receiverDraftEmail = value?.Trim() ?? string.Empty;
|
||||||
|
_selectedReceiverEmailSuggestion = _receiverDraftEmail;
|
||||||
_receiverPopupValidationMessage = null;
|
_receiverPopupValidationMessage = null;
|
||||||
|
|
||||||
var searchVersion = ++_receiverEmailSearchVersion;
|
var searchVersion = ++_receiverEmailSearchVersion;
|
||||||
@@ -511,6 +561,7 @@
|
|||||||
if (string.IsNullOrWhiteSpace(_receiverDraftEmail) || _receiverDraftEmail.Length < 2)
|
if (string.IsNullOrWhiteSpace(_receiverDraftEmail) || _receiverDraftEmail.Length < 2)
|
||||||
{
|
{
|
||||||
_receiverEmailSuggestions.Clear();
|
_receiverEmailSuggestions.Clear();
|
||||||
|
_selectedReceiverEmailSuggestion = null;
|
||||||
_isReceiverEmailSearchRunning = false;
|
_isReceiverEmailSearchRunning = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -530,12 +581,18 @@
|
|||||||
.OrderBy(email => email)
|
.OrderBy(email => email)
|
||||||
.Take(12)
|
.Take(12)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
_selectedReceiverEmailSuggestion = _receiverEmailSuggestions.FirstOrDefault(email =>
|
||||||
|
string.Equals(email, _receiverDraftEmail, StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogWarning(ex, "Failed to load receiver email suggestions for {SearchTerm}", _receiverDraftEmail);
|
Logger.LogWarning(ex, "Failed to load receiver email suggestions for {SearchTerm}", _receiverDraftEmail);
|
||||||
if (searchVersion == _receiverEmailSearchVersion)
|
if (searchVersion == _receiverEmailSearchVersion)
|
||||||
|
{
|
||||||
_receiverEmailSuggestions.Clear();
|
_receiverEmailSuggestions.Clear();
|
||||||
|
_selectedReceiverEmailSuggestion = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user