Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@using MudBlazor

<MudMenu @ref="_menu"
Icon="@Icon"
IconColor="@IconColor"
StartIcon="@StartIcon"
EndIcon="@EndIcon"
Label="@Label"
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">
<ChildContent>
<CascadingValue TValue="AbpMudActionMenu" Value="@this" IsFixed="true">
@ChildContent
</CascadingValue>
</ChildContent>
</MudMenu>
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
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;

/// <summary>
/// A <see cref="MudMenu"/> for actions that open a dialog. Use it with <see cref="AbpMudActionMenuItem"/>.
/// </summary>
public partial class AbpMudActionMenu : ComponentBase
{
protected MudMenu? _menu;

[Inject]
protected IStringLocalizer<AbpUiResource> UiLocalizer { get; set; } = default!;

[Parameter]
public string? Icon { get; set; }

[Parameter]
public Color IconColor { get; set; } = Color.Inherit;

[Parameter]
public string? StartIcon { get; set; }

[Parameter]
public string? EndIcon { get; set; }

[Parameter]
public string? Label { get; set; }

/// <summary>
/// The accessible name of an activator that has no <see cref="Label"/>. Defaults to "Actions".
/// </summary>
[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 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; }

[Parameter]
public string? Class { get; set; }

[Parameter]
public string? Style { get; set; }

[Parameter]
public string? ListClass { get; set; }

[Parameter]
public string? PopoverClass { get; set; }

/// <summary>
/// Never null, because MudBlazor reads it without a null check while rendering.
/// </summary>
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object?> UserAttributes { get; set; } = new();

[Parameter]
public RenderFragment<MenuContext>? 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;
}

/// <summary>
/// Closes the whole menu hierarchy. MudBlazor restores the focus to the activator while closing,
/// so <see cref="AbpMudActionMenuItem"/> calls this before its handler opens a dialog.
/// </summary>
public virtual async Task CloseAsync()
{
if (_menu != null)
{
await _menu.CloseAllMenusAsync();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@using MudBlazor

<MudMenuItem AutoClose="@(!ControlsMenu)"
OnClick="@OnClickHandlerAsync"
Disabled="@Disabled"
Icon="@Icon"
IconColor="@IconColor"
Label="@Label"
Href="@Href"
Target="@Target"
ForceLoad="@ForceLoad"
Class="@Class"
UserAttributes="@UserAttributes">
@ChildContent
</MudMenuItem>
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using MudBlazor;

namespace Volo.Abp.MudBlazorUI.Components;

/// <summary>
/// A menu item that closes its menu before running <see cref="OnClick"/>, so a dialog opened by the
/// handler keeps the focus. Works in an <see cref="AbpMudActionMenu"/> and in a plain <see cref="MudMenu"/>.
/// </summary>
public partial class AbpMudActionMenuItem : ComponentBase
{
[CascadingParameter]
protected AbpMudActionMenu? ParentMenu { get; set; }

[CascadingParameter]
protected MudMenu? ParentMudMenu { get; set; }

/// <summary>
/// Whether this item can close the menu itself. When it cannot, MudBlazor keeps closing it.
/// </summary>
protected virtual bool ControlsMenu => ParentMenu != null || ParentMudMenu != null;

[Parameter]
public EventCallback<MouseEventArgs> 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; }

/// <summary>
/// Never null, because MudBlazor reads it without a null check while rendering.
/// </summary>
[Parameter(CaptureUnmatchedValues = true)]
public Dictionary<string, object?> UserAttributes { get; set; } = new();

[Parameter]
public RenderFragment? ChildContent { get; set; }

protected virtual async Task OnClickHandlerAsync(MouseEventArgs args)
{
if (ParentMenu != null)
{
await ParentMenu.CloseAsync();
}
else if (ParentMudMenu != null)
{
await ParentMudMenu.CloseAllMenusAsync();
}

await OnClick.InvokeAsync(args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
{
if (Primary == false)
{
<MudMenuItem OnClick="@ActionClickedAsync" Disabled="@Disabled">
<AbpMudActionMenuItem OnClick="@ActionClickedAsync" Disabled="@Disabled">
@if (!string.IsNullOrEmpty(Icon))
{
<MudIcon Icon="@Icon" Class="me-2" Size="Size.Small" />
}
@Text
</MudMenuItem>
</AbpMudActionMenuItem>
}
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

@if (Type == MudActionType.Dropdown || DisabledOrNoActions())
{
<MudMenu Icon="@Icons.Material.Filled.MoreVert"
AnchorOrigin="Origin.BottomRight"
TransformOrigin="Origin.TopRight"
Dense="true"
Disabled="@DisabledOrNoActions()">
<AbpMudActionMenu Icon="@Icons.Material.Filled.MoreVert"
AriaLabel="@ToggleText"
AnchorOrigin="Origin.BottomRight"
TransformOrigin="Origin.TopRight"
Dense="true"
Disabled="@DisabledOrNoActions()">
<CascadingValue TValue="IMudEntityActions" Value="@this" Name="ParentActions">
@ChildContent
</CascadingValue>
</MudMenu>
</AbpMudActionMenu>
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
{
<MudTabs KeepPanelsAlive="true" @bind-ActivePanelIndex="@_activeTabIndex" Variant="Variant.Pills" Position="Position.Left"
PanelClass="pa-4">
@foreach (var group in Groups)
{
<MudTabPanel Text="@group.DisplayName">
<MudStack Spacing="2">
@{
@* 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. *@
RenderFragment<FeatureGroupDto> renderGroup = group =>
@<MudStack Spacing="2">
<MudText Typo="Typo.h6">@group.DisplayName</MudText>
@foreach (var feature in group.Features)
{
Expand Down Expand Up @@ -68,7 +69,24 @@
}
</div>
}
</MudStack>
</MudStack>;
}
@for (var groupIndex = 0; groupIndex < Groups.Count; groupIndex++)
{
var group = Groups[groupIndex];
@* MudTabs renders the panel content after the loop is over. *@
var isFirstGroup = groupIndex == 0;
<MudTabPanel Text="@group.DisplayName">
@if (isFirstGroup)
{
<div @ref="_firstGroupContainer" tabindex="-1" class="mud-width-full">
@renderGroup(group)
</div>
}
else
{
@renderGroup(group)
}
</MudTabPanel>
}
</MudTabs>
Expand Down
Loading
Loading