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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
@namespace Microsoft.Fast.Components.FluentUI
@implements IDisposable
@inherits FluentComponentBase
<div>
<CascadingValue Value="this" IsFixed="true">
<CascadingValue Value="@Expanded" Name="NavMenuExpanded">
<FluentTreeView Class="@ClassValue"
Style="@StyleValue"
OnSelectedChange="HandleSelectedChangeAsync">
OnSelectedChange="@HandleSelectedChange">
@if (Collapsible) {
<FluentTreeItem Id="@_expandCollapseTreeItemId" Class="nav-menu-expander" @onclick="CollapsibleClickAsync">
<FluentTreeItem Id="@_expandCollapseTreeItemId" Class="nav-menu-expander" @onclick="@ToggleCollapsedAsync" @onkeydown="@HandleExpandCollapseKeyDownAsync">
@if (NavigationIconContent is not null) {
@NavigationIconContent
<div>
@NavigationIconContent
</div>
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Fast.Components.FluentUI.Utilities;

namespace Microsoft.Fast.Components.FluentUI;
Expand Down Expand Up @@ -86,41 +87,82 @@ public FluentNavMenu()

internal bool HasIcons => _links.Any(i => i.HasIcon) || _groups.Any(g => g.HasIcon);

internal async Task CollapsibleClickAsync()
private bool Collapsed => !Expanded;

private Task ToggleCollapsedAsync() =>
Expanded
? CollapseAsync()
: ExpandAsync();

/// <summary>
/// Ensures the <see cref="FluentNavMenu"/> is collasped.
/// </summary>
/// <returns></returns>
public async Task CollapseAsync()
{
if (Collapsible)
{
Expanded = !Expanded;
await InvokeAsync(StateHasChanged);
if (Collapsed || !Collapsible)
return;

if (ExpandedChanged.HasDelegate)
{
await ExpandedChanged.InvokeAsync(Expanded);
}
Expanded = false;

if (OnExpanded.HasDelegate)
{
await OnExpanded.InvokeAsync(Expanded);
}
if (ExpandedChanged.HasDelegate)
{
await ExpandedChanged.InvokeAsync(Expanded);
}

StateHasChanged();
}

internal async Task HandleSelectedChangeAsync(FluentTreeItem treeItem)

/// <summary>
/// Ensures the <see cref="FluentNavMenu"/> is expanded.
/// </summary>
/// <returns></returns>
public async Task ExpandAsync()
{
if (treeItem.Id == _expandCollapseTreeItemId)
{
await CollapsibleClickAsync();
if (Expanded)
return;

Expanded = true;

if (ExpandedChanged.HasDelegate)
{
await ExpandedChanged.InvokeAsync(Expanded);
}
string? href = _links.FirstOrDefault(x => x.Id == treeItem.Id)?.Href;
if (string.IsNullOrWhiteSpace(href))

if (OnExpanded.HasDelegate)
{
href = _groups.FirstOrDefault(x => x.Id == treeItem.Id)?.Href;
await OnExpanded.InvokeAsync(Expanded);
}
if (!string.IsNullOrWhiteSpace(href) && href != _prevHref)
StateHasChanged();
}

private async Task HandleExpandCollapseKeyDownAsync(KeyboardEventArgs args)
{
Task handler = args.Code switch
{
"Enter" => ExpandAsync(),
"ArrowRight" => ExpandAsync(),
"ArrowLeft" => CollapseAsync(),
_ => Task.CompletedTask
};
await handler;
}

private void HandleSelectedChange(FluentTreeItem treeItem)
{
if (treeItem.Selected && treeItem.Id != _expandCollapseTreeItemId)
{
_prevHref = href;
NavigationManager.NavigateTo(href);
string? href = _links.FirstOrDefault(x => x.Id == treeItem.Id)?.Href;
if (string.IsNullOrWhiteSpace(href))
{
href = _groups.FirstOrDefault(x => x.Id == treeItem.Id)?.Href;
}
if (!string.IsNullOrWhiteSpace(href) && href != _prevHref)
{
_prevHref = href;
NavigationManager.NavigateTo(href);
}
}
}

Expand All @@ -144,10 +186,15 @@ internal void RemoveNavMenuGroup(FluentNavMenuGroup group)
_groups.Remove(group);
}

public void Dispose()
void IDisposable.Dispose()
{
_links.Clear();
_groups.Clear();
}

internal async Task GroupExpandedAsync(FluentNavMenuGroup group)
{
if (Collapsed)
await ExpandAsync();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

::deep .nav-menu-expander::part(content-region) {
margin-inline-start: calc(var(--design-unit) * 2px);
-webkit-user-select: none;
user-select: none;
}

::deep .nav-menu-expander::part(positioning-region):hover {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
@namespace Microsoft.Fast.Components.FluentUI
@implements IDisposable
@inherits FluentComponentBase
<FluentTreeItem Id="@Id"
Class="@ClassValue"
Style="@StyleValue"
Disabled="@Disabled"
Selected="@Selected"
Expanded="@(NavMenuExpanded ? Expanded : false)"
Text="@(NavMenuExpanded ? Text : string.Empty)">
Text="@(NavMenuExpanded ? Text : string.Empty)"
@onkeydown="@HandleKeyDownAsync"
@onclick="@ToggleCollapsedAsync">
@if (HasIcon)
{
if (IconContent is not null)
{
<div slot="start" @onclick="HandleIconClick">@IconContent</div>
<div slot="start">@IconContent</div>
}
else
{
<FluentIcon Value="@Icon" Width="20px" Slot="start" OnClick="HandleIconClick" />
<FluentIcon Value="@Icon" Width="20px" Slot="start" />
}
}
else if (NavMenu.HasIcons)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Fast.Components.FluentUI.Utilities;


Expand Down Expand Up @@ -81,6 +82,8 @@ public partial class FluentNavMenuGroup : FluentComponentBase, IDisposable
[CascadingParameter(Name = "NavMenuExpanded")]
private bool NavMenuExpanded { get; set; }

private bool Collapsed => !Expanded;

public FluentNavMenuGroup()
{
Id = Identifier.NewId();
Expand All @@ -97,47 +100,73 @@ public FluentNavMenuGroup()

internal bool HasIcon => Icon != null || IconContent is not null;

public override async Task SetParametersAsync(ParameterView parameters)
/// <summary>
/// Ensures the <see cref="FluentNavMenu"/> is collasped.
/// </summary>
/// <returns></returns>
public async Task CollapseAsync()
{
bool originalExpanded = Expanded;
await base.SetParametersAsync(parameters);
if (Expanded != originalExpanded)
if (Collapsed)
return;

Expanded = false;

if (OnExpandedChanged.HasDelegate)
{
await OnExpandedChanged.InvokeAsync(Expanded);
}
}

protected override void OnInitialized()
{
base.OnInitialized();
NavMenu.AddNavMenuGroup(this);
StateHasChanged();
}

private async Task ExpandMenu()
/// <summary>
/// Ensures the <see cref="FluentNavMenu"/> is expanded.
/// </summary>
/// <returns></returns>
public async Task ExpandAsync()
{
if (Disabled)
if (Expanded)
return;

// Expand the Nav Menu and this Group if the user clicks on its NavMenuToggleIcon
if (!NavMenuExpanded)
{
await NavMenu.CollapsibleClickAsync();
Expanded = true;

Expanded = true;
if (OnExpandedChanged.HasDelegate)
{
await OnExpandedChanged.InvokeAsync(Expanded);

Selected = true;
}

await NavMenu.GroupExpandedAsync(this);
StateHasChanged();
}

private async Task HandleKeyDownAsync(KeyboardEventArgs args)
{
Task handler = args.Code switch
{
"Enter" => ExpandAsync(),
"ArrowRight" => ExpandAsync(),
"ArrowLeft" => CollapseAsync(),
_ => Task.CompletedTask
};
await handler;
}

private void HandleIconClick()
protected override void OnInitialized()
{
if (!Disabled)
Selected = true;
base.OnInitialized();
NavMenu.AddNavMenuGroup(this);
}

/// <summary>
/// Dispose of this navmenu group.
/// </summary>
public void Dispose()
void IDisposable.Dispose()
{
NavMenu.RemoveNavMenuGroup(this);
}

private Task ToggleCollapsedAsync() =>
Expanded
? CollapseAsync()
: ExpandAsync();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@namespace Microsoft.Fast.Components.FluentUI
@implements IDisposable
@inherits FluentComponentBase
<FluentTreeItem Id="@Id"
Class="@ClassValue"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ internal void HandleIconClick()
if (!Disabled)
Selected = true;
}

internal void SetSelected(bool value)
{
Selected = value;
Expand All @@ -122,7 +123,7 @@ internal void SetSelected(bool value)
/// <summary>
/// Dispose of this navmenu link.
/// </summary>
public void Dispose()
void IDisposable.Dispose()
{
NavMenu.RemoveNavMenuLink(this);
}
Expand Down