fix(nav): per-parent dropdown collapsed state; reset on focusout

HashSet<string> _collapsedDropdowns replaces single bool so each parent
tracks its own dismiss state independently. onfocusout added alongside
onmouseleave so keyboard users get the dropdown re-enabled without a
mouse pass after Enter-activating a child link.
This commit is contained in:
daniel-c-harvey
2026-06-13 20:00:20 -04:00
parent c44117ccc5
commit 86999cb94e
@@ -17,15 +17,16 @@
dd-nav-item-collapsed is added on child click to force-hide the
dropdown after SPA navigation (which keeps the DOM and may leave
:hover true). It is cleared on mouseleave so the next hover works. *@
<li class="dd-nav-item-parent @(_dropdownCollapsed ? "dd-nav-item-collapsed" : "")"
@onmouseleave="ResetDropdown">
<li class="dd-nav-item-parent @(_collapsedDropdowns.Contains(navPage.Route) ? "dd-nav-item-collapsed" : "")"
@onmouseleave="() => ResetDropdown(navPage.Route)"
@onfocusout="() => ResetDropdown(navPage.Route)">
<a href="@navPage.Route" class="dd-nav-link">@navPage.Name</a>
<ul class="dd-nav-dropdown">
@foreach (var child in navPage.Children)
{
<li>
<a href="@child.Route" class="dd-nav-link dd-nav-dropdown-link"
@onclick="CollapseDropdown">@child.Name</a>
@onclick="() => CollapseDropdown(navPage.Route)">@child.Name</a>
</li>
}
</ul>
@@ -95,7 +96,7 @@
[Parameter] public required EventCallback<bool> IsDarkModeChanged { get; set; }
private bool _mobileMenuOpen;
private bool _dropdownCollapsed;
private readonly HashSet<string> _collapsedDropdowns = [];
protected override async Task OnAfterRenderAsync(bool firstRender)
{
@@ -129,7 +130,7 @@
private void CloseMobileMenu() => _mobileMenuOpen = false;
private void CollapseDropdown() => _dropdownCollapsed = true;
private void CollapseDropdown(string route) => _collapsedDropdowns.Add(route);
private void ResetDropdown() => _dropdownCollapsed = false;
private void ResetDropdown(string route) => _collapsedDropdowns.Remove(route);
}