Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
4 changes: 4 additions & 0 deletions src/BootstrapBlazor.Server/Components/Samples/Buttons.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

<h4>@Localizer["Description"]</h4>

<DemoBlock Title="@Localizer["ToggleButton"]" Introduction="@Localizer["ToggleIntroduction"]" Name="Toggle">
<ToggleButton Text="Toggle" Color="Color.Danger"></ToggleButton>
</DemoBlock>

<DemoBlock Title="@Localizer["Block1Title"]" Introduction="@Localizer["Block1Intro"]" Name="Normal">
<div class="row g-3">
<div class="col-6 col-sm-4 col-md-3 col-lg-auto"><Button OnClick="@ButtonClick" Color="Color.Primary">@Localizer["PrimaryButton"]</Button></div>
Expand Down
23 changes: 23 additions & 0 deletions src/BootstrapBlazor/Components/Button/ToggleButton.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@namespace BootstrapBlazor.Components
@inherits ButtonBase

<button @attributes="@AdditionalAttributes" @onclick="@OnClickButton" id="@Id" class="@ToggleClassName" disabled="@Disabled"
role="button" data-bs-placement="@PlacementString" data-bs-trigger="@TriggerString"
aria-disabled="@DisabledString" tabindex="@Tab" data-bs-toggle="button"
@onclick:stopPropagation="@StopPropagation">
@if(IsAsyncLoading)
{
<i class="@LoadingIcon"></i>
}
else if (!string.IsNullOrEmpty(Icon))
{
<i class="@Icon"></i>
}
@if (!string.IsNullOrEmpty(Text))
{
<span>@Text</span>
}
<CascadingValue Value="this" IsFixed="true">
@ChildContent
</CascadingValue>
</button>
81 changes: 81 additions & 0 deletions src/BootstrapBlazor/Components/Button/ToggleButton.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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>
/// Toggle Button 按钮组件
/// </summary>
public partial class ToggleButton
{
/// <summary>
/// 获得/设置 状态切换回调方法
/// </summary>
[Parameter]
public Func<bool, Task>? OnToggleAsync { get; set; }

/// <summary>
/// 获得/设置 当前状态是否为激活状态 默认 false
/// </summary>
[Parameter]
public bool IsActive { get; set; }

/// <summary>
/// 获得/设置 激活状态回调方法
/// </summary>
[Parameter]
public EventCallback<bool> IsActiveChanged { get; set; }

private string? ToggleClassName => CssBuilder.Default(ClassName)
.AddClass("active", IsActive)
.Build();

private async Task OnClickButton()
{
if (IsAsync)
{
IsAsyncLoading = true;
IsDisabled = true;
}

await HandlerClick();

// 恢复按钮
if (IsAsync)
{
IsDisabled = IsKeepDisabled;
IsAsyncLoading = false;
}
}

private async Task HandlerClick()
{
IsActive = !IsActive;
if (OnClickWithoutRender != null)
{
if (!IsAsync)
{
IsNotRender = true;
}

await OnClickWithoutRender();
}

if (OnClick.HasDelegate)
{
await OnClick.InvokeAsync();
}

if (IsActiveChanged.HasDelegate)
{
await IsActiveChanged.InvokeAsync(IsActive);
}

if (OnToggleAsync != null)
{
await OnToggleAsync(IsActive);
}
}
}
41 changes: 41 additions & 0 deletions test/UnitTest/Components/ButtonTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -452,4 +452,45 @@
Assert.Equal("test-share-title", cut.Instance.ShareContext?.Title);
Assert.Equal("www.blazor.zone", cut.Instance.ShareContext?.Url);
}

[Fact]
public async Task ToogleButton_Ok()
{
var active = false;
var bindActive = false;

Check warning on line 460 in test/UnitTest/Components/ButtonTest.cs

View workflow job for this annotation

GitHub Actions / run test

The variable 'bindActive' is assigned but its value is never used
var clickWithoutRender = false;
var clicked = false;
var tcs = new TaskCompletionSource();
var cut = Context.RenderComponent<ToggleButton>(pb =>
{
pb.Add(a => a.IsActive, false);
pb.Add(a => a.IsActiveChanged, EventCallback.Factory.Create<bool>(this, b =>
{
active = b;
bindActive = true;
}));
pb.Add(a => a.OnClickWithoutRender, () =>
{
clickWithoutRender = true;
return Task.CompletedTask;
});
pb.Add(a => a.OnClick, () =>
{
clicked = true;
return Task.CompletedTask;
});
pb.Add(a => a.OnToggleAsync, async isActive =>
{
await Task.Delay(10);
active = isActive;
tcs.TrySetResult();
});
});
var button = cut.Find("button");
await cut.InvokeAsync(() => button.Click());
await tcs.Task;
Assert.True(active);
Assert.True(clickWithoutRender);
Assert.True(clicked);
}
}
21 changes: 21 additions & 0 deletions test/UnitTest/Components/TableTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8720,6 +8720,27 @@ public void Modify_Ok()
Assert.True(ProhibitDelete(cut.Instance));
}

[Fact]
public void Table_Sortable()
{
var localizer = Context.Services.GetRequiredService<IStringLocalizer<Foo>>();
var cut = Context.RenderComponent<Table<Foo>>(pb =>
{
pb.AddCascadingValue<ISortableList>(new SortableList());
pb.Add(a => a.TableColumns, foo => builder =>
{
builder.OpenComponent<TableColumn<Foo, string>>(0);
builder.AddAttribute(1, "Field", "Name");
builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string)));
builder.CloseComponent();
});
pb.Add(a => a.RenderMode, TableRenderMode.Table);
pb.Add(a => a.Items, Foo.GenerateFoo(localizer));
});
}

class SortableList : ISortableList { }

static bool ProhibitEdit(Table<Foo> @this)
{
var ret = false;
Expand Down
Loading