Skip to content

Commit fca3391

Browse files
csharpfritzCopilot
andcommitted
feat: Implement Menu level styles (StaticMenuStyle, IMenuStyleContainer, RenderFragment params) (FritzAndFriends#360)
- Add StaticMenuStyle sub-component class to MenuItemStyle.razor.cs - Create IMenuStyleContainer interface in Interfaces/ - Menu implements IMenuStyleContainer with all 4 style properties - Add RenderFragment parameters: DynamicMenuStyleContent, StaticMenuStyleContent, DynamicMenuItemStyleContent, StaticMenuItemStyleContent - Apply StaticMenuStyle CSS to ul.level1 in Menu.razor - Add IsFixed=true to CascadingValue for ParentMenu - Add 8 bUnit tests covering StaticMenuStyle, RenderFragment params, interface implementation, and defaults Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b0b3dcc commit fca3391

5 files changed

Lines changed: 295 additions & 2 deletions

File tree

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
@using static BlazorWebFormsComponents.WebColor
2+
@using static BlazorWebFormsComponents.Enums.BorderStyle
3+
@using System.Text.RegularExpressions
4+
5+
@code {
6+
7+
[Fact]
8+
public void Menu_StaticMenuStyle_AppliesStyles()
9+
{
10+
JSInterop.Mode = JSRuntimeMode.Loose;
11+
12+
var cut = Render(
13+
@<Menu ID="TestMenu">
14+
<ChildContent>
15+
<StaticMenuStyle BackColor="LightGreen"
16+
ForeColor="Black"
17+
BorderStyle="Solid"
18+
BorderWidth="1"
19+
BorderColor="DarkGreen" />
20+
21+
<Items>
22+
<MenuItem Text="Home" Value="home" />
23+
<MenuItem Text="About" Value="about" />
24+
</Items>
25+
</ChildContent>
26+
</Menu>
27+
);
28+
29+
var theMarkup = cut.Markup;
30+
31+
theMarkup.ShouldContain("#TestMenu ul.level1");
32+
33+
// Verify the style content
34+
var reTest = new Regex(@"ul\.level1\s*\{([^}]+)\}");
35+
reTest.Match(theMarkup).Captures.Count.ShouldBe(1);
36+
var theStyleRules = reTest.Match(theMarkup).Groups[1].Value;
37+
38+
// Assert the style rules were applied
39+
theStyleRules.ShouldContain("background-color:");
40+
theStyleRules.ShouldContain("color:");
41+
theStyleRules.ShouldContain("border:");
42+
}
43+
44+
[Fact]
45+
public void Menu_StaticMenuStyle_ViaRenderFragment_AppliesStyles()
46+
{
47+
JSInterop.Mode = JSRuntimeMode.Loose;
48+
49+
var cut = Render(
50+
@<Menu ID="TestMenu2">
51+
<StaticMenuStyleContent>
52+
<StaticMenuStyle BackColor="Yellow"
53+
ForeColor="Navy" />
54+
</StaticMenuStyleContent>
55+
<ChildContent>
56+
<Items>
57+
<MenuItem Text="Home" Value="home" />
58+
</Items>
59+
</ChildContent>
60+
</Menu>
61+
);
62+
63+
var theMarkup = cut.Markup;
64+
65+
var reTest = new Regex(@"ul\.level1\s*\{([^}]+)\}");
66+
reTest.Match(theMarkup).Captures.Count.ShouldBe(1);
67+
var theStyleRules = reTest.Match(theMarkup).Groups[1].Value;
68+
69+
theStyleRules.ShouldContain("background-color:");
70+
theStyleRules.ShouldContain("color:");
71+
}
72+
73+
[Fact]
74+
public void Menu_DynamicMenuStyle_ViaRenderFragment_AppliesStyles()
75+
{
76+
JSInterop.Mode = JSRuntimeMode.Loose;
77+
78+
var cut = Render(
79+
@<Menu ID="TestMenu3">
80+
<DynamicMenuStyleContent>
81+
<DynamicMenuStyle BackColor="LightSkyBlue"
82+
ForeColor="Black" />
83+
</DynamicMenuStyleContent>
84+
<ChildContent>
85+
<Items>
86+
<MenuItem Text="Home" Value="home" />
87+
</Items>
88+
</ChildContent>
89+
</Menu>
90+
);
91+
92+
var theMarkup = cut.Markup;
93+
94+
var reTest = new Regex(@"ul\.dynamic\s*\{([^}]+)\}");
95+
reTest.Match(theMarkup).Captures.Count.ShouldBe(1);
96+
var theStyleRules = reTest.Match(theMarkup).Groups[1].Value;
97+
98+
theStyleRules.ShouldContain("background-color:");
99+
theStyleRules.ShouldContain("color:");
100+
}
101+
102+
[Fact]
103+
public void Menu_StaticMenuItemStyle_ViaRenderFragment_AppliesStyles()
104+
{
105+
JSInterop.Mode = JSRuntimeMode.Loose;
106+
107+
var cut = Render(
108+
@<Menu ID="TestMenu4">
109+
<StaticMenuItemStyleContent>
110+
<StaticMenuItemStyle BackColor="Wheat"
111+
ForeColor="Brown" />
112+
</StaticMenuItemStyleContent>
113+
<ChildContent>
114+
<Items>
115+
<MenuItem Text="Home" Value="home" />
116+
</Items>
117+
</ChildContent>
118+
</Menu>
119+
);
120+
121+
var theMarkup = cut.Markup;
122+
123+
var reTest = new Regex(@"a\.static\s*\{([^}]+)\}");
124+
reTest.Match(theMarkup).Captures.Count.ShouldBe(1);
125+
var theStyleRules = reTest.Match(theMarkup).Groups[1].Value;
126+
127+
theStyleRules.ShouldContain("background-color:");
128+
theStyleRules.ShouldContain("color:");
129+
}
130+
131+
[Fact]
132+
public void Menu_DynamicMenuItemStyle_ViaRenderFragment_AppliesStyles()
133+
{
134+
JSInterop.Mode = JSRuntimeMode.Loose;
135+
136+
var cut = Render(
137+
@<Menu ID="TestMenu5">
138+
<DynamicMenuItemStyleContent>
139+
<DynamicMenuItemStyle BackColor="Coral"
140+
ForeColor="White" />
141+
</DynamicMenuItemStyleContent>
142+
<ChildContent>
143+
<Items>
144+
<MenuItem Text="Home" Value="home" />
145+
</Items>
146+
</ChildContent>
147+
</Menu>
148+
);
149+
150+
var theMarkup = cut.Markup;
151+
152+
var reTest = new Regex(@"a\.dynamic\s*\{([^}]+)\}");
153+
reTest.Match(theMarkup).Captures.Count.ShouldBe(1);
154+
var theStyleRules = reTest.Match(theMarkup).Groups[1].Value;
155+
156+
theStyleRules.ShouldContain("background-color:");
157+
theStyleRules.ShouldContain("color:");
158+
}
159+
160+
[Fact]
161+
public void Menu_ImplementsIMenuStyleContainer()
162+
{
163+
JSInterop.Mode = JSRuntimeMode.Loose;
164+
165+
var cut = Render(
166+
@<Menu>
167+
<ChildContent>
168+
<Items>
169+
<MenuItem Text="Home" Value="home" />
170+
</Items>
171+
</ChildContent>
172+
</Menu>
173+
);
174+
175+
var menu = cut.FindComponent<Menu>().Instance;
176+
(menu is BlazorWebFormsComponents.Interfaces.IMenuStyleContainer).ShouldBeTrue();
177+
}
178+
179+
[Fact]
180+
public void Menu_StaticMenuStyle_DefaultIsNotNull()
181+
{
182+
JSInterop.Mode = JSRuntimeMode.Loose;
183+
184+
var cut = Render(
185+
@<Menu>
186+
<ChildContent>
187+
<Items>
188+
<MenuItem Text="Home" Value="home" />
189+
</Items>
190+
</ChildContent>
191+
</Menu>
192+
);
193+
194+
var menu = cut.FindComponent<Menu>().Instance;
195+
menu.StaticMenuStyle.ShouldNotBeNull();
196+
}
197+
198+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace BlazorWebFormsComponents.Interfaces
2+
{
3+
/// <summary>
4+
/// Interface for components that contain Menu-specific style properties.
5+
/// </summary>
6+
public interface IMenuStyleContainer
7+
{
8+
MenuItemStyle DynamicMenuStyle { get; set; }
9+
MenuItemStyle StaticMenuStyle { get; set; }
10+
MenuItemStyle DynamicMenuItemStyle { get; set; }
11+
MenuItemStyle StaticMenuItemStyle { get; set; }
12+
}
13+
}

src/BlazorWebFormsComponents/Menu.razor

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
}
99
<div id="@ID" class="@GetMenuCssClass()" style="@Style" title="@ToolTip">
1010
<ul class="level1@(Orientation == Orientation.Horizontal ? " horizontal" : "")">
11-
<CascadingValue Name="ParentMenu" Value="this">
11+
<CascadingValue Name="ParentMenu" Value="this" IsFixed="true">
12+
@DynamicMenuStyleContent
13+
@StaticMenuStyleContent
14+
@DynamicMenuItemStyleContent
15+
@StaticMenuItemStyleContent
1216
@ChildContent
1317
@ChildNodesRenderFragment
1418
</CascadingValue>
@@ -47,6 +51,10 @@
4751
z-index: 1;
4852
}
4953
54+
@($"#{ID} ul.level1") {
55+
@StaticMenuStyle?.ToStyle().ToString()
56+
}
57+
5058
@($"#{ID} a") {
5159
font-family: Arial;
5260
text-decoration: none;

src/BlazorWebFormsComponents/Menu.razor.cs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Xml;
66
using BlazorComponentUtilities;
77
using BlazorWebFormsComponents.Enums;
8+
using BlazorWebFormsComponents.Interfaces;
89
using Microsoft.AspNetCore.Components;
910
using Microsoft.AspNetCore.Components.Rendering;
1011
using Microsoft.JSInterop;
@@ -15,7 +16,7 @@ namespace BlazorWebFormsComponents
1516
/// <summary>
1617
/// A menubar component capable of making hierarchical menus for navigating your application
1718
/// </summary>
18-
public partial class Menu : BaseStyledComponent
19+
public partial class Menu : BaseStyledComponent, IMenuStyleContainer
1920
{
2021

2122
#region Injected Properties
@@ -225,6 +226,69 @@ public StaticMenuItemStyle StaticMenuItemStyle {
225226
}
226227
}
227228

229+
private StaticMenuStyle _StaticMenuStyle = new StaticMenuStyle();
230+
public StaticMenuStyle StaticMenuStyle
231+
{
232+
get { return _StaticMenuStyle; }
233+
set
234+
{
235+
_StaticMenuStyle = value;
236+
this.StateHasChanged();
237+
}
238+
}
239+
240+
#region IMenuStyleContainer explicit implementation
241+
242+
MenuItemStyle IMenuStyleContainer.DynamicMenuStyle
243+
{
244+
get => _DynamicMenuStyle;
245+
set => DynamicMenuStyle = (DynamicMenuStyle)value;
246+
}
247+
248+
MenuItemStyle IMenuStyleContainer.StaticMenuStyle
249+
{
250+
get => _StaticMenuStyle;
251+
set => StaticMenuStyle = (StaticMenuStyle)value;
252+
}
253+
254+
MenuItemStyle IMenuStyleContainer.DynamicMenuItemStyle
255+
{
256+
get => _DynamicMenuItemStyle;
257+
set => DynamicMenuItemStyle = (DynamicMenuItemStyle)value;
258+
}
259+
260+
MenuItemStyle IMenuStyleContainer.StaticMenuItemStyle
261+
{
262+
get => _StaticMenuItemStyle;
263+
set => StaticMenuItemStyle = (StaticMenuItemStyle)value;
264+
}
265+
266+
#endregion
267+
268+
#region Style RenderFragment Parameters
269+
270+
/// <summary>
271+
/// Content for the DynamicMenuStyle sub-component.
272+
/// </summary>
273+
[Parameter] public RenderFragment DynamicMenuStyleContent { get; set; }
274+
275+
/// <summary>
276+
/// Content for the StaticMenuStyle sub-component.
277+
/// </summary>
278+
[Parameter] public RenderFragment StaticMenuStyleContent { get; set; }
279+
280+
/// <summary>
281+
/// Content for the DynamicMenuItemStyle sub-component.
282+
/// </summary>
283+
[Parameter] public RenderFragment DynamicMenuItemStyleContent { get; set; }
284+
285+
/// <summary>
286+
/// Content for the StaticMenuItemStyle sub-component.
287+
/// </summary>
288+
[Parameter] public RenderFragment StaticMenuItemStyleContent { get; set; }
289+
290+
#endregion
291+
228292

229293
[Parameter]
230294
public RenderFragment ChildContent { get; set; }

src/BlazorWebFormsComponents/MenuItemStyle.razor.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,14 @@ protected override void OnInitialized()
125125

126126
}
127127

128+
public class StaticMenuStyle : MenuItemStyle {
129+
130+
protected override void OnInitialized()
131+
{
132+
base.OnInitialized();
133+
ParentMenu.StaticMenuStyle = this;
134+
}
135+
136+
}
137+
128138
}

0 commit comments

Comments
 (0)