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
21 changes: 20 additions & 1 deletion src/BootstrapBlazor.Server/Components/Samples/Dropdowns.razor
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
</div>
</DemoBlock>

<DemoBlock Title="@Localizer["DropdownItemTemplateTitle"]" Introduction="@Localizer["DropdownItemTemplateIntro"]" Name="ItemTemplate">
<DemoBlock Title="@Localizer["DropdownItemTemplateTitle"]" Introduction="@Localizer["DropdownItemTemplateIntro"]"
Name="ItemTemplate">
<Dropdown TValue="string" Items="ItemTemplateList">
<ItemTemplate>
<Tooltip Title="just a tooltip text demo" Trigger="hover">
Expand All @@ -42,6 +43,24 @@
</Dropdown>
</DemoBlock>

<DemoBlock Title="@Localizer["DropdownItemsTemplateTitle"]" Introduction="@Localizer["DropdownItemsTemplateIntro"]"
Name="ItemsTemplate">
<Dropdown TValue="string" IsFixedButtonText="true" FixedButtonText="More" Icon="fa solid fa-ellipsis">
<ItemsTemplate>
<DropdownItem Text="Copy" Icon="fa-solid fa-copy" OnClick="@(() => OnClickAction("Copy"))"></DropdownItem>
<DropdownItem Text="Paste" Icon="fa-solid fa-paste" OnClick="@(() => OnClickAction("Paste"))"></DropdownItem>
<Divider></Divider>
<DropdownItem Text="Action1" Icon="fa-solid fa-flag" OnClick="@(() => OnClickAction("Action1"))"></DropdownItem>
<DropdownItem>
<Tooltip Title="just a tooltip text demo" Trigger="hover">
<span class="fa-solid fa-flag"></span>
<div class="ms-2 flex-fill" @onclick="@(() => OnClickAction("Action2"))">Action2</div>
</Tooltip>
</DropdownItem>
</ItemsTemplate>
</Dropdown>
</DemoBlock>

<DemoBlock Title="@Localizer["SplitTitle"]" Introduction='@Localizer["SplitIntro"]' Name="Split">
<div class="row g-3">
<div class="col-6 col-sm-4 col-md-3">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}");

/// <summary>
/// GetAttributes
/// </summary>
Expand Down
4 changes: 3 additions & 1 deletion src/BootstrapBlazor.Server/Locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -1626,7 +1626,9 @@
"DropdownCascadeItem7": "Jingan",
"DropdownCascadeItem8": "Huangpu",
"DropdownItemTemplateTitle": "Item Template",
"DropdownItemTemplateIntro": "By setting <code>ItemTemplate</code>, you can customize the content displayed in the drop-down item. In this example, the <code>Tooltip</code> component is used to add a tooltip function when the mouse is hovered."
"DropdownItemTemplateIntro": "By setting <code>ItemTemplate</code>, you can customize the content displayed in the drop-down item. In this example, the <code>Tooltip</code> 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 `<itemsTemplate>`. In this example, we use the `<DropdownItem>` component and `<DropdownDivider>` component to customize the dropdown list component."
},
"BootstrapBlazor.Server.Components.Samples.GoTops": {
"Title": "GoTop",
Expand Down
4 changes: 3 additions & 1 deletion src/BootstrapBlazor.Server/Locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1626,7 +1626,9 @@
"DropdownCascadeItem7": "静安区",
"DropdownCascadeItem8": "黄浦区",
"DropdownItemTemplateTitle": "下拉项模板",
"DropdownItemTemplateIntro": "通过设置 <code>ItemTemplate</code> 可以自定义下拉项显示内容,本例中通过自定义模板使用 <code>Tooltip</code> 组件增加鼠标悬浮是显示提示功能"
"DropdownItemTemplateIntro": "通过设置 <code>ItemTemplate</code> 可以自定义下拉项显示内容,本例中通过自定义模板使用 <code>Tooltip</code> 组件增加鼠标悬浮是显示提示功能",
"DropdownItemsTemplateTitle": "下拉框模板",
"DropdownItemsTemplateIntro": "通过设置 <code>ItemsTemplate</code> 可以自定义下拉框所有内容,本例中通过使用 <code>DropdownItem</code> 组件与 <code>DropdownDivider</code> 对下拉框组件进行自定义"
},
"BootstrapBlazor.Server.Components.Samples.GoTops": {
"Title": "GoTop 返回顶端组件",
Expand Down
12 changes: 9 additions & 3 deletions src/BootstrapBlazor/Components/Dropdown/Dropdown.razor
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
<BootstrapLabel for="@Id" ShowLabelTooltip="ShowLabelTooltip" Value="@DisplayText"></BootstrapLabel>
}
<div @attributes="@AdditionalAttributes" id="@Id" class="@DirectionClassName">
<DynamicElement TagName="button" type="button" class="@ButtonClassName" data-bs-toggle="@DropdownToggle" disabled="@Disabled"
<DynamicElement TagName="button" type="button" class="@ButtonClassName" data-bs-toggle="@DropdownToggle"
disabled="@Disabled"
TriggerClick="ShowSplit" OnClick="OnClickButton" PreventDefault="false" StopPropagation="false">
@if (ButtonTemplate == null)
{
Expand All @@ -20,7 +21,10 @@
{
<i class="@Icon"></i>
}
<span>@ButtonText</span>
@if (!string.IsNullOrEmpty(ButtonText))
{
<span>@ButtonText</span>
}
}
else
{
Expand All @@ -29,7 +33,9 @@
</DynamicElement>
@if (ShowSplit)
{
<button type="button" class="@ClassName" data-bs-toggle="@ToggleString" disabled="@Disabled" aria-haspopup="true" aria-expanded="false"></button>
<button type="button" class="@ClassName" data-bs-toggle="@ToggleString" disabled="@Disabled"
aria-haspopup="true" aria-expanded="false">
</button>
}
<div class="@MenuAlignmentClass">
@if (ItemsTemplate == null)
Expand Down
6 changes: 6 additions & 0 deletions src/BootstrapBlazor/Components/Dropdown/Dropdown.razor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@
margin-inline-start: 0.25rem;
}
}

.dropdown-menu {
.divider {
margin: 0.25rem 0;
}
}
22 changes: 22 additions & 0 deletions src/BootstrapBlazor/Components/Dropdown/DropdownItem.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@namespace BootstrapBlazor.Components

@if (ChildContent != null)
{
<div class="@ItemClassString">
@ChildContent
</div>
}
else
{
<DynamicElement class="@ItemClassString"
TriggerClick="!IsDisabled" OnClick="OnClickItem">
@if (!string.IsNullOrEmpty(ItemIconString))
{
<i class="@ItemIconString"></i>
}
@if (!string.IsNullOrEmpty(Text))
{
<span>@Text</span>
}
</DynamicElement>
}
66 changes: 66 additions & 0 deletions src/BootstrapBlazor/Components/Dropdown/DropdownItem.razor.cs
Original file line number Diff line number Diff line change
@@ -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([email protected]) Website: https://www.blazor.zone

namespace BootstrapBlazor.Components;

/// <summary>
/// DropdownItem 组件
/// </summary>
public partial class DropdownItem
{
/// <summary>
/// 获得/设置 显示文本
/// </summary>
[Parameter]
public string? Text { get; set; }

/// <summary>
/// 获得/设置 图标
/// </summary>
[Parameter]
public string? Icon { get; set; }

/// <summary>
/// 获得/设置 是否被禁用 默认 false 优先级低于 <see cref="OnDisabledCallback"/>
/// </summary>
[Parameter]
public bool Disabled { get; set; }

/// <summary>
/// 获得/设置 是否被禁用回调方法 默认 null 优先级高于 <see cref="Disabled"/>
/// </summary>
[Parameter]
public Func<bool>? OnDisabledCallback { get; set; }

/// <summary>
/// 获得/设置 点击回调方法 默认 null
/// </summary>
[Parameter]
public Func<Task>? OnClick { get; set; }

/// <summary>
/// 获得/设置 组件内容
/// </summary>
[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();
}
}
}
65 changes: 56 additions & 9 deletions test/UnitTest/Components/DropdownTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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("<i class=\"fa-solid fa-test-icon\"></i>");
var button = cut.Find("button");
Expand Down Expand Up @@ -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<Dropdown<string>>(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("<div>test-items-template</div>"));
}));
builder.OpenComponent<DropdownItem>(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<DropdownItem>(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<DropdownItem>(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<DropdownItem>(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, "<div>dropdown-item-childcontent</div>")));
builder.CloseComponent();
});
});
cut.Contains("<div>test-items-template</div>");
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]
Expand Down
Loading