using Microsoft.AspNetCore.Components; using System; using System.Collections.Generic; using System.Linq; namespace AntBlazor { public partial class Menu : AntDomComponentBase { [CascadingParameter(Name = "PrefixCls")] public string PrefixCls { get; set; } = "ant-menu"; [CascadingParameter] public AntSider Parent { get; set; } [Parameter] public MenuTheme Theme { get; set; } = MenuTheme.Light; [Parameter] public MenuMode Mode { get; set; } = MenuMode.Vertical; [Parameter] public RenderFragment ChildContent { get; set; } [Parameter] public EventCallback OnSubmenuClicked { get; set; } [Parameter] public EventCallback OnMenuItemClicked { get; set; } [Parameter] public bool Accordion { get; set; } [Parameter] public bool Selectable { get; set; } = true; [Parameter] public bool InlineCollapsed { get; set; } [Parameter] public IEnumerable DefaultSelectedKeys { get; set; } = new List(); [Parameter] public IEnumerable DefaultOpenKeys { get; set; } = new List(); [Parameter] public string[] OpenKeys { get => _openKeys ?? Array.Empty(); set { _openKeys = value; HandleOpenKeySet(); } } [Parameter] public EventCallback OpenKeysChanged { get; set; } [Parameter] public EventCallback OnOpenChange { get; set; } [Parameter] public string[] SelectedKeys { get => _selectedKeys ?? Array.Empty(); set { _selectedKeys = value; } } [Parameter] public EventCallback SelectedKeysChanged { get; set; } internal MenuMode InternalMode { get; private set; } private bool _collapsed; private string[] _openKeys; private string[] _selectedKeys; public List Submenus { get; set; } = new List(); public List MenuItems { get; set; } = new List(); public void SelectItem(MenuItem item) { if (item == null) { return; } foreach (MenuItem menuitem in MenuItems.Where(x => x != item)) { menuitem.Deselect(); } if (!item.IsSelected) { item.Select(); } else { item.Deselect(); } StateHasChanged(); if (OnMenuItemClicked.HasDelegate) OnMenuItemClicked.InvokeAsync(item); _selectedKeys = MenuItems.Where(x => x.IsSelected).Select(x => x.Key).ToArray(); if (SelectedKeysChanged.HasDelegate) SelectedKeysChanged.InvokeAsync(_selectedKeys); } public void SelectSubmenu(SubMenu menu) { if (menu == null) { return; } if (Accordion) { foreach (SubMenu item in Submenus.Where(x => x != menu && x != menu.Parent)) { item.Close(); } } if (menu.IsOpen) { menu.Close(); } else { menu.Open(); } if (OnSubmenuClicked.HasDelegate) OnSubmenuClicked.InvokeAsync(menu); var openKeys = Submenus.Where(x => x.IsOpen).Select(x => x.Key).ToArray(); HandleOpenChange(openKeys); StateHasChanged(); } private void SetClass() { ClassMapper .Clear() .Add(PrefixCls) .Add($"{PrefixCls}-root") .Add($"{PrefixCls}-{Theme}") .Add($"{PrefixCls}-{InternalMode}") .If($"{PrefixCls}-inline-collapsed", () => _collapsed) .If($"{PrefixCls}-unselectable", () => !Selectable); } protected override void OnInitialized() { base.OnInitialized(); if (InternalMode != MenuMode.Inline && _collapsed) throw new ArgumentException($"{nameof(Menu)} in the {Mode} mode cannot be {nameof(InlineCollapsed)}"); InternalMode = Mode; if (Parent != null) { Parent.OnCollapsed += Update; } SetClass(); } protected override void OnParametersSet() { base.OnParametersSet(); if (Parent == null) { this._collapsed = InlineCollapsed; } Update(_collapsed); SetClass(); } public void Update(bool collapsed) { this._collapsed = collapsed; if (collapsed) { InternalMode = MenuMode.Vertical; foreach (SubMenu item in Submenus) { item.Close(); } HandleOpenChange(Array.Empty()); } else { InternalMode = Mode; } } private void HandleOpenChange(string[] openKeys) { this._openKeys = openKeys; if (OnOpenChange.HasDelegate) OnOpenChange.InvokeAsync(openKeys); if (OpenKeysChanged.HasDelegate) OpenKeysChanged.InvokeAsync(openKeys); } private void HandleOpenKeySet() { foreach (SubMenu item in Submenus.Where(x => x.Key.IsIn(this.OpenKeys))) { item.Open(); } foreach (SubMenu item in Submenus.Where(x => !x.Key.IsIn(this.OpenKeys))) { item.Close(); } StateHasChanged(); } protected override void Dispose(bool disposing) { if (Parent != null) { Parent.OnCollapsed -= Update; } base.Dispose(disposing); } } }