You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Components/Components/Menu/Menu.razor.cs

336 lines
8.7 KiB

using System.Diagnostics.CodeAnalysis;
using System.Windows.Input;
using Connected.Annotations;
using Connected.Utilities;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
namespace Connected.Components;
public partial class Menu : UIComponent, IActivatable
{
protected string Classname =>
new CssBuilder("mud-menu")
.AddClass(Class)
.Build();
protected string ActivatorClassname =>
new CssBuilder("mud-menu-activator")
.AddClass("mud-disabled", Disabled)
.Build();
private bool _isOpen;
private bool _isMouseOver = false;
[Parameter]
[Category(CategoryTypes.Menu.Behavior)]
public string Label { get; set; }
/// <summary>
/// User class names for the list, separated by space
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupAppearance)]
public string ListClass { get; set; }
/// <summary>
/// User class names for the popover, separated by space
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupAppearance)]
public string PopoverClass { get; set; }
/// <summary>
/// Icon to use if set will turn the button into a MudIconButton.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Behavior)]
public string Icon { get; set; }
/// <summary>
/// The color of the icon. It supports the theme colors.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Appearance)]
public ThemeColor IconColor { get; set; } = ThemeColor.Inherit;
/// <summary>
/// Icon placed before the text if set.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Behavior)]
public string StartIcon { get; set; }
/// <summary>
/// Icon placed after the text if set.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Behavior)]
public string EndIcon { get; set; }
/// <summary>
/// The color of the button. It supports the theme colors.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Appearance)]
public ThemeColor Color { get; set; } = ThemeColor.Default;
/// <summary>
/// The button Size of the component.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Appearance)]
public Size Size { get; set; } = Size.Medium;
/// <summary>
/// The button variant to use.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Appearance)]
public Variant Variant { get; set; } = Variant.Text;
/// <summary>
/// If true, compact vertical padding will be applied to all menu items.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupAppearance)]
public bool Dense { get; set; }
/// <summary>
/// If true, the list menu will be same width as the parent.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupAppearance)]
public bool FullWidth { get; set; }
/// <summary>
/// Sets the maxheight the menu can have when open.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupAppearance)]
public int? MaxHeight { get; set; }
/// <summary>
/// If true, instead of positioning the menu at the left upper corner, position at the exact cursor location.
/// This makes sense for larger activators
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupBehavior)]
public bool PositionAtCursor { get; set; }
/// <summary>
/// If true, instead of positioning the menu at the left upper corner, position at the exact cursor location.
/// This makes sense for larger activators
/// </summary>
[Obsolete("Use PositionAtCursor instead.", true)]
[Parameter]
public bool PositionAtCurser
{
get => PositionAtCursor;
set => PositionAtCursor = value;
}
/// <summary>
/// Place a MudButton, a MudIconButton or any other component capable of acting as an activator. This will
/// override the standard button and all parameters which concern it.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Behavior)]
public RenderFragment ActivatorContent { get; set; }
/// <summary>
/// Specify the activation event when ActivatorContent is set
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Behavior)]
public MouseEvent ActivationEvent { get; set; } = MouseEvent.LeftClick;
/// <summary>
/// Set the anchor origin point to determen where the popover will open from.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupAppearance)]
public Origin AnchorOrigin { get; set; } = Origin.TopLeft;
/// <summary>
/// Sets the transform origin point for the popover.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupAppearance)]
public Origin TransformOrigin { get; set; } = Origin.TopLeft;
/// <summary>
/// Sets the direction the select menu will start from relative to its parent.
/// </summary>
[ExcludeFromCodeCoverage]
[Obsolete("Use AnchorOrigin or TransformOrigin instead.", true)]
[Parameter] public Direction Direction { get; set; } = Direction.Bottom;
/// <summary>
/// If true, the select menu will open either before or after the input depending on the direction.
/// </summary>
[ExcludeFromCodeCoverage]
[Obsolete("Use AnchorOrigin or TransformOrigin instead.", true)]
[Parameter] public bool OffsetY { get; set; }
/// <summary>
/// If true, the select menu will open either above or bellow the input depending on the direction.
/// </summary>
[ExcludeFromCodeCoverage]
[Obsolete("Use AnchorOrigin or TransformOrigin instead.", true)]
[Parameter] public bool OffsetX { get; set; }
/// <summary>
/// Set to true if you want to prevent page from scrolling when the menu is open
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupAppearance)]
public bool LockScroll { get; set; }
/// <summary>
/// If true, menu will be disabled.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Behavior)]
public bool Disabled { get; set; }
/// <summary>
/// If true, disables ripple effect.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Appearance)]
public bool DisableRipple { get; set; }
/// <summary>
/// If true, no drop-shadow will be used.
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.Appearance)]
public bool DisableElevation { get; set; }
#region Obsolete members from previous MudButtonBase inherited structure
[ExcludeFromCodeCoverage]
[Obsolete("Linking is not supported. MudMenu is not a MudBaseButton anymore.", true)]
[Parameter] public string Link { get; set; }
[ExcludeFromCodeCoverage]
[Obsolete("Linking is not supported. MudMenu is not a MudBaseButton anymore.", true)]
[Parameter] public string Target { get; set; }
[ExcludeFromCodeCoverage]
[Obsolete("MudMenu is not a MudBaseButton anymore.", true)]
[Parameter] public string HtmlTag { get; set; } = "button";
[ExcludeFromCodeCoverage]
[Obsolete("MudMenu is not a MudBaseButton anymore.", true)]
[Parameter] public ButtonType ButtonType { get; set; }
[ExcludeFromCodeCoverage]
[Obsolete("MudMenu is not a MudBaseButton anymore.", true)]
[Parameter] public ICommand Command { get; set; }
[ExcludeFromCodeCoverage]
[Obsolete("MudMenu is not a MudBaseButton anymore.", true)]
[Parameter] public object CommandParameter { get; set; }
#endregion
/// <summary>
/// Add menu items here
/// </summary>
[Parameter]
[Category(CategoryTypes.Menu.PopupBehavior)]
public RenderFragment ChildContent { get; set; }
public string PopoverStyle { get; set; }
public void CloseMenu()
{
_isOpen = false;
_isMouseOver = false;
PopoverStyle = null;
StateHasChanged();
}
public void OpenMenu(EventArgs args)
{
if (Disabled)
return;
if (PositionAtCursor) SetPopoverStyle((MouseEventArgs)args);
_isOpen = true;
StateHasChanged();
}
// Sets the popover style ONLY when there is an activator
private void SetPopoverStyle(MouseEventArgs args)
{
AnchorOrigin = Origin.TopLeft;
PopoverStyle = $"margin-top: {args?.OffsetY.ToPx()}; margin-left: {args?.OffsetX.ToPx()};";
}
public void ToggleMenu(MouseEventArgs args)
{
if (Disabled)
return;
if (ActivationEvent == MouseEvent.LeftClick && args.Button != 0 && !_isOpen)
return;
if (ActivationEvent == MouseEvent.RightClick && args.Button != 2 && !_isOpen)
return;
if (_isOpen)
CloseMenu();
else
OpenMenu(args);
}
public void ToggleMenuTouch(TouchEventArgs args)
{
if (Disabled)
{
return;
}
if (_isOpen)
{
CloseMenu();
}
else
{
OpenMenu(args);
}
}
/// <summary>
/// Implementation of IActivatable.Activate, toggles the menu.
/// </summary>
/// <param name="activator"></param>
/// <param name="args"></param>
public void Activate(object activator, MouseEventArgs args)
{
ToggleMenu(args);
}
public void MouseEnter(MouseEventArgs args)
{
_isMouseOver = true;
if (ActivationEvent == MouseEvent.MouseOver)
{
OpenMenu(args);
}
}
public async void MouseLeave()
{
_isMouseOver = false;
await Task.Delay(100);
if (ActivationEvent == MouseEvent.MouseOver && _isMouseOver == false)
{
CloseMenu();
}
}
}