Skip to content

Commit

Permalink
feat(Search): add IsClearable parameter (#5296)
Browse files Browse the repository at this point in the history
* chore: 更新 OctIcon 支持 Color 参数

* doc: 更新图标示例

* chore: 更新依赖包

* feat: 增加 SearchContext 精简代码逻辑

减少级联参数

* style: 增加样式

* doc: 更新示例代码

* doc: 更新示例文档

* test: 增加单元测试

* test: 更新单元测试

* chore: bump version 9.3.1-beta07

* test: 更新单元测试

* feat: 增加 ButtonTemplate 参数

* feat: 增加 ShowClearIcon 参数

* refactor: 增加 form-control-group 节点

* style: 更新样式

* feat: 增加 PrefixButtonTemplate 参数

* refactor: 增加 PrefixButtonTemplate 逻辑

* style: 增加 bb-search-icon-input-padding-right 变量

* doc: 增加示例

* refactor: 更改 IsClearable 参数

* refactor: 调整 ButtonTemplate 位置

* doc: 增加示例代码

* doc: 更新示例

* doc: 增加文档注释

* doc: 增加注释文档多语言

* test: 更新单元测试

* refactor: 重构 DOM 结构精简样式
  • Loading branch information
ArgoZhang authored Feb 4, 2025
1 parent 15fa69e commit fff6f06
Show file tree
Hide file tree
Showing 15 changed files with 399 additions and 51 deletions.
6 changes: 3 additions & 3 deletions src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="BootstrapBlazor.AntDesignIcon" Version="9.0.1" />
<PackageReference Include="BootstrapBlazor.AntDesignIcon" Version="9.0.2" />
<PackageReference Include="BootstrapBlazor.AzureOpenAI" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.AzureTranslator" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.BaiduSpeech" Version="9.0.0" />
Expand All @@ -32,7 +32,7 @@
<PackageReference Include="BootstrapBlazor.CherryMarkdown" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.Dock" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.DockView" Version="9.0.3" />
<PackageReference Include="BootstrapBlazor.DriverJs" Version="9.0.1" />
<PackageReference Include="BootstrapBlazor.DriverJs" Version="9.0.3" />
<PackageReference Include="BootstrapBlazor.ElementIcon" Version="9.0.1" />
<PackageReference Include="BootstrapBlazor.FileViewer" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.0.2" />
Expand All @@ -48,7 +48,7 @@
<PackageReference Include="BootstrapBlazor.Mermaid" Version="9.0.3" />
<PackageReference Include="BootstrapBlazor.MindMap" Version="9.1.3" />
<PackageReference Include="BootstrapBlazor.MouseFollower" Version="9.0.1" />
<PackageReference Include="BootstrapBlazor.OctIcon" Version="9.0.1" />
<PackageReference Include="BootstrapBlazor.OctIcon" Version="9.0.2" />
<PackageReference Include="BootstrapBlazor.OnScreenKeyboard" Version="9.0.1" />
<PackageReference Include="BootstrapBlazor.PdfReader" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.Player" Version="9.0.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@typeparam TValue

<Button Text="Clear1" OnClick="OnClickClear"></Button>
<Button Text="Search1" OnClick="OnClickSearch"></Button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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.Server.Components.Components;

/// <summary>
/// SearchButtonTemplateDemo 示例组件
/// </summary>
public partial class SearchButtonTemplateDemo<TValue>
{
/// <summary>
/// 获得/设置 <see cref="SearchContext{TValue}"/> 实例"/>
/// </summary>
[Parameter, EditorRequired, NotNull]
public SearchContext<TValue>? Context { get; set; }

[Inject, NotNull]
private ToastService? ToastService { get; set; }

private async Task OnClickSearch()
{
await Context.OnSearchAsync();

await ToastService.Information("Search-ButtonTemplate", "Click Search1 Button");
}

private async Task OnClickClear()
{
await Context.OnClearAsync();

await ToastService.Information("Search-ButtonTemplate", "Click Clear1 Button");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
<Pre>&lt;link href="_content/BootstrapBlazor.AntDesignIcon/BootstrapBlazor.AntDesignIcon.bundle.scp.css" rel="stylesheet"&gt;</Pre>

<div class="mb-2">
<AntDesignIcon Category="AntDesignIconCategory.Outlined" Name="github"></AntDesignIcon>
<AntDesignIcon Category="AntDesignIconCategory.Filled" Name="left-circle"></AntDesignIcon>
<AntDesignIcon Category="AntDesignIconCategory.Outlined" Name="left-circle"></AntDesignIcon>
</div>

<Pre>&lt;AntDesignIcon Category="AntDesignIconCategory.Outlined" Name="github"&gt;&lt;/AntDesignIcon&gt;</Pre>
Expand Down
99 changes: 99 additions & 0 deletions src/BootstrapBlazor.Server/Components/Samples/Searches.razor
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,106 @@
</Search>
</div>
</div>
</DemoBlock>

<DemoBlock Title="@Localizer["SearchesIconTemplateTitle"]"
Introduction="@Localizer["SearchesIconTemplateIntro"]"
Name="IconTemplate">
<section ignore>
<p>@((MarkupString)Localizer["SearchesIconTemplateDesc"].Value)</p>
</section>
<div class="row g-3">
<div class="col-12">
<Search PlaceHolder="@Localizer["SearchesPlaceHolder"]"
OnSearch="@OnModelSearch"
IsClearable="true" ShowSearchButton="false"
ShowPrefixIcon="true" PrefixIcon="fa fa-flag">
<IconTemplate>
<i class="search-icon fa-solid fa-camera" @onclick="() => OnClickCamera(context)"></i>
</IconTemplate>
</Search>
</div>
</div>
</DemoBlock>

<DemoBlock Title="@Localizer["SearchesButtonTemplateTitle"]"
Introduction="@Localizer["SearchesButtonTemplateIntro"]"
Name="ButtonTemplate">
<section ignore>
<p>@((MarkupString)Localizer["SearchesButtonTemplateDesc"].Value)</p>
<p>@((MarkupString)Localizer["SearchesButtonTemplateDesc2"].Value)</p>
<Pre>[Parameter, EditorRequired, NotNull]
public SearchContext&lt;TValue&gt;? Context { get; set; }

[Inject, NotNull]
private ToastService? ToastService { get; set; }

private async Task OnClickSearch()
{
await Context.OnSearchAsync();

await ToastService.Information("Search-ButtonTemplate", "Click Search1 Button");
}

private async Task OnClickClear()
{
await Context.OnClearAsync();

await ToastService.Information("Search-ButtonTemplate", "Click Clear1 Button");
}</Pre>
</section>
<div class="row g-3">
<div class="col-12">
<Search PlaceHolder="@Localizer["SearchesPlaceHolder"]"
OnSearch="@OnModelSearch"
IsClearable="true"
ShowPrefixIcon="true" PrefixIcon="fa fa-flag">
<PrefixButtonTemplate>
<Button Text="Text1"></Button>
<Button Text="Text2"></Button>
</PrefixButtonTemplate>
<ButtonTemplate>
<SearchButtonTemplateDemo Context="context"></SearchButtonTemplateDemo>
</ButtonTemplate>
</Search>
</div>
</div>
</DemoBlock>

<DemoBlock Title="@Localizer["SearchesIsClearableTitle"]"
Introduction="@Localizer["SearchesIsClearableIntro"]"
Name="ButtonTemplate">
<section ignore>
<div class="row g-3">
<div class="col-12 col-sm-4">
<BootstrapInputGroup>
<BootstrapInputGroupLabel DisplayText="IsClearable"></BootstrapInputGroupLabel>
<Checkbox @bind-Value="_isClearable"></Checkbox>
</BootstrapInputGroup>
</div>
<div class="col-12 col-sm-4">
<BootstrapInputGroup>
<BootstrapInputGroupLabel DisplayText="ShowClearButton"></BootstrapInputGroupLabel>
<Checkbox @bind-Value="_showClearButton"></Checkbox>
</BootstrapInputGroup>
</div>
<div class="col-12 col-sm-4">
<BootstrapInputGroup>
<BootstrapInputGroupLabel DisplayText="ShowSearchButton"></BootstrapInputGroupLabel>
<Checkbox @bind-Value="_showSearchButton"></Checkbox>
</BootstrapInputGroup>
</div>
</div>
</section>
<div class="row g-3">
<div class="col-12 col-sm-6">
<Search PlaceHolder="@Localizer["SearchesPlaceHolder"]"
OnSearch="@OnModelSearch"
IsClearable="_isClearable" ShowClearButton="_showClearButton" ShowSearchButton="_showSearchButton"
ShowPrefixIcon="true" PrefixIcon="fa-brands fa-github">
</Search>
</div>
</div>
</DemoBlock>

<AttributeTable Items="@GetAttributes()" />
44 changes: 41 additions & 3 deletions src/BootstrapBlazor.Server/Components/Samples/Searches.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ namespace BootstrapBlazor.Server.Components.Samples;
/// </summary>
public sealed partial class Searches
{
[Inject, NotNull]
private ToastService? ToastService { get; set; }

[NotNull]
private ConsoleLogger? Logger { get; set; }

Expand Down Expand Up @@ -78,6 +81,17 @@ private async Task<IEnumerable<Foo>> OnSearchFoo(string searchText)
: Enumerable.Range(1, 10).Select(i => LocalizerFoo["Foo.Name", $"{i:d4}"].Value).ToList();
}

private async Task OnClickCamera(SearchContext<string?> context)
{
await Task.Delay(10);

await ToastService.Information("Custom IconTemplate", "Click custom icon");
}

private bool _isClearable = true;
private bool _showClearButton = false;
private bool _showSearchButton = false;

/// <summary>
/// 获得属性方法
/// </summary>
Expand All @@ -93,11 +107,35 @@ private AttributeItem[] GetAttributes() =>
},
new()
{
Name="SearchButtonLoadingIcon",
Description = Localizer["SearchesButtonLoadingIcon"],
Name="IsClearable",
Description = Localizer["SearchesIsClearable"],
Type = "bool",
ValueList = "true|false",
DefaultValue = "false"
},
new()
{
Name="ClearIcon",
Description = Localizer["SearchesClearIcon"],
Type = "string",
ValueList = " — ",
DefaultValue = "fa-fw fa-spin fa-solid fa-spinner"
DefaultValue = " — "
},
new()
{
Name="PrefixButtonTemplate",
Description = Localizer["SearchesPrefixButtonTemplate"],
Type = "RenderFragment",
ValueList = " — ",
DefaultValue = " — "
},
new()
{
Name="ButtonTemplate",
Description = Localizer["SearchesButtonTemplate"],
Type = "RenderFragment",
ValueList = " — ",
DefaultValue = " — "
},
new() {
Name = "ClearButtonIcon",
Expand Down
15 changes: 14 additions & 1 deletion src/BootstrapBlazor.Server/Locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -4226,7 +4226,20 @@
"SearchesItemTemplateIntro": "By setting <code>ItemTemplate</code> and matching generic data, you can achieve any desired effect. In this example, by searching for any keyword, the backend calls any third-party search results and displays them. After selecting the search item, you can handle it yourself through the <code>OnSelectedItemChanged</code> callback method",
"SearchesShowPrefixIconTitle": "ShowPrefixIcon",
"SearchesShowPrefixIconIntro": "Control whether to show the prefix icon by setting the <code>ShowPrefixIcon</code> parameter",
"SearchesShowPrefixIconDescription": "You can customize the prefix through <code>PrefixIconTemplate</code>. In this example, the <code>Svg</code> icon is used through the prefix template."
"SearchesShowPrefixIconDescription": "You can customize the prefix through <code>PrefixIconTemplate</code>. In this example, the <code>Svg</code> icon is used through the prefix template.",
"SearchesButtonTemplateTitle": "Button Template",
"SearchesButtonTemplateIntro": "Customize the buttons displayed by the component by setting <code>ButtonTemplate</code>",
"SearchesButtonTemplateDesc": "Customize the buttons displayed in front of the component by setting <code>PrefixButtonTemplate</code>",
"SearchesButtonTemplateDesc2": "In a custom template, you can call the <code>OnClear</code> <code>OnSearch</code> method inside the <code>Search</code> component with the context.",
"SearchesIsClearableTitle": "IsClearable",
"SearchesIsClearableIntro": "Display the clear icon by setting <code>IsClearable=\"true\"</code>",
"SearchesIsClearable": "Whether to display the clear icon",
"SearchesClearIcon": "Clear Icon",
"SearchesPrefixButtonTemplate": "Prefix button template",
"SearchesButtonTemplate": "Button template",
"SearchesIconTemplateTitle": "Icon Template",
"SearchesIconTemplateIntro": "Customize the icon displayed by the component by setting <code>IconTemplate</code>",
"SearchesIconTemplateDesc": "The search component context <code>SearchContext&lt;string&gt;</code> provides the <code>OnClear</code> <code>OnSearch</code> methods within the component"
},
"BootstrapBlazor.Server.Components.Samples.Titles": {
"Title": "Title",
Expand Down
15 changes: 14 additions & 1 deletion src/BootstrapBlazor.Server/Locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -4226,7 +4226,20 @@
"SearchesItemTemplateIntro": "通过设置 <code>ItemTemplate</code> 配合泛型数据可以做出自己想要的任何效果,本例中通过搜索任意关键字,后台调用任意第三方搜索结果并且进行展示,选中搜索项后通过 <code>OnSelectedItemChanged</code> 回调方法可以自行处理",
"SearchesShowPrefixIconTitle": "显示前缀图标",
"SearchesShowPrefixIconIntro": "通过设置 <code>ShowPrefixIcon</code> 参数控制是否显示前缀图标",
"SearchesShowPrefixIconDescription": "可以通过 <code>PrefixIconTemplate</code> 自定义前缀,本例中通过前缀模板使用 <code>Svg</code> 图标"
"SearchesShowPrefixIconDescription": "可以通过 <code>PrefixIconTemplate</code> 自定义前缀,本例中通过前缀模板使用 <code>Svg</code> 图标",
"SearchesButtonTemplateTitle": "按钮模板",
"SearchesButtonTemplateIntro": "通过设置 <code>ButtonTemplate</code> 自定义组件显示的按钮",
"SearchesButtonTemplateDesc": "通过设置 <code>PrefixButtonTemplate</code> 自定义组件前置显示的按钮",
"SearchesButtonTemplateDesc2": "在自定义模板中可以通过关联参数调用 <code>Search</code> 组件内部的 <code>OnClear</code> <code>OnSearch</code> 方法",
"SearchesIsClearableTitle": "IsClearable",
"SearchesIsClearableIntro": "通过设置 <code>IsClearable=\"true\"</code> 显示清空小图标",
"SearchesIsClearable": "是否显示清空小按钮",
"SearchesClearIcon": "清空图标",
"SearchesPrefixButtonTemplate": "前置按钮模板",
"SearchesButtonTemplate": "按钮模板",
"SearchesIconTemplateTitle": "图标模板",
"SearchesIconTemplateIntro": "通过设置 <code>IconTemplate</code> 自定义组件显示的图标",
"SearchesIconTemplateDesc": "搜索组件上下文 <code>SearchContext&lt;string&gt;</code> 提供了组件内部的 <code>OnClear</code> <code>OnSearch</code> 方法"
},
"BootstrapBlazor.Server.Components.Samples.Titles": {
"Title": "Title 网站标题",
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.3.1-beta06</Version>
<Version>9.3.1-beta07</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
64 changes: 42 additions & 22 deletions src/BootstrapBlazor/Components/Search/Search.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,48 @@

<div @attributes="@AdditionalAttributes" class="@ClassString" id="@Id">
<div class="input-group">
<input @attributes="AdditionalAttributes" id="@InputId" class="@ClassName" autocomplete="off" type="text"
data-bs-toggle="@ToggleString" data-bs-placement="@PlacementString"
data-bs-offset="@OffsetString" data-bs-custom-class="@CustomClassString"
data-bb-auto-dropdown-focus="@ShowDropdownListOnFocusString"
data-bb-skip-esc="@SkipEscString" data-bb-skip-enter="@SkipEnterString"
data-bb-scroll-behavior="@ScrollIntoViewBehaviorString"
data-bb-input="@UseInputString"
value="@_displayText"
placeholder="@PlaceHolder" disabled="@Disabled" @ref="FocusElement" />
@if (PrefixButtonTemplate != null)
{
@PrefixButtonTemplate(_context)
}
<div class="form-control-group form-control">
@if (ShowPrefixIcon)
{
<div class="search-prefix-icon">
@if (PrefixIconTemplate != null)
{
@PrefixIconTemplate(_context)
}
else
{
<i class="@PrefixIcon"></i>
}
</div>
}
<input id="@InputId" class="search-input" autocomplete="off" type="text"
data-bs-toggle="@ToggleString" data-bs-placement="@PlacementString"
data-bs-offset="@OffsetString" data-bs-custom-class="@CustomClassString"
data-bb-auto-dropdown-focus="@ShowDropdownListOnFocusString"
data-bb-skip-esc="@SkipEscString" data-bb-skip-enter="@SkipEnterString"
data-bb-scroll-behavior="@ScrollIntoViewBehaviorString"
data-bb-input="@UseInputString"
value="@_displayText"
placeholder="@PlaceHolder" disabled="@Disabled" @ref="FocusElement" />
@if (IsClearable)
{
<div class="search-icon search-clear-icon">
<i class="@ClearIcon" @onclick="OnClearClick" aria-label="Clear"></i>
</div>
}
@if (IconTemplate != null)
{
@IconTemplate(_context)
}
</div>
@if (ButtonTemplate != null)
{
@ButtonTemplate(_context)
}
@if (ShowClearButton)
{
<Button Color="ClearButtonColor" Text="@ClearButtonText" Icon="@ClearButtonIcon" OnClick="OnClearClick" aria-label="Clear"></Button>
Expand All @@ -22,19 +55,6 @@
<Button Color="SearchButtonColor" Text="@SearchButtonText" Icon="@ButtonIcon" OnClick="OnSearchClick" aria-label="Search"></Button>
}
</div>
@if (ShowPrefixIcon)
{
<div class="search-prefix-icon">
@if (PrefixIconTemplate != null)
{
@PrefixIconTemplate
}
else
{
<i class="@PrefixIcon"></i>
}
</div>
}
<ul class="dropdown-menu">
@foreach (var item in _filterItems)
{
Expand Down
Loading

0 comments on commit fff6f06

Please sign in to comment.