From 3c1c69728a90d24d6d060f0409c48f881111b416 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 10 Aug 2026 16:52:33 +0800 Subject: [PATCH 1/3] Focus the first input of MudBlazor dialogs opened from action menus --- .../Components/AbpMudActionMenu.razor | 24 ++++++ .../Components/AbpMudActionMenu.razor.cs | 80 +++++++++++++++++++ .../Components/AbpMudActionMenuItem.razor | 15 ++++ .../Components/AbpMudActionMenuItem.razor.cs | 61 ++++++++++++++ .../Components/MudEntityAction.razor | 4 +- .../Components/MudEntityActions.razor | 13 +-- .../Components/FeatureManagementModal.razor | 2 +- .../PermissionManagementModal.razor | 1 + .../ResourcePermissionManagementModal.razor | 12 +-- .../_Imports.razor | 1 + 10 files changed, 198 insertions(+), 15 deletions(-) create mode 100644 framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor create mode 100644 framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs create mode 100644 framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor create mode 100644 framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor.cs diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor new file mode 100644 index 0000000000..e4c22b1079 --- /dev/null +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor @@ -0,0 +1,24 @@ +@using MudBlazor + + + + + @ChildContent + + + diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs new file mode 100644 index 0000000000..a05b8f7c21 --- /dev/null +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs @@ -0,0 +1,80 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using MudBlazor; + +namespace Volo.Abp.MudBlazorUI.Components; + +/// +/// A for entity/row actions that open a dialog. +/// Use it together with . +/// +public partial class AbpMudActionMenu : ComponentBase +{ + protected MudMenu? _menu; + + [Parameter] + public string? Icon { get; set; } + + [Parameter] + public Color IconColor { get; set; } = Color.Inherit; + + [Parameter] + public string? StartIcon { get; set; } + + [Parameter] + public string? Label { get; set; } + + [Parameter] + public string? AriaLabel { get; set; } + + [Parameter] + public Color Color { get; set; } = Color.Default; + + [Parameter] + public Variant Variant { get; set; } = Variant.Text; + + [Parameter] + public Size Size { get; set; } = Size.Medium; + + [Parameter] + public bool Dense { get; set; } + + [Parameter] + public Origin? AnchorOrigin { get; set; } + + [Parameter] + public Origin TransformOrigin { get; set; } = Origin.TopLeft; + + [Parameter] + public bool Disabled { get; set; } + + [Parameter] + public string? Class { get; set; } + + [Parameter] + public string? Style { get; set; } + + /// + /// Replaces the default activator button. The menu is opened through the given + /// , same as . + /// + [Parameter] + public RenderFragment? ActivatorContent { get; set; } + + [Parameter] + public RenderFragment? ChildContent { get; set; } + + /// + /// Closes the menu and returns the focus to its activator. + /// calls this before running its handler: MudBlazor restores + /// the focus while closing the menu, and doing that after the handler opened a dialog would take + /// the focus back out of that dialog. + /// + public virtual async Task CloseAsync() + { + if (_menu != null) + { + await _menu.CloseAllMenusAsync(); + } + } +} diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor new file mode 100644 index 0000000000..f2bd4d56d0 --- /dev/null +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor @@ -0,0 +1,15 @@ +@using MudBlazor + + + @ChildContent + diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor.cs b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor.cs new file mode 100644 index 0000000000..3d5e5b8168 --- /dev/null +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +using MudBlazor; + +namespace Volo.Abp.MudBlazorUI.Components; + +/// +/// An item of an . It closes the menu before running +/// , so a dialog opened by the handler keeps the focus. +/// Outside an it behaves like a plain . +/// +public partial class AbpMudActionMenuItem : ComponentBase +{ + [CascadingParameter] + protected AbpMudActionMenu? ParentMenu { get; set; } + + [Parameter] + public EventCallback OnClick { get; set; } + + [Parameter] + public bool Disabled { get; set; } + + [Parameter] + public string? Icon { get; set; } + + [Parameter] + public Color IconColor { get; set; } = Color.Inherit; + + [Parameter] + public string? Label { get; set; } + + [Parameter] + public string? Href { get; set; } + + [Parameter] + public string? Target { get; set; } + + [Parameter] + public bool ForceLoad { get; set; } + + [Parameter] + public string? Class { get; set; } + + [Parameter(CaptureUnmatchedValues = true)] + public Dictionary? UserAttributes { get; set; } + + [Parameter] + public RenderFragment? ChildContent { get; set; } + + protected virtual async Task OnClickHandlerAsync(MouseEventArgs args) + { + if (ParentMenu != null) + { + await ParentMenu.CloseAsync(); + } + + await OnClick.InvokeAsync(args); + } +} diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/MudEntityAction.razor b/framework/src/Volo.Abp.MudBlazorUI/Components/MudEntityAction.razor index c1ae598b89..7436c570e9 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/MudEntityAction.razor +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/MudEntityAction.razor @@ -7,13 +7,13 @@ { if (Primary == false) { - + @if (!string.IsNullOrEmpty(Icon)) { } @Text - + } } else diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/MudEntityActions.razor b/framework/src/Volo.Abp.MudBlazorUI/Components/MudEntityActions.razor index e60654fdf1..379cb192fc 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/MudEntityActions.razor +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/MudEntityActions.razor @@ -4,15 +4,16 @@ @if (Type == MudActionType.Dropdown || DisabledOrNoActions()) { - + @ChildContent - + } else { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor index fd4711c104..6b542ef6e5 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor @@ -5,7 +5,7 @@ @using Volo.Abp.FeatureManagement.Localization @inherits AbpFeatureManagementComponentBase - + @L["Features"]@ProviderKeyDisplayName diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor index e26ee3beb1..870bbea127 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/PermissionManagementModal.razor @@ -16,6 +16,7 @@ UserAttributes="@(new Dictionary { { "aria-label", L["Search"].Value } })" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Search" + AutoFocus="true" Immediate="true" /> diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor index be05954983..7f01a7bcec 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/Components/ResourcePermissionManagementModal.razor @@ -24,14 +24,14 @@ - - + + @L["Edit"] - - + + @L["Delete"] - - + + diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/_Imports.razor b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/_Imports.razor index 614bc218c7..aa44b2cc7f 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/_Imports.razor +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor.MudBlazor/_Imports.razor @@ -2,3 +2,4 @@ @using Volo.Abp.AspNetCore.Components.Web @using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout @using MudBlazor +@using Volo.Abp.MudBlazorUI.Components From d2f2572affe4977e5cf3fbfb5f2362aebab6821a Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 10 Aug 2026 20:47:24 +0800 Subject: [PATCH 2/3] Keep the action menu origins and the accessible name of labeled activators --- .../Components/AbpMudActionMenu.razor | 15 +++- .../Components/AbpMudActionMenu.razor.cs | 71 +++++++++++++++++-- .../Components/AbpMudActionMenuItem.razor | 2 +- .../Components/AbpMudActionMenuItem.razor.cs | 23 ++++-- .../Components/FeatureManagementModal.razor | 31 ++++++-- .../FeatureManagementModal.razor.cs | 57 +++++++++++++++ 6 files changed, 181 insertions(+), 18 deletions(-) diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor index e4c22b1079..dd2092acea 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor @@ -4,17 +4,30 @@ Icon="@Icon" IconColor="@IconColor" StartIcon="@StartIcon" + EndIcon="@EndIcon" Label="@Label" - AriaLabel="@AriaLabel" + AriaLabel="@GetAriaLabel()" Color="@Color" Variant="@Variant" Size="@Size" Dense="@Dense" + FullWidth="@FullWidth" + MaxHeight="@MaxHeight" AnchorOrigin="@AnchorOrigin" TransformOrigin="@TransformOrigin" + ActivationEvent="@ActivationEvent" + PositionAtCursor="@PositionAtCursor" + PopoverFixed="@PopoverFixed" + RelativeWidth="@RelativeWidth" + LockScroll="@LockScroll" + Ripple="@Ripple" + DropShadow="@DropShadow" Disabled="@Disabled" Class="@Class" Style="@Style" + ListClass="@ListClass" + PopoverClass="@PopoverClass" + UserAttributes="@UserAttributes" ActivatorContent="@ActivatorContent"> diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs index a05b8f7c21..7a4b1f3ed3 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs @@ -1,5 +1,9 @@ +using System; +using System.Collections.Generic; using System.Threading.Tasks; +using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; using MudBlazor; namespace Volo.Abp.MudBlazorUI.Components; @@ -12,6 +16,9 @@ public partial class AbpMudActionMenu : ComponentBase { protected MudMenu? _menu; + [Inject] + protected IStringLocalizer UiLocalizer { get; set; } = default!; + [Parameter] public string? Icon { get; set; } @@ -21,9 +28,16 @@ public partial class AbpMudActionMenu : ComponentBase [Parameter] public string? StartIcon { get; set; } + [Parameter] + public string? EndIcon { get; set; } + [Parameter] public string? Label { get; set; } + /// + /// The accessible name of the activator. An activator without a falls back + /// to the localized "Actions" text. + /// [Parameter] public string? AriaLabel { get; set; } @@ -39,12 +53,39 @@ public partial class AbpMudActionMenu : ComponentBase [Parameter] public bool Dense { get; set; } + [Parameter] + public bool FullWidth { get; set; } + + [Parameter] + public int? MaxHeight { get; set; } + [Parameter] public Origin? AnchorOrigin { get; set; } [Parameter] public Origin TransformOrigin { get; set; } = Origin.TopLeft; + [Parameter] + public MouseEvent ActivationEvent { get; set; } = MouseEvent.LeftClick; + + [Parameter] + public bool PositionAtCursor { get; set; } + + [Parameter] + public bool PopoverFixed { get; set; } + + [Parameter] + public DropdownWidth RelativeWidth { get; set; } = DropdownWidth.Ignore; + + [Parameter] + public bool LockScroll { get; set; } + + [Parameter] + public bool Ripple { get; set; } = true; + + [Parameter] + public bool DropShadow { get; set; } = true; + [Parameter] public bool Disabled { get; set; } @@ -54,21 +95,39 @@ public partial class AbpMudActionMenu : ComponentBase [Parameter] public string? Style { get; set; } + [Parameter] + public string? ListClass { get; set; } + + [Parameter] + public string? PopoverClass { get; set; } + /// - /// Replaces the default activator button. The menu is opened through the given - /// , same as . + /// Never null, because MudBlazor reads it without a null check while rendering. /// + [Parameter(CaptureUnmatchedValues = true)] + public Dictionary UserAttributes { get; set; } = new(); + [Parameter] public RenderFragment? ActivatorContent { get; set; } [Parameter] public RenderFragment? ChildContent { get; set; } + protected virtual string? GetAriaLabel() + { + if (!AriaLabel.IsNullOrEmpty()) + { + return AriaLabel; + } + + // A label is already the accessible name, so overriding it would hide the visible text. + return Label.IsNullOrEmpty() ? UiLocalizer["Actions"].Value : null; + } + /// - /// Closes the menu and returns the focus to its activator. - /// calls this before running its handler: MudBlazor restores - /// the focus while closing the menu, and doing that after the handler opened a dialog would take - /// the focus back out of that dialog. + /// Closes the whole menu hierarchy. calls this before running + /// its handler, because MudBlazor restores the focus to the activator while closing and that + /// would take the focus out of a dialog the handler opened. /// public virtual async Task CloseAsync() { diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor index f2bd4d56d0..53b2064860 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor @@ -1,6 +1,6 @@ @using MudBlazor - -/// An item of an . It closes the menu before running -/// , so a dialog opened by the handler keeps the focus. -/// Outside an it behaves like a plain . +/// A menu item that closes its menu before running , so a dialog opened by +/// the handler keeps the focus. Works inside an and inside a plain +/// . /// public partial class AbpMudActionMenuItem : ComponentBase { [CascadingParameter] protected AbpMudActionMenu? ParentMenu { get; set; } + [CascadingParameter] + protected MudMenu? ParentMudMenu { get; set; } + + /// + /// Whether this item can close the menu itself. When it cannot, MudBlazor keeps closing it. + /// + protected virtual bool ControlsMenu => ParentMenu != null || ParentMudMenu != null; + [Parameter] public EventCallback OnClick { get; set; } @@ -43,8 +51,11 @@ public partial class AbpMudActionMenuItem : ComponentBase [Parameter] public string? Class { get; set; } + /// + /// Never null, because MudBlazor reads it without a null check while rendering. + /// [Parameter(CaptureUnmatchedValues = true)] - public Dictionary? UserAttributes { get; set; } + public Dictionary UserAttributes { get; set; } = new(); [Parameter] public RenderFragment? ChildContent { get; set; } @@ -55,6 +66,10 @@ public partial class AbpMudActionMenuItem : ComponentBase { await ParentMenu.CloseAsync(); } + else if (ParentMudMenu != null) + { + await ParentMudMenu.CloseAllMenusAsync(); + } await OnClick.InvokeAsync(args); } diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor index 6b542ef6e5..a718e6fadb 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor @@ -5,7 +5,7 @@ @using Volo.Abp.FeatureManagement.Localization @inherits AbpFeatureManagementComponentBase - + @L["Features"]@ProviderKeyDisplayName @@ -18,10 +18,11 @@ { - @foreach (var group in Groups) - { - - + @{ + @* The features come from the definitions, so there is no known input to put + AutoFocus on. The first panel gets a container that takes the focus instead. *@ + RenderFragment renderGroup = group => + @ @group.DisplayName @foreach (var feature in group.Features) { @@ -68,7 +69,25 @@ } } - + ; + } + @for (var groupIndex = 0; groupIndex < Groups.Count; groupIndex++) + { + var group = Groups[groupIndex]; + @* MudTabs renders the panel content later, when the loop variable is already past + the last index. *@ + var isFirstGroup = groupIndex == 0; + + @if (isFirstGroup) + { +
+ @renderGroup(group) +
+ } + else + { + @renderGroup(group) + }
}
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs index c913b05f3c..f75adfafc4 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using Microsoft.Extensions.Localization; +using Microsoft.JSInterop; using Microsoft.Extensions.Options; using MudBlazor; using Volo.Abp.AspNetCore.Components.Messages; @@ -44,6 +45,14 @@ public partial class FeatureManagementModal protected Dictionary SelectionStringValues = new(); + protected const int MaxFocusRenderCount = 5; + + protected ElementReference _firstGroupContainer; + + protected bool _shouldFocusFirstGroup; + + protected int _focusRenderCount; + public virtual async Task OpenAsync(string providerName, string? providerKey = null, string? providerKeyDisplayName = null) { try @@ -89,6 +98,11 @@ public partial class FeatureManagementModal } _isVisible = true; + // The previous reference points to an element that is gone, and it would be taken for a + // bound container on the next render. + _firstGroupContainer = default; + _shouldFocusFirstGroup = Groups.Any(); + _focusRenderCount = 0; await InvokeAsync(StateHasChanged); } catch (Exception ex) @@ -97,6 +111,49 @@ public partial class FeatureManagementModal } } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + await base.OnAfterRenderAsync(firstRender); + + if (!_shouldFocusFirstGroup) + { + return; + } + + if (!_isVisible) + { + _shouldFocusFirstGroup = false; + return; + } + + // The dialog provider renders the content in a later batch, so the container is not bound yet + // on the render that makes the dialog visible. Rendering again brings this method back. + if (_firstGroupContainer.Id.IsNullOrEmpty()) + { + if (_focusRenderCount++ < MaxFocusRenderCount) + { + await InvokeAsync(StateHasChanged); + } + else + { + _shouldFocusFirstGroup = false; + } + + return; + } + + _shouldFocusFirstGroup = false; + + try + { + await _firstGroupContainer.MudFocusFirstAsync(); + } + catch (JSException) + { + // The dialog was closed before the focus call reached the element. + } + } + public virtual Task CloseModal() { _isVisible = false; From 6a525aacd984a85d90a93783d9599e662bef36d5 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 11 Aug 2026 10:19:00 +0800 Subject: [PATCH 3/3] Shorten the action menu and feature dialog comments --- .../Components/AbpMudActionMenu.razor.cs | 11 ++++------- .../Components/AbpMudActionMenuItem.razor.cs | 5 ++--- .../Components/FeatureManagementModal.razor | 5 ++--- .../Components/FeatureManagementModal.razor.cs | 7 +++---- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs index 7a4b1f3ed3..ff0ff5efc9 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenu.razor.cs @@ -9,8 +9,7 @@ using MudBlazor; namespace Volo.Abp.MudBlazorUI.Components; /// -/// A for entity/row actions that open a dialog. -/// Use it together with . +/// A for actions that open a dialog. Use it with . /// public partial class AbpMudActionMenu : ComponentBase { @@ -35,8 +34,7 @@ public partial class AbpMudActionMenu : ComponentBase public string? Label { get; set; } /// - /// The accessible name of the activator. An activator without a falls back - /// to the localized "Actions" text. + /// The accessible name of an activator that has no . Defaults to "Actions". /// [Parameter] public string? AriaLabel { get; set; } @@ -125,9 +123,8 @@ public partial class AbpMudActionMenu : ComponentBase } /// - /// Closes the whole menu hierarchy. calls this before running - /// its handler, because MudBlazor restores the focus to the activator while closing and that - /// would take the focus out of a dialog the handler opened. + /// Closes the whole menu hierarchy. MudBlazor restores the focus to the activator while closing, + /// so calls this before its handler opens a dialog. /// public virtual async Task CloseAsync() { diff --git a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor.cs b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor.cs index 2d3e230394..48299b84a2 100644 --- a/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor.cs +++ b/framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudActionMenuItem.razor.cs @@ -7,9 +7,8 @@ using MudBlazor; namespace Volo.Abp.MudBlazorUI.Components; /// -/// A menu item that closes its menu before running , so a dialog opened by -/// the handler keeps the focus. Works inside an and inside a plain -/// . +/// A menu item that closes its menu before running , so a dialog opened by the +/// handler keeps the focus. Works in an and in a plain . /// public partial class AbpMudActionMenuItem : ComponentBase { diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor index a718e6fadb..baa5e43fb8 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor @@ -20,7 +20,7 @@ PanelClass="pa-4"> @{ @* The features come from the definitions, so there is no known input to put - AutoFocus on. The first panel gets a container that takes the focus instead. *@ + AutoFocus on. The first panel gets a container that takes the focus. *@ RenderFragment renderGroup = group => @ @group.DisplayName @@ -74,8 +74,7 @@ @for (var groupIndex = 0; groupIndex < Groups.Count; groupIndex++) { var group = Groups[groupIndex]; - @* MudTabs renders the panel content later, when the loop variable is already past - the last index. *@ + @* MudTabs renders the panel content after the loop is over. *@ var isFirstGroup = groupIndex == 0; @if (isFirstGroup) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs index f75adfafc4..2b0c50a103 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Blazor.MudBlazor/Components/FeatureManagementModal.razor.cs @@ -98,8 +98,7 @@ public partial class FeatureManagementModal } _isVisible = true; - // The previous reference points to an element that is gone, and it would be taken for a - // bound container on the next render. + // The previous reference points to an element that is gone by now. _firstGroupContainer = default; _shouldFocusFirstGroup = Groups.Any(); _focusRenderCount = 0; @@ -126,8 +125,8 @@ public partial class FeatureManagementModal return; } - // The dialog provider renders the content in a later batch, so the container is not bound yet - // on the render that makes the dialog visible. Rendering again brings this method back. + // The dialog provider renders the content in a later batch, so rendering again is what brings + // this method back once the container is bound. if (_firstGroupContainer.Id.IsNullOrEmpty()) { if (_focusRenderCount++ < MaxFocusRenderCount)