diff --git a/src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor b/src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor index 1f492cefbf7..0070f384d11 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor @@ -31,7 +31,8 @@ - + @@ -42,6 +43,24 @@ + + + + + + + + + + +
Action2
+
+
+
+
+
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor.cs index bfdc9ab61fb..03b097dccd0 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor.cs @@ -163,6 +163,8 @@ private async Task OnIsAsyncClick() await ToastService.Success("Dropdown IsAsync", "Job done!"); } + private Task OnClickAction(string actionName) => ToastService.Information("Custom Action", $"Trigger {actionName}"); + /// /// GetAttributes /// diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 47f19c74f04..8e13ec592fc 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -1626,7 +1626,9 @@ "DropdownCascadeItem7": "Jingan", "DropdownCascadeItem8": "Huangpu", "DropdownItemTemplateTitle": "Item Template", - "DropdownItemTemplateIntro": "By setting ItemTemplate, you can customize the content displayed in the drop-down item. In this example, the Tooltip component is used to add a tooltip function when the mouse is hovered." + "DropdownItemTemplateIntro": "By setting ItemTemplate, you can customize the content displayed in the drop-down item. In this example, the Tooltip component is used to add a tooltip function when the mouse is hovered.", + "DropdownItemsTemplateTitle": "Items Template", + "DropdownItemsTemplateIntro": "You can customize all the content of the dropdown list by setting ``. In this example, we use the `` component and `` component to customize the dropdown list component." }, "BootstrapBlazor.Server.Components.Samples.GoTops": { "Title": "GoTop", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index d918aa4b98e..cd70bc387ad 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -1626,7 +1626,9 @@ "DropdownCascadeItem7": "静安区", "DropdownCascadeItem8": "黄浦区", "DropdownItemTemplateTitle": "下拉项模板", - "DropdownItemTemplateIntro": "通过设置 ItemTemplate 可以自定义下拉项显示内容,本例中通过自定义模板使用 Tooltip 组件增加鼠标悬浮是显示提示功能" + "DropdownItemTemplateIntro": "通过设置 ItemTemplate 可以自定义下拉项显示内容,本例中通过自定义模板使用 Tooltip 组件增加鼠标悬浮是显示提示功能", + "DropdownItemsTemplateTitle": "下拉框模板", + "DropdownItemsTemplateIntro": "通过设置 ItemsTemplate 可以自定义下拉框所有内容,本例中通过使用 DropdownItem 组件与 DropdownDivider 对下拉框组件进行自定义" }, "BootstrapBlazor.Server.Components.Samples.GoTops": { "Title": "GoTop 返回顶端组件", diff --git a/src/BootstrapBlazor/Components/Dropdown/Dropdown.razor b/src/BootstrapBlazor/Components/Dropdown/Dropdown.razor index 742bbc4dd3d..3e301d3b32d 100644 --- a/src/BootstrapBlazor/Components/Dropdown/Dropdown.razor +++ b/src/BootstrapBlazor/Components/Dropdown/Dropdown.razor @@ -8,7 +8,8 @@ }
- @if (ButtonTemplate == null) { @@ -20,7 +21,10 @@ { } - @ButtonText + @if (!string.IsNullOrEmpty(ButtonText)) + { + @ButtonText + } } else { @@ -29,7 +33,9 @@ @if (ShowSplit) { - + }
@if (ItemsTemplate == null) diff --git a/src/BootstrapBlazor/Components/Dropdown/Dropdown.razor.scss b/src/BootstrapBlazor/Components/Dropdown/Dropdown.razor.scss index 76895d21ca4..0c2d0df901b 100644 --- a/src/BootstrapBlazor/Components/Dropdown/Dropdown.razor.scss +++ b/src/BootstrapBlazor/Components/Dropdown/Dropdown.razor.scss @@ -9,3 +9,9 @@ margin-inline-start: 0.25rem; } } + +.dropdown-menu { + .divider { + margin: 0.25rem 0; + } +} diff --git a/src/BootstrapBlazor/Components/Dropdown/DropdownItem.razor b/src/BootstrapBlazor/Components/Dropdown/DropdownItem.razor new file mode 100644 index 00000000000..0bce731247b --- /dev/null +++ b/src/BootstrapBlazor/Components/Dropdown/DropdownItem.razor @@ -0,0 +1,22 @@ +@namespace BootstrapBlazor.Components + +@if (ChildContent != null) +{ +
+ @ChildContent +
+} +else +{ + + @if (!string.IsNullOrEmpty(ItemIconString)) + { + + } + @if (!string.IsNullOrEmpty(Text)) + { + @Text + } + +} diff --git a/src/BootstrapBlazor/Components/Dropdown/DropdownItem.razor.cs b/src/BootstrapBlazor/Components/Dropdown/DropdownItem.razor.cs new file mode 100644 index 00000000000..16024d32a84 --- /dev/null +++ b/src/BootstrapBlazor/Components/Dropdown/DropdownItem.razor.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Components; + +/// +/// DropdownItem 组件 +/// +public partial class DropdownItem +{ + /// + /// 获得/设置 显示文本 + /// + [Parameter] + public string? Text { get; set; } + + /// + /// 获得/设置 图标 + /// + [Parameter] + public string? Icon { get; set; } + + /// + /// 获得/设置 是否被禁用 默认 false 优先级低于 + /// + [Parameter] + public bool Disabled { get; set; } + + /// + /// 获得/设置 是否被禁用回调方法 默认 null 优先级高于 + /// + [Parameter] + public Func? OnDisabledCallback { get; set; } + + /// + /// 获得/设置 点击回调方法 默认 null + /// + [Parameter] + public Func? OnClick { get; set; } + + /// + /// 获得/设置 组件内容 + /// + [Parameter] + public RenderFragment? ChildContent { get; set; } + + private string? ItemIconString => CssBuilder.Default("dropdown-item-icon") + .AddClass(Icon, !string.IsNullOrEmpty(Icon)) + .Build(); + + private string? ItemClassString => CssBuilder.Default("dropdown-item") + .AddClass("disabled", IsDisabled) + .Build(); + + private bool IsDisabled => OnDisabledCallback?.Invoke() ?? Disabled; + + private async Task OnClickItem() + { + if (OnClick != null) + { + await OnClick(); + } + } +} diff --git a/test/UnitTest/Components/DropdownTest.cs b/test/UnitTest/Components/DropdownTest.cs index aad1347ccca..4a90b0365af 100644 --- a/test/UnitTest/Components/DropdownTest.cs +++ b/test/UnitTest/Components/DropdownTest.cs @@ -42,10 +42,7 @@ public async Task IsAsync_Ok() pb.Add(a => a.IsAsync, true); pb.Add(a => a.IsKeepDisabled, false); pb.Add(a => a.Icon, "fa-solid fa-test-icon"); - pb.Add(a => a.OnClickWithoutRender, () => - { - return Task.CompletedTask; - }); + pb.Add(a => a.OnClickWithoutRender, () => Task.CompletedTask); }); cut.Contains(""); var button = cut.Find("button"); @@ -272,16 +269,66 @@ public void Disabled_Ok() } [Fact] - public void ItemsTemplate_Ok() + public async Task ItemsTemplate_Ok() { + var clicked = false; var cut = Context.RenderComponent>(pb => { - pb.Add(a => a.ItemsTemplate, new RenderFragment(builder => + pb.Add(a => a.IsFixedButtonText, true); + pb.Add(a => a.FixedButtonText, "fixed text"); + pb.Add(a => a.ItemsTemplate, builder => { - builder.AddContent(0, new MarkupString("
test-items-template
")); - })); + builder.OpenComponent(0); + builder.AddAttribute(1, "Icon", "fa-solid fa-icon1"); + builder.AddAttribute(2, "Text", "dropdown-item-test1"); + builder.AddAttribute(3, "OnClick", () => + { + clicked = true; + return Task.CompletedTask; + }); + builder.CloseComponent(); + + builder.OpenComponent(0); + builder.AddAttribute(1, "Icon", "fa-solid fa-icon2"); + builder.AddAttribute(2, "Text", "dropdown-item-test2"); + builder.AddAttribute(3, "Disabled", true); + builder.CloseComponent(); + + builder.OpenComponent(0); + builder.AddAttribute(1, "Icon", "fa-solid fa-icon3"); + builder.AddAttribute(2, "Text", "dropdown-item-test3"); + builder.AddAttribute(3, "Disabled", false); + builder.AddAttribute(4, "OnDisabledCallback", () => true); + builder.CloseComponent(); + + builder.OpenComponent(0); + builder.AddAttribute(1, "Icon", "fa-solid fa-icon4"); + builder.AddAttribute(2, "Text", "dropdown-item-test4"); + builder.AddAttribute(3, "ChildContent", + new RenderFragment(pb1 => pb1.AddMarkupContent(0, "
dropdown-item-childcontent
"))); + builder.CloseComponent(); + }); }); - cut.Contains("
test-items-template
"); + cut.Contains("fa-solid fa-icon1"); + cut.Contains("dropdown-item-test1"); + + cut.Contains("fa-solid fa-icon2"); + cut.Contains("dropdown-item-test2"); + + cut.Contains("fa-solid fa-icon3"); + cut.Contains("dropdown-item-test3"); + + cut.DoesNotContain("fa-solid fa-icon4"); + cut.DoesNotContain("dropdown-item-test4"); + cut.Contains("dropdown-item-childcontent"); + + cut.Contains("dropdown-item disabled"); + + Assert.False(clicked); + + var item = cut.Find(".dropdown-item"); + await cut.InvokeAsync((() => item.Click())); + Assert.True(clicked); } [Fact]