Skip to content

Commit

Permalink
feat(RadioListGeneric): implement RadioListGeneric component (#4908)
Browse files Browse the repository at this point in the history
* feat: 更新逻辑

* refactor: 重构组件

* doc: 增加示例

* doc: 更新 CheckboxList 示例

* doc: 更新 RadioList 示例

* feat: 增加 Value 逻辑

* test: 增加单元测试

* chore: bump version 9.1.6

---------

Co-authored-by: Argo Zhang <argo@live.ca>
Co-authored-by: A5196060 <5196060@qq.com>
Co-authored-by: j4587698 <zhuce@jvxiang.com>
Co-authored-by: Mr Lu <ghi.ghi@163.com>
  • Loading branch information
5 people authored Dec 21, 2024
1 parent 3c4cc8e commit 72398af
Show file tree
Hide file tree
Showing 9 changed files with 414 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
</ValidateForm>
</DemoBlock>

<DemoBlock Title="@Localizer["GenericTitle"]" Introduction="@Localizer["GenericIntro"]" Name="Generic">
<DemoBlock Title="@Localizer["CheckboxListGenericTitle"]" Introduction="@Localizer["CheckboxListGenericIntro"]" Name="Generic">
<CheckboxListGeneric @bind-Value="@_selectedFoos" Items="@GenericItems" />
<section ignore>
@if (_selectedFoos != null)
Expand Down
7 changes: 7 additions & 0 deletions src/BootstrapBlazor.Server/Components/Samples/Radios.razor
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@
</ValidateForm>
</DemoBlock>

<DemoBlock Title="@Localizer["RadioListGenericTitle"]" Introduction="@Localizer["RadioListGenericIntro"]" Name="Generic">
<RadioListGeneric @bind-Value="@_selectedFoo" Items="@GenericItems" />
<section ignore>
<div>@_selectedFoo.Name</div>
</section>
</DemoBlock>

<AttributeTable Items="@GetAttributes()" />

<EventTable Items="@GetEvents()" />
Expand Down
18 changes: 18 additions & 0 deletions src/BootstrapBlazor.Server/Components/Samples/Radios.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone

using DocumentFormat.OpenXml.Office2010.Excel;
using DocumentFormat.OpenXml.Wordprocessing;

namespace BootstrapBlazor.Server.Components.Samples;

/// <summary>
Expand Down Expand Up @@ -52,6 +55,12 @@ private Task OnSelectedChanged(IEnumerable<SelectedItem> values, string val)
return Task.CompletedTask;
}

[NotNull]
private IEnumerable<SelectedItem<Foo>>? GenericItems { get; set; }

[NotNull]
private Foo? _selectedFoo = default;

/// <summary>
/// OnInitialized 方法
/// </summary>
Expand Down Expand Up @@ -85,6 +94,15 @@ protected override void OnInitialized()

Model = Foo.Generate(LocalizerFoo);
FooItems = Foo.GetCompleteItems(LocalizerFoo);

GenericItems = new List<SelectedItem<Foo>>()
{
new() { Text = Localizer["item1"], Value = new Foo() { Id = 1, Name = LocalizerFoo["Foo.Name", "001"] } },
new() { Text = Localizer["item2"], Value = new Foo() { Id = 2, Name = LocalizerFoo["Foo.Name", "002"] } },
new() { Text = Localizer["item3"], Value = new Foo() { Id = 3, Name = LocalizerFoo["Foo.Name", "003"] } },
};

_selectedFoo = new Foo() { Id = 1, Name = LocalizerFoo["Foo.Name", "001"] };
}

private Task OnItemChanged(IEnumerable<SelectedItem> values, SelectedItem val)
Expand Down
8 changes: 6 additions & 2 deletions src/BootstrapBlazor.Server/Locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -2376,7 +2376,9 @@
"StatusText2": "Not selected",
"StatusText3": "Indeterminate",
"Checkbox2Text": "Two-way binding",
"Checkbox3Text": "Handwritten labels"
"Checkbox3Text": "Handwritten labels",
"RadioListGenericTitle": "Generic List",
"RadioListGenericIntro": "Enable generic support through <code>SelectedItem&lt;TValue&gt;</code>"
},
"BootstrapBlazor.Server.Components.Samples.CheckboxLists": {
"Title": "CheckboxList",
Expand Down Expand Up @@ -3024,7 +3026,9 @@
"RadiosItem1": "Option one",
"RadiosItem2": "Option two",
"RadiosAdd1": "Beijing",
"RadiosAdd2": "Shanghai"
"RadiosAdd2": "Shanghai",
"RadioListGenericTitle": "Generic List",
"RadioListGenericIntro": "Enable generic support through <code>SelectedItem&lt;TValue&gt;</code>"
},
"BootstrapBlazor.Server.Components.Samples.Rates": {
"RatesTitle": "Rate",
Expand Down
8 changes: 6 additions & 2 deletions src/BootstrapBlazor.Server/Locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -2426,7 +2426,9 @@
"MaxSelectedCountIntro": "通过设置 <code>MaxSelectedCount</code> 属性控制最大可选数量,通过 <code>OnMaxSelectedCountExceed</code> 回调处理逻辑",
"MaxSelectedCountDesc": "选中节点超过 2 个时,弹出 <code>Toast</code> 提示栏",
"OnMaxSelectedCountExceedTitle": "可选最大数量提示",
"OnMaxSelectedCountExceedContent": "最多只能选择 {0} 项"
"OnMaxSelectedCountExceedContent": "最多只能选择 {0} 项",
"CheckboxListGenericTitle": "泛型支持",
"CheckboxListGenericIntro": "通过 <code>SelectedItem&lt;TValue&gt;</code> 开启泛型支持"
},
"BootstrapBlazor.Server.Components.Samples.ColorPickers": {
"Title": "ColorPicker 颜色拾取器",
Expand Down Expand Up @@ -3024,7 +3026,9 @@
"RadiosItem1": "选项一",
"RadiosItem2": "选项二",
"RadiosAdd1": "北京",
"RadiosAdd2": "上海"
"RadiosAdd2": "上海",
"RadioListGenericTitle": "泛型支持",
"RadioListGenericIntro": "通过 <code>SelectedItem&lt;TValue&gt;</code> 开启泛型支持"
},
"BootstrapBlazor.Server.Components.Samples.Rates": {
"RatesTitle": "Rate 评分",
Expand Down
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>9.1.6-beta03</Version>
<Version>9.1.6</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
3 changes: 1 addition & 2 deletions src/BootstrapBlazor/Components/Radio/RadioListGeneric.razor
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{
<BootstrapLabel required="@Required" ShowLabelTooltip="ShowLabelTooltip" Value="@DisplayText" />
}
@* @if (IsButton)
@if (IsButton)
{
<div @attributes="@AdditionalAttributes" class="radio-list-group">
<div class="@ButtonClassString" role="group">
Expand All @@ -29,4 +29,3 @@ else
}
</div>
}
*@
188 changes: 134 additions & 54 deletions src/BootstrapBlazor/Components/Radio/RadioListGeneric.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ namespace BootstrapBlazor.Components;
/// <summary>
/// 单选框组合组件
/// </summary>
[ExcludeFromCodeCoverage]
public partial class RadioListGeneric<TValue>
public partial class RadioListGeneric<TValue> : IModelEqualityComparer<TValue>
{
/// <summary>
/// 获得/设置 值为可为空枚举类型时是否自动添加空值 默认 false 自定义空值显示文本请参考 <see cref="NullItemText"/>
Expand All @@ -30,56 +29,137 @@ public partial class RadioListGeneric<TValue>
[Parameter]
public RenderFragment<SelectedItem<TValue>>? ItemTemplate { get; set; }

//private string? GroupName => Id;

//private string? ClassString => CssBuilder.Default("radio-list form-control")
// .AddClass("no-border", !ShowBorder && ValidCss != "is-invalid")
// .AddClass("is-vertical", IsVertical)
// .AddClass(CssClass).AddClass(ValidCss)
// .Build();

//private string? ButtonClassString => CssBuilder.Default("radio-list btn-group")
// .AddClass("disabled", IsDisabled)
// .AddClass("btn-group-vertical", IsVertical)
// .AddClassFromAttributes(AdditionalAttributes)
// .Build();

//private string? GetButtonItemClassString(SelectedItem item) => CssBuilder.Default("btn")
// .AddClass($"active bg-{Color.ToDescriptionString()}", CurrentValueAsString == item.Value)
// .Build();

///// <summary>
///// <inheritdoc/>
///// </summary>
//protected override void OnParametersSet()
//{
// var t = NullableUnderlyingType ?? typeof(TValue);
// if (t.IsEnum && Items == null)
// {
// Items = t.ToSelectList<TValue>((NullableUnderlyingType != null && IsAutoAddNullItem) ? new SelectedItem<TValue>(default, NullItemText) : null);
// }

// base.OnParametersSet();
//}

///// <summary>
///// 点击选择框方法
///// </summary>
//private async Task OnClick(SelectedItem<TValue> item)
//{
// if (!IsDisabled)
// {
// if (OnSelectedChanged != null)
// {
// await OnSelectedChanged(Items, Value);
// }
// StateHasChanged();
// }
//}

//private CheckboxState CheckState(SelectedItem<TValue> item) => this.Equals<TValue>(Value, item.Value) ? CheckboxState.Checked : CheckboxState.UnChecked;

//private RenderFragment? GetChildContent(SelectedItem<TValue> item) => ItemTemplate == null
// ? null
// : ItemTemplate(item);
/// <summary>
/// 获得/设置 是否为按钮样式 默认 false
/// </summary>
[Parameter]
public bool IsButton { get; set; }

/// <summary>
/// 获得/设置 是否显示边框 默认为 true
/// </summary>
[Parameter]
public bool ShowBorder { get; set; } = true;

/// <summary>
/// 获得/设置 是否为竖向排列 默认为 false
/// </summary>
[Parameter]
public bool IsVertical { get; set; }

/// <summary>
/// 获得/设置 按钮颜色 默认为 None 未设置
/// </summary>
[Parameter]
public Color Color { get; set; }

/// <summary>
/// 获得/设置 数据源
/// </summary>
[Parameter]
[NotNull]
public IEnumerable<SelectedItem<TValue>>? Items { get; set; }

/// <summary>
/// 获得/设置 SelectedItemChanged 方法
/// </summary>
[Parameter]
public Func<TValue, Task>? OnSelectedChanged { get; set; }

/// <summary>
/// 获得/设置 数据主键标识标签 默认为 <see cref="KeyAttribute"/><code><br /></code>用于判断数据主键标签,如果模型未设置主键时可使用 <see cref="ModelEqualityComparer"/> 参数自定义判断 <code><br /></code>数据模型支持联合主键
/// </summary>
[Parameter]
[NotNull]
public Type? CustomKeyAttribute { get; set; } = typeof(KeyAttribute);

/// <summary>
/// 获得/设置 比较数据是否相同回调方法 默认为 null
/// <para>提供此回调方法时忽略 <see cref="CustomKeyAttribute"/> 属性</para>
/// </summary>
[Parameter]
public Func<TValue, TValue, bool>? ModelEqualityComparer { get; set; }

/// <summary>
/// 获得 当前选项是否被禁用
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
private bool GetDisabledState(SelectedItem<TValue> item) => IsDisabled || item.IsDisabled;

private string? GroupName => Id;

private string? ClassString => CssBuilder.Default("radio-list form-control")
.AddClass("no-border", !ShowBorder && ValidCss != "is-invalid")
.AddClass("is-vertical", IsVertical)
.AddClass(CssClass).AddClass(ValidCss)
.Build();

private string? ButtonClassString => CssBuilder.Default("radio-list btn-group")
.AddClass("disabled", IsDisabled)
.AddClass("btn-group-vertical", IsVertical)
.AddClassFromAttributes(AdditionalAttributes)
.Build();

private string? GetButtonItemClassString(SelectedItem<TValue> item) => CssBuilder.Default("btn")
.AddClass($"active bg-{Color.ToDescriptionString()}", Equals(Value, item.Value))
.Build();

/// <summary>
/// <inheritdoc/>
/// </summary>
protected override void OnParametersSet()
{
base.OnParametersSet();

if (IsButton && Color == Color.None)
{
Color = Color.Primary;
}

var t = NullableUnderlyingType ?? typeof(TValue);
if (t.IsEnum && Items == null)
{
Items = t.ToSelectList<TValue>((NullableUnderlyingType != null && IsAutoAddNullItem) ? new SelectedItem<TValue>(default, NullItemText) : null);
}

Items ??= [];

// set item active
if (Value != null)
{
var item = Items.FirstOrDefault(i => Equals(Value, i.Value));
if (item == null)
{
Value = default;
}
}
}

/// <summary>
/// 点击选择框方法
/// </summary>
private async Task OnClick(SelectedItem<TValue?> item)
{
if (!IsDisabled)
{
CurrentValue = item.Value;
if (OnSelectedChanged != null)
{
await OnSelectedChanged(Value);
}
StateHasChanged();
}
}

private CheckboxState CheckState(SelectedItem<TValue> item) => this.Equals<TValue>(Value, item.Value) ? CheckboxState.Checked : CheckboxState.UnChecked;

private RenderFragment? GetChildContent(SelectedItem<TValue> item) => ItemTemplate == null
? null
: ItemTemplate(item);

/// <summary>
/// <inheritdoc/>
/// </summary>
public bool Equals(TValue? x, TValue? y) => this.Equals<TValue>(x, y);
}
Loading

0 comments on commit 72398af

Please sign in to comment.