Skip to content

Commit 1dc702c

Browse files
YomodoJeffrey Jangli
andauthored
Fixed HandleOnBlur (#317)
Disabled some unused code Co-authored-by: Jeffrey Jangli <Jeffrey.Jangli@kpn.com>
1 parent 5796c96 commit 1dc702c

4 files changed

Lines changed: 129 additions & 110 deletions

File tree

CodeBeam.MudBlazor.Extensions/Components/ComboBox/MudComboBox.razor

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
Class="@InputClassname" Style="@InputStyle" Margin="@Margin" Placeholder="@Placeholder"
1515
Variant="@Variant" Immediate="true"
1616
TextUpdateSuppression="false"
17-
ShowVisualiser="@((MultiSelection == true && SelectedValues.Count() != 0) || Editable == false)" DataVisualiserStyle="min-height: 1.1876em"
18-
Value="@_searchString" ValueChanged="@HandleInternalValueChanged"
17+
ShowVisualiser="@((MultiSelection && SelectedValues.Any()) || !Editable)" DataVisualiserStyle="min-height: 1.1876em"
18+
@bind-Value="@_searchString"
1919
DisableUnderLine="@DisableUnderLine"
2020
Disabled="@Disabled" ReadOnly="@ReadOnly" Error="@Error" ErrorId="@ErrorId"
21-
Clearable="@Clearable" ForceClearable="@(Clearable && HasValue(Value))" OnClearButtonClick="(async (e) => await ClearButtonClickHandlerAsync(e))"
22-
@attributes="UserAttributes" OnBlur="@HandleOnBlur" ForceShrink="@(HasValue(Value) || _isOpen || ForceShrink)">
21+
Clearable="@Clearable" ForceClearable="@(Clearable && HasValue(Value))" OnClearButtonClick="@ClearButtonClickHandlerAsync"
22+
@attributes="UserAttributes" OnBlur="@HandleOnBlur" ForceShrink="@(HasValue(Value) || _isOpen || ForceShrink)">
2323

2424
<AdornmentEnd>
2525
<MudIcon Icon="@_currentIcon" Color="@AdornmentColor" Size="@IconSize" @onclick="OnAdornmentClick" />
@@ -35,23 +35,23 @@
3535
{
3636
<MudChipSet Class="d-flex flex-wrap mud-width-full" AllClosable="ChipCloseable" OnClose="ChipClosed">
3737
@foreach (var item in Items?.Where(x => (MultiSelection ? SelectedValues.Contains(x.Value) : Value?.Equals(x.Value) == true)) ?? new List<MudComboBoxItem<T>>())
38-
{
39-
<MudChip Class="@ChipClass" Value="item.Value" Text="@(ToStringFunc != null ? ToStringFunc.Invoke(item.Value) : string.IsNullOrEmpty(item.Text) ? Converter.Set(item.Value) : item.Text)" Color="@Color" Size="@ChipSize" Variant="@ChipVariant" @onmousedown:stopPropagation />
40-
}
41-
@*@if (ItemCollection != null)
4238
{
43-
foreach (var item in ItemCollection.Where(x => SelectedValues.Contains(x)))
44-
{
45-
<MudChip Class="@ChipClass" Value="@item" Text="@Converter.Set(item)" Color="@Color" Size="@ChipSize" Variant="@ChipVariant" @onmousedown:stopPropagation />
46-
}
39+
<MudChip Class="@ChipClass" Value="item.Value" Text="@(ToStringFunc != null ? ToStringFunc.Invoke(item.Value) : string.IsNullOrEmpty(item.Text) ? Converter.Set(item.Value) : item.Text)" Color="@Color" Size="@ChipSize" Variant="@ChipVariant" @onmousedown:stopPropagation />
4740
}
48-
else
49-
{
50-
foreach (var item in Items?.Where(x => (MultiSelection ? SelectedValues.Contains(x.Value) : Value?.Equals(x.Value) == true)) ?? new List<MudComboboxItem<T>>())
51-
{
52-
<MudChip Class="@ChipClass" Value="item.Value" Text="@(ToStringFunc != null ? ToStringFunc.Invoke(item.Value) : string.IsNullOrEmpty(item.Text) ? Converter.Set(item.Value) : item.Text)" Color="@Color" Size="@ChipSize" Variant="@ChipVariant" @onmousedown:stopPropagation />
53-
}
54-
}*@
41+
@*@if (ItemCollection != null)
42+
{
43+
foreach (var item in ItemCollection.Where(x => SelectedValues.Contains(x)))
44+
{
45+
<MudChip Class="@ChipClass" Value="@item" Text="@Converter.Set(item)" Color="@Color" Size="@ChipSize" Variant="@ChipVariant" @onmousedown:stopPropagation />
46+
}
47+
}
48+
else
49+
{
50+
foreach (var item in Items?.Where(x => (MultiSelection ? SelectedValues.Contains(x.Value) : Value?.Equals(x.Value) == true)) ?? new List<MudComboboxItem<T>>())
51+
{
52+
<MudChip Class="@ChipClass" Value="item.Value" Text="@(ToStringFunc != null ? ToStringFunc.Invoke(item.Value) : string.IsNullOrEmpty(item.Text) ? Converter.Set(item.Value) : item.Text)" Color="@Color" Size="@ChipSize" Variant="@ChipVariant" @onmousedown:stopPropagation />
53+
}
54+
}*@
5555
</MudChipSet>
5656
}
5757
else if (InputPresenter == ValuePresenter.Text && (Editable == false || (MultiSelection == true && Editable == true)))
@@ -116,31 +116,31 @@
116116
@if (MultiSelection)
117117
{
118118
<div Style="position: sticky; top: 0px; background-color: var(--mud-palette-background); z-index: 2" @onkeydown:stopPropagation>
119-
@if (Editable)
120-
{
121-
<div class="pa-2">
122-
<MudTextFieldExtended id="@($"{_elementId}-autocomplete")" @ref="_searchbox" T="string" Value="_searchString" ValueChanged="@HandleInternalValueChanged" Margin="Margin.Dense"
123-
Variant="Variant.Outlined" Immediate="true" OnKeyDown="SearchBoxHandleKeyDown" OnKeyUp="SearchBoxHandleKeyUp" Clearable="@SearchBoxClearable">
124-
<AdornmentEnd>
125-
<MudIcon Icon="@Icons.Material.Filled.Search" Color="@Color" />
126-
</AdornmentEnd>
127-
</MudTextFieldExtended>
128-
</div>
129-
}
119+
@if (Editable)
120+
{
121+
<div class="pa-2">
122+
<MudTextFieldExtended id="@($"{_elementId}-autocomplete")" @ref="@_searchbox" T="string" @bind-Value="@_searchString" Margin="Margin.Dense"
123+
Variant="Variant.Outlined" Immediate="true" OnKeyDown="@SearchBoxHandleKeyDown" OnKeyUp="@SearchBoxHandleKeyUp" Clearable="@SearchBoxClearable">
124+
<AdornmentEnd>
125+
<MudIcon Icon="@Icons.Material.Filled.Search" Color="@Color" />
126+
</AdornmentEnd>
127+
</MudTextFieldExtended>
128+
</div>
129+
}
130130

131-
@if (SelectAll)
132-
{
133-
<div class="@($"mud-combobox-item mud-combobox-item-clickable mud-combobox-item-{Dense.ToDescriptionString()} mud-ripple d-flex")" @onclick="SelectAllItems" @onclick:stopPropagation="true">
134-
<MudCheckBox Class="mx-4" @bind-Checked="_allSelected" Color="@Color" @onclick="SelectAllItems" Dense="true" />
135-
<MudText Typo="GetTypo()">@SelectAllText</MudText>
136-
</div>
137-
<MudDivider />
138-
}
131+
@if (SelectAll)
132+
{
133+
<div class="@($"mud-combobox-item mud-combobox-item-clickable mud-combobox-item-{Dense.ToDescriptionString()} mud-ripple d-flex")" @onclick="SelectAllItems" @onclick:stopPropagation="true">
134+
<MudCheckBox Class="mx-4" @bind-Checked="@_allSelected" Color="@Color" @onclick="@SelectAllItems" Dense="true" />
135+
<MudText Typo="GetTypo()">@SelectAllText</MudText>
136+
</div>
137+
<MudDivider />
138+
}
139139
</div>
140140
}
141141

142142
@ChildContent
143-
@if (NoItemsContent != null && HasEligibleItems() == false)
143+
@if (NoItemsContent != null && !HasEligibleItems())
144144
{
145145
<div class="pa-2">
146146
@NoItemsContent

CodeBeam.MudBlazor.Extensions/Components/ComboBox/MudComboBox.razor.cs

Lines changed: 80 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -455,11 +455,11 @@ protected async Task SyncMultiselectionValues(bool singleToMultiselection)
455455
{
456456
SelectedValues = new HashSet<T>() { Value };
457457
}
458-
458+
459459
}
460460
await SelectedValuesChanged.InvokeAsync(_selectedValues);
461461
}
462-
else
462+
else
463463
{
464464
await SetValueAsync(SelectedValues.LastOrDefault(), false);
465465
_searchString = Converter.Set(SelectedValues.LastOrDefault());
@@ -652,7 +652,7 @@ protected override void OnInitialized()
652652
// TODO: Check this line again
653653
SetValueAsync(SelectedValues.FirstOrDefault()).AndForget();
654654
}
655-
655+
656656
}
657657

658658
bool _oldShowCheckbox = true;
@@ -873,8 +873,6 @@ protected internal async Task SearchBoxHandleKeyDown(KeyboardEventArgs obj)
873873
case "ArrowDown":
874874
case "Home":
875875
case "End":
876-
HandleKeyDown(obj);
877-
break;
878876
case "Enter":
879877
case "NumpadEnter":
880878
HandleKeyDown(obj);
@@ -885,7 +883,7 @@ protected internal async Task SearchBoxHandleKeyDown(KeyboardEventArgs obj)
885883
StateHasChanged();
886884
break;
887885
}
888-
886+
889887
}
890888

891889
protected internal void SearchBoxHandleKeyUp(KeyboardEventArgs obj)
@@ -901,17 +899,38 @@ protected internal async void HandleKeyUp(KeyboardEventArgs obj)
901899

902900
protected internal async Task HandleOnBlur(FocusEventArgs obj)
903901
{
904-
if (Strict)
902+
if (!MultiSelection)
905903
{
906-
var item = Items.FirstOrDefault(x => Converter.Set(x.Value).Equals(_searchString, StringComparison.OrdinalIgnoreCase));
907-
if (item is not null)
908-
await ToggleOption(item, true);
904+
if (Strict)
905+
{
906+
// Check if the user-provided search string is an exact (case-insensitive) match against an item in the collection.
907+
var item = Items.FirstOrDefault(x => Converter.Set(x.Value).Equals(_searchString, StringComparison.OrdinalIgnoreCase));
908+
if (item is not null)
909+
await ToggleOption(item, true);
910+
911+
// No item equals the user-provided search string.
912+
else
913+
{
914+
// Restore the previous selected item, if any.
915+
if (Value is not null)
916+
{
917+
item = Items.FirstOrDefault(x => x.Value.Equals(Value));
918+
if (item is not null)
919+
await ToggleOption(item, true);
920+
921+
// Remove non-matching search string.
922+
else
923+
await Clear();
924+
}
925+
926+
// There was no previous selected item. Remove non-matching search string.
927+
else
928+
await Clear();
929+
}
930+
}
909931
else
910-
await Clear();
932+
await UpdateComboBoxValueAsync(Converter.Get(_searchString), updateText: true, updateSearchString: true);
911933
}
912-
else
913-
await UpdateComboBoxValueAsync(Converter.Get(_searchString), updateText: true, updateSearchString: true);
914-
915934
await OnBlurredAsync(obj);
916935
}
917936

@@ -956,9 +975,7 @@ public async Task ToggleMenu()
956975
else
957976
{
958977
await OpenMenu();
959-
960978
}
961-
962979
}
963980

964981
public async Task OpenMenu()
@@ -968,18 +985,22 @@ public async Task OpenMenu()
968985
_isOpen = true;
969986
UpdateIcon();
970987
StateHasChanged();
988+
971989
if (Editable)
972990
{
973-
if (MultiSelection == true && SearchBoxAutoFocus == true)
991+
if (MultiSelection)
974992
{
975-
await Task.Delay(1);
976-
await _searchbox.SelectAsync();
993+
if (SearchBoxAutoFocus)
994+
{
995+
await Task.Delay(1);
996+
await _searchbox.SelectAsync();
997+
}
977998
}
978999
else
979-
{
9801000
await _inputReference.SelectAsync();
981-
}
9821001
}
1002+
1003+
// Disable escape propagation: if ComboBox menu is open, only the ComboBox popover should close and underlying components should not handle escape key.
9831004
await _keyInterceptor.UpdateKey(new() { Key = "Escape", StopDown = "Key+none" });
9841005

9851006
if (MultiSelection)
@@ -1002,6 +1023,7 @@ public async Task CloseMenu()
10021023
DeactiveAllItems();
10031024
StateHasChanged();
10041025

1026+
// Enable escape propagation: The ComboBox popover was closed, no underlying components are allowed to handle escape key.
10051027
await _keyInterceptor.UpdateKey(new() { Key = "Escape", StopDown = "none" });
10061028

10071029
await OnClose.InvokeAsync();
@@ -1050,7 +1072,7 @@ protected internal async Task ToggleOption(MudComboBoxItem<T> item, bool selecte
10501072
SelectedValues = SelectedValues.Append(item.Value);
10511073
await SelectedValuesChanged.InvokeAsync(_selectedValues);
10521074
_allSelected = GetAllSelectedState();
1053-
1075+
10541076
//await Task.Delay(1);
10551077
}
10561078
item.Selected = true;
@@ -1086,10 +1108,10 @@ public override async Task ForceUpdate()
10861108
}
10871109
}
10881110

1089-
public async Task BeginValidatePublic()
1090-
{
1091-
await BeginValidateAsync();
1092-
}
1111+
//public async Task BeginValidatePublic()
1112+
//{
1113+
// await BeginValidateAsync();
1114+
//}
10931115

10941116
protected internal bool? Add(MudComboBoxItem<T> item)
10951117
{
@@ -1118,7 +1140,7 @@ public async Task BeginValidatePublic()
11181140
/// <summary>
11191141
/// Extra handler for clearing selection.
11201142
/// </summary>
1121-
protected async ValueTask ClearButtonClickHandlerAsync(MouseEventArgs e)
1143+
protected async Task ClearButtonClickHandlerAsync(MouseEventArgs e)
11221144
{
11231145
await UpdateComboBoxValueAsync(default);
11241146
_searchString = null;
@@ -1273,22 +1295,22 @@ protected int GetActiveProperItemIndex()
12731295
return -1;
12741296
}
12751297

1276-
protected T GetActiveItemValue()
1277-
{
1278-
if (_lastActivatedItem == null)
1279-
{
1280-
return Items.FirstOrDefault(x => x.Active == true).Value;
1281-
}
1282-
else
1283-
{
1284-
return _lastActivatedItem.Value;
1285-
}
1286-
}
1298+
//protected T GetActiveItemValue()
1299+
//{
1300+
// if (_lastActivatedItem == null)
1301+
// {
1302+
// return Items.FirstOrDefault(x => x.Active == true).Value;
1303+
// }
1304+
// else
1305+
// {
1306+
// return _lastActivatedItem.Value;
1307+
// }
1308+
//}
12871309

1288-
protected internal void UpdateLastActivatedItem(T value)
1289-
{
1290-
_lastActivatedItem = Items.FirstOrDefault(x => value == null ? x.Value == null : Comparer != null ? Comparer.Equals(value, x.Value) : value.Equals(x.Value));
1291-
}
1310+
//protected internal void UpdateLastActivatedItem(T value)
1311+
//{
1312+
// _lastActivatedItem = Items.FirstOrDefault(x => value == null ? x.Value == null : Comparer != null ? Comparer.Equals(value, x.Value) : value.Equals(x.Value));
1313+
//}
12921314

12931315
protected void DeactiveAllItems()
12941316
{
@@ -1365,21 +1387,23 @@ public async Task ActivateFirstItem(string startsWith = null)
13651387
public async Task ActivateAdjacentItem(int changeCount)
13661388
{
13671389
if (Items == null || Items.Count == 0)
1368-
{
13691390
return;
1370-
}
13711391

13721392
var properItems = GetEnabledAndEligibleItems();
13731393
int index = GetActiveProperItemIndex();
1374-
if (index + changeCount >= properItems.Count || 0 > index + changeCount)
1394+
if (properItems.Count == 1 && index == 0)
1395+
{
1396+
properItems[0].SetActive(true);
1397+
_lastActivatedItem = properItems[0];
1398+
}
1399+
else if (index + changeCount >= properItems.Count || 0 > index + changeCount)
13751400
{
13761401
return;
13771402
}
1378-
1403+
13791404
DeactiveAllItems();
13801405
properItems[index + changeCount].SetActive(true);
13811406
_lastActivatedItem = properItems[index + changeCount];
1382-
13831407
await ScrollToMiddleAsync(Items[index + changeCount]);
13841408
}
13851409

@@ -1399,30 +1423,25 @@ public async Task ActivateLastItem()
13991423
}
14001424
_lastActivatedItem = item;
14011425
}
1402-
1426+
14031427
#endregion
14041428

14051429
protected internal List<MudComboBoxItem<T>> GetEnabledAndEligibleItems() => Items.Where(x => !x.Disabled && x.Eligible).ToList();
1406-
14071430

14081431
protected bool HasEligibleItems()
14091432
{
1410-
return Items.Any(x => x.Eligible == true);
1433+
foreach (var item in CollectionsMarshal.AsSpan(Items))
1434+
{
1435+
if (item.Eligible)
1436+
return true;
1437+
}
1438+
return false;
14111439
}
14121440

14131441
protected internal string GetSearchString() => _searchString;
14141442

1415-
protected Typo GetTypo()
1416-
{
1417-
if (Dense == Dense.Slim || Dense == Dense.Superslim)
1418-
{
1419-
return Typo.body2;
1420-
}
1421-
1422-
return Typo.body1;
1423-
}
1443+
protected Typo GetTypo() => Dense == Dense.Slim || Dense == Dense.Superslim ? Typo.body2 : Typo.body1;
14241444

1425-
protected internal ValueTask ScrollToMiddleAsync(MudComboBoxItem<T> item) =>
1426-
item is not null ? ScrollManagerExtended.ScrollToMiddleAsync(_popoverId, item.ItemId) : ValueTask.CompletedTask;
1445+
protected internal ValueTask ScrollToMiddleAsync(MudComboBoxItem<T> item) => item is not null ? ScrollManagerExtended.ScrollToMiddleAsync(_popoverId, item.ItemId) : ValueTask.CompletedTask;
14271446
}
14281447
}

0 commit comments

Comments
 (0)