Skip to content

Commit fff4f56

Browse files
committed
Add nav drawer toggle
1 parent 2e491bc commit fff4f56

6 files changed

Lines changed: 192 additions & 9 deletions

File tree

demo/StaticSample/StaticSample.Client/Layout/MainLayout.razor

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@
66

77
<MudLayout>
88
<MudAppBar Elevation="0">
9-
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@((e) => DrawerToggle())" />
9+
<MudStaticNavDrawerToggle Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" />
10+
<MudText Typo="Typo.h6" Style="white-space:nowrap;">Static Input</MudText>
1011
<MudSpacer />
1112
<RenderStateViewer Parent="this" Class="px-4" />
1213
<MudIconButton Icon="@Icons.Custom.Brands.MudBlazor" Color="Color.Inherit" Href="https://mudblazor.com/" Target="_blank" />
1314
<MudIconButton Icon="@Icons.Custom.Brands.GitHub" Color="Color.Inherit" Href="https://github.com/0phois/MudBlazor.StaticInput" Target="_blank" />
1415
</MudAppBar>
1516

16-
<MudDrawer @bind-Open="_drawerOpen" Elevation="1">
17-
<MudDrawerHeader>
18-
<MudText Typo="Typo.h6">Static Input</MudText>
19-
</MudDrawerHeader>
17+
<MudDrawer @bind-Open="_drawerOpen" Elevation="1" Variant="@DrawerVariant.Responsive" Breakpoint="@Breakpoint.Md" ClipMode="DrawerClipMode.Always">
2018
<NavMenu />
2119
</MudDrawer>
2220

demo/StaticSample/StaticSample.Client/StaticSample.Client.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,8 @@
1515
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.10" />
1616
</ItemGroup>
1717

18+
<ItemGroup>
19+
<ProjectReference Include="..\..\..\src\MudBlazor.StaticInput.csproj" />
20+
</ItemGroup>
21+
1822
</Project>

demo/StaticSample/StaticSample.Client/_Imports.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010
@using StaticSample.Client
1111
@using MudBlazor
1212
@using MudBlazor.Services
13+
@using MudBlazor.StaticInput
1314
@using Blazr.RenderState
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
@using Microsoft.JSInterop
2+
3+
@namespace MudBlazor.StaticInput
4+
5+
@inherits MudIconButton
6+
@inject IJSRuntime JsRuntime
7+
8+
@{
9+
base.BuildRenderTree(__builder);
10+
}
11+
12+
@code {
13+
/// <summary>
14+
/// The id of the <see cref="MudDrawer"/> to toggle
15+
/// </summary>
16+
/// <remarks>
17+
/// If not provided, the first mud-drawer element located within the DOM is used.
18+
/// </remarks>
19+
[Parameter]
20+
public string? DrawerId { get; set; } = "_no_id_provided_";
21+
22+
private string _elementId = string.Empty;
23+
24+
protected override void OnParametersSet()
25+
{
26+
UserAttributes["data-mud-drawer-toggle"] = DrawerId;
27+
UserAttributes["data-static-component"] = true;
28+
UserAttributes["data-static-id"] = _elementId;
29+
30+
base.OnClick = EventCallback.Factory.Create<MouseEventArgs>(this, async () => await JsRuntime.InvokeVoidAsync("MudDrawerInterop.toggleDrawer", DrawerId));
31+
32+
base.OnParametersSet();
33+
}
34+
35+
protected override void OnInitialized()
36+
{
37+
_elementId = Guid.NewGuid().ToString()[..8];
38+
39+
base.OnInitialized();
40+
}
41+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Microsoft.AspNetCore.Components.Web;
2+
using Microsoft.AspNetCore.Components;
3+
4+
namespace MudBlazor.StaticInput;
5+
6+
/// <summary>
7+
/// A <see cref="MudIconButton"/> used to toggle the state of the navigation <see cref="MudDrawer"/>
8+
/// </summary>
9+
/// <remarks>
10+
/// <list type="bullet">
11+
/// <item>
12+
/// <see cref="DrawerClipMode"/> should be set to <see cref="DrawerClipMode.Always"/>
13+
/// </item>
14+
/// <item>
15+
/// <see cref="DrawerVariant.Temporary"/> is not currently supported since the required <see cref="MudOverlay"/> is not implemented
16+
/// </item>
17+
/// </list>
18+
/// </remarks>
19+
public partial class MudStaticNavDrawerToggle : MudIconButton
20+
21+
{
22+
protected new EventCallback<MouseEventArgs> OnClick { get; set; }
23+
protected new ButtonType ButtonType { get; set; }
24+
protected new string HtmlTag { get; set; } = "button";
25+
protected new string? Href { get; set; }
26+
protected new string? Target { get; set; }
27+
protected new bool ClickPropagation { get; set; }
28+
}

src/wwwroot/NavigationObserver.js

Lines changed: 115 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,128 @@ let hasInitialized = false;
2828
}
2929
});
3030
});
31-
observer.observe(document.body, {
32-
childList: true,
33-
subtree: true
34-
});
31+
observer.observe(document.body, { childList: true, subtree: true });
32+
3533
initializeScripts();
3634
}
3735
};
3836

37+
window.MudDrawerInterop = {
38+
initialize: function () {
39+
const drawerToggleElements = document.querySelectorAll('[data-mud-drawer-toggle]');
40+
41+
drawerToggleElements.forEach(element => {
42+
element.removeEventListener('click', this.handleToggleDrawer);
43+
element.addEventListener('click', this.handleToggleDrawer);
44+
});
45+
46+
const responsiveDrawer = document.querySelectorAll('.mud-drawer-responsive')[0];
47+
48+
if (responsiveDrawer) {
49+
MudDrawerInterop.monitorResize(responsiveDrawer);
50+
}
51+
},
52+
53+
monitorResize(responsiveDrawer) {
54+
const classSections = Array.from(responsiveDrawer.parentElement.classList).find(className => className.includes('responsive')).split('-');
55+
const breakpoint = classSections[classSections.length - 2];
56+
const position = classSections[classSections.length - 1];
57+
const breakpointValue = MudDrawerInterop.getBreakpointValue(breakpoint);
58+
const resizeQuery = window.matchMedia(`(min-width: ${breakpointValue}px)`);
59+
60+
if (responsiveDrawer.parentElement.offsetWidth <= breakpointValue) {
61+
MudDrawerInterop.autoCollapse(responsiveDrawer, breakpoint, position);
62+
} else {
63+
MudDrawerInterop.autoExpand(responsiveDrawer, breakpoint, position);
64+
}
65+
66+
resizeQuery.addEventListener('change', ev => {
67+
if (ev.matches) {
68+
MudDrawerInterop.autoExpand(responsiveDrawer, breakpoint, position);
69+
}
70+
else {
71+
MudDrawerInterop.autoCollapse(responsiveDrawer, breakpoint, position);
72+
}
73+
})
74+
},
75+
76+
getBreakpointValue(breakpoint) {
77+
switch (breakpoint) {
78+
case 'xs': return 380;
79+
case 'sm': return 600;
80+
case 'md': return 960;
81+
case 'lg': return 1280;
82+
case 'xl': return 1920;
83+
}
84+
},
85+
86+
autoCollapse(responsiveDrawer, breakpoint, position) {
87+
responsiveDrawer.classList.add('mud-drawer--closed');
88+
responsiveDrawer.classList.remove('mud-drawer--open');
89+
responsiveDrawer.parentElement.classList.add(`mud-drawer-closed-responsive-${breakpoint}-${position}`)
90+
responsiveDrawer.parentElement.classList.remove(`mud-drawer-open-responsive-${breakpoint}-${position}`)
91+
},
92+
93+
autoExpand(responsiveDrawer, breakpoint, position) {
94+
responsiveDrawer.classList.add('mud-drawer--open');
95+
responsiveDrawer.classList.remove('mud-drawer--closed');
96+
responsiveDrawer.parentElement.classList.add(`mud-drawer-open-responsive-${breakpoint}-${position}`)
97+
responsiveDrawer.parentElement.classList.remove(`mud-drawer-closed-responsive-${breakpoint}-${position}`)
98+
},
99+
100+
handleToggleDrawer: function (event) {
101+
const element = event.currentTarget;
102+
const targetDrawerId = element.getAttribute('data-mud-drawer-toggle');
103+
104+
MudDrawerInterop.toggleDrawer(targetDrawerId);
105+
},
106+
107+
toggleDrawer: function (drawerId) {
108+
let mudDrawer;
109+
110+
if (drawerId === '_no_id_provided_') {
111+
mudDrawer = document.querySelectorAll('.mud-drawer')[0];
112+
} else {
113+
mudDrawer = document.getElementById(drawerId);
114+
}
115+
116+
if (mudDrawer) {
117+
mudDrawer.classList.toggle('mud-drawer--open');
118+
mudDrawer.classList.toggle('mud-drawer--closed');
119+
mudDrawer.classList.remove('mud-drawer--initial');
120+
}
121+
122+
const header = document.querySelector('.mud-drawer-header');
123+
124+
if (header) {
125+
if (mudDrawer.className.includes('mud-drawer--closed') === true) {
126+
header.classList.add('mud-typography-nowrap');
127+
}
128+
else {
129+
header.classList.remove('mud-typography-nowrap');
130+
}
131+
}
132+
133+
const layout = mudDrawer.parentElement;
134+
135+
if (layout) {
136+
if (layout.className.includes('mud-drawer-open') === true) {
137+
layout.className = layout.className.replace(/\bmud-drawer-open\b/g, 'mud-drawer-closed');
138+
} else {
139+
layout.className = layout.className.replace(/\bmud-drawer-closed\b/g, 'mud-drawer-open');
140+
141+
if (mudDrawer.className.includes('mud-static-responsive')) {
142+
mudDrawer.classList.add('mud-drawer-clipped-always');
143+
}
144+
}
145+
}
146+
},
147+
};
148+
39149
function ensureInitialized() {
40150
if (window.MutationObserverModule && !hasInitialized) {
41151
window.MutationObserverModule.initialize();
152+
window.MudDrawerInterop.initialize();
42153
}
43154
}
44155

0 commit comments

Comments
 (0)