merge master to feature

This commit is contained in:
James Yeung 2022-08-21 22:53:33 +08:00
commit 3ac7701da4
86 changed files with 2038 additions and 1228 deletions

View File

@ -14,6 +14,34 @@ timeline: true
- Major version release is not included in this schedule for breaking change and new features. - Major version release is not included in this schedule for breaking change and new features.
--- ---
### 0.11.0
`2022-06-16`
🌈Every cloud has a silver lining.
- Table
- 🔥 support for Table virtualization [#2143](https://github.com/ant-design-blazor/ant-design-blazor/pull/2143) [@anranruye](https://github.com/anranruye)
- 🔥 Support to control/restore table filter/sorter state using existing QueryModel [#2129](https://github.com/ant-design-blazor/ant-design-blazor/pull/2129) [@AnaNikolasevic](https://github.com/AnaNikolasevic)
- 🆕 support setting table scrollbar width using `ScrollBarWidth` parameter. [#2451](https://github.com/ant-design-blazor/ant-design-blazor/pull/2451) [@ElderJames](https://github.com/ElderJames)
- 🆕 support for using built-in logic when defining the PaginationTemplate. [#2220](https://github.com/ant-design-blazor/ant-design-blazor/pull/2220) [@anranruye](https://github.com/anranruye)
- 🛠 make Responsive default to false (with a breaking change). [#2419](https://github.com/ant-design-blazor/ant-design-blazor/pull/2419) [@ElderJames](https://github.com/ElderJames)
- 🛠 Use Small size Pagination to fit compact Table [#2246](https://github.com/ant-design-blazor/ant-design-blazor/pull/2246) [@anranruye](https://github.com/anranruye)
- TreeSelect
- 🐞 Fixed TreeSelect expressions and selection [#2507](https://github.com/ant-design-blazor/ant-design-blazor/pull/2507) [@ElderJames](https://github.com/ElderJames)
- 🐞 Fixed TreeSelect binding default where it did not show selected items [#2134](https://github.com/ant-design-blazor/ant-design-blazor/pull/2134) [@gmij](https://github.com/gmij)
- 🆕 Add Upload support for incorporating build-in InputFile [#2443](https://github.com/ant-design-blazor/ant-design-blazor/pull/2443) [@ElderJames](https://github.com/ElderJames)
- 🆕 Add Select search debounce. [#2275](https://github.com/ant-design-blazor/ant-design-blazor/pull/2275) [@tompru](https://github.com/tompru)
- 🆕 Component library added .net 6 target framework [#2484](https://github.com/ant-design-blazor/ant-design-blazor/pull/2484) [@ElderJames](https://github.com/ElderJames)
- ⌨️ Add Form Feedback Icon when Invalid [#2418](https://github.com/ant-design-blazor/ant-design-blazor/pull/2418) [@bweissronin](https://github.com/bweissronin)
- ⌨️ Add Checkbox supports trigger check when clicking label [#2296](https://github.com/ant-design-blazor/ant-design-blazor/pull/2296) [@bweissronin](https://github.com/bweissronin)
- ⌨️ Add Icon `Alt` Parameter to set the alt attribute that pairs with role="img" [#2302](https://github.com/ant-design-blazor/ant-design-blazor/pull/2302) [@bweissronin](https://github.com/bweissronin)
- ⌨️ Add Button `AriaLabel` Parameter [#2278](https://github.com/ant-design-blazor/ant-design-blazor/pull/2278) [@bweissronin](https://github.com/bweissronin)
- 🐞 Fixed Tree incorrect checking during initialization. [#2506](https://github.com/ant-design-blazor/ant-design-blazor/pull/2506) [@ElderJames](https://github.com/ElderJames)
- 🐞 Fixed DatePicker that week selection issue when unable to click date selection. [#2463](https://github.com/ant-design-blazor/ant-design-blazor/pull/2463) [@WhyILoveSpringRoll](https://github.com/WhyILoveSpringRoll)
- 📖 docs(faq): add CSS isolation explanation. [#2158](https://github.com/ant-design-blazor/ant-design-blazor/pull/2158) [@dennisrahmen](https://github.com/dennisrahmen)
### 0.10.7 ### 0.10.7

View File

@ -14,6 +14,39 @@ timeline: true
- 主版本号:含有破坏性更新和新特性,不在发布周期内。 - 主版本号:含有破坏性更新和新特性,不在发布周期内。
--- ---
### 0.11.0
`2022-06-16`
🌈守得云开见月明~
- Table
- 🔥 支持虚拟化[#2143](https://github.com/ant-design-blazor/ant-design-blazor/pull/2143) [@anranruye](https://github.com/anranruye)
- 🔥 支持使用已有的 QueryModel 控制/恢复表格筛选排序状态[#2129](https://github.com/ant-design-blazor/ant-design-blazor/pull/2129) [@AnaNikolasevic](https://github.com/AnaNikolasevic)
- 🆕 支持用 `ScrollBarWidth` 属性来设置滚动条的宽度。[#2451](https://github.com/ant-design-blazor/ant-design-blazor/pull/2451) [@ElderJames](https://github.com/ElderJames)
- 🆕 允许在定义 `PaginationTemplate` 时使用组件内置逻辑。[#2220](https://github.com/ant-design-blazor/ant-design-blazor/pull/2220) [@anranruye](https://github.com/anranruye)
- 🛠 修改 Responsive 属性默认值为false需要响应式样式时需要设为true。[#2419](https://github.com/ant-design-blazor/ant-design-blazor/pull/2419) [@ElderJames](https://github.com/ElderJames)
- 🛠 使用 Small 大小的Pagination来适配紧凑型Table[#2246](https://github.com/ant-design-blazor/ant-design-blazor/pull/2246) [@anranruye](https://github.com/anranruye)
- 🆕 增加 Upload 支持结合原生 InputFile 组件。[#2443](https://github.com/ant-design-blazor/ant-design-blazor/pull/2443) [@ElderJames](https://github.com/ElderJames)
- 🆕 增加 Select 搜索框防抖延时绑定。[#2275](https://github.com/ant-design-blazor/ant-design-blazor/pull/2275) [@tompru](https://github.com/tompru)
- 🆕 组件库增加 .NET 6 目标框架。[#2484](https://github.com/ant-design-blazor/ant-design-blazor/pull/2484) [@ElderJames](https://github.com/ElderJames)
- TreeSelect
- 🐞 修复表达式和选择功能。[#2507](https://github.com/ant-design-blazor/ant-design-blazor/pull/2507) [@ElderJames](https://github.com/ElderJames)
- 🐞 修复绑定默认值时,没有显示选中项。[#2134](https://github.com/ant-design-blazor/ant-design-blazor/pull/2134) [@gmij](https://github.com/gmij)
- 🐞 修复 DatePicker 点击日期时,不能选中周的问题[#2463](https://github.com/ant-design-blazor/ant-design-blazor/pull/2463) [@WhyILoveSpringRoll](https://github.com/WhyILoveSpringRoll)
- 🐞 修复 Tree 初始化时 checkbox 不能正常选中的问题。[#2506](https://github.com/ant-design-blazor/ant-design-blazor/pull/2506) [@ElderJames](https://github.com/ElderJames)
- ⌨️ 增加 Form 支持当验证失败时显示Feedback图标。[#2418](https://github.com/ant-design-blazor/ant-design-blazor/pull/2418) [@bweissronin](https://github.com/bweissronin)
- ⌨️ 增加 Checkbox 支持点击标签时触发勾选[#2296](https://github.com/ant-design-blazor/ant-design-blazor/pull/2296) [@bweissronin](https://github.com/bweissronin)
- ⌨️ 增加 Icon Alt 属性,与原来的`role="img"` 搭配[#2302](https://github.com/ant-design-blazor/ant-design-blazor/pull/2302) [@bweissronin](https://github.com/bweissronin)
- ⌨️ 增加 Button AriaLabel 属性[#2278](https://github.com/ant-design-blazor/ant-design-blazor/pull/2278) [@bweissronin](https://github.com/bweissronin)
- 📖 常用问答增加 CSS 隔离的组件样式修改方式[#2158](https://github.com/ant-design-blazor/ant-design-blazor/pull/2158) [@dennisrahmen](https://github.com/dennisrahmen)
### 0.10.7 ### 0.10.7
`2022-05-22` `2022-05-22`

View File

@ -1,6 +1,6 @@
<p align="center"> <p align="center">
<a href="https://yangshunjie.com/ant-design-blazor/"> <a href="https://yangshunjie.com/ant-design-blazor/">
<img src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/logo.svg?sanitize=true"> <img src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/master/logo.svg?sanitize=true">
</a> </a>
</p> </p>
@ -52,7 +52,7 @@ WebAssembly 静态托管页面示例
- 可直接运行在 [.NET MAUI](https://dotnet.microsoft.com/zh-cn/apps/maui?WT.mc_id=DT-MVP-5003987)、[WPF](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/wpf?view=aspnetcore-6.0&WT.mc_id=DT-MVP-5003987)、[Windows Forms](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/windows-forms?view=aspnetcore-6.0) 等 Blazor 混合客户端环境中。 - 可直接运行在 [.NET MAUI](https://dotnet.microsoft.com/zh-cn/apps/maui?WT.mc_id=DT-MVP-5003987)、[WPF](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/wpf?view=aspnetcore-6.0&WT.mc_id=DT-MVP-5003987)、[Windows Forms](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/windows-forms?view=aspnetcore-6.0) 等 Blazor 混合客户端环境中。
- 可直接运行在 [Electron](http://electron.atom.io/) 等基于 Web 标准的环境上。 - 可直接运行在 [Electron](http://electron.atom.io/) 等基于 Web 标准的环境上。
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br> Edge / IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br> Edge / IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron |
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| Edge 16 / IE 11† | 522 | 57 | 11 | 44 | Chromium 57 | | Edge 16 / IE 11† | 522 | 57 | 11 | 44 | Chromium 57 |

View File

@ -1,6 +1,6 @@
<p align="center"> <p align="center">
<a href="https://yangshunjie.com/ant-design-blazor/"> <a href="https://yangshunjie.com/ant-design-blazor/">
<img src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/logo.svg?sanitize=true"> <img src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/master/logo.svg?sanitize=true">
</a> </a>
</p> </p>
@ -51,7 +51,7 @@ WebAssembly static hosting examples:
- Run directly on [.NET MAUI](https://dotnet.microsoft.com/zh-cn/apps/maui?WT.mc_id=DT-MVP-5003987) / [WPF](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/wpf?view=aspnetcore-6.0&WT.mc_id=DT-MVP-5003987) / [Windows Forms](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/windows-forms?view=aspnetcore-6.0) and other Blazor Hybrid workloads. - Run directly on [.NET MAUI](https://dotnet.microsoft.com/zh-cn/apps/maui?WT.mc_id=DT-MVP-5003987) / [WPF](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/wpf?view=aspnetcore-6.0&WT.mc_id=DT-MVP-5003987) / [Windows Forms](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/windows-forms?view=aspnetcore-6.0) and other Blazor Hybrid workloads.
- Run directly on [Electron](http://electron.atom.io/) and other Web standards-based environments. - Run directly on [Electron](http://electron.atom.io/) and other Web standards-based environments.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br> Edge / IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br> Edge / IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron |
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| Edge 16 / IE 11† | 522 | 57 | 11 | 44 | Chromium 57 | | Edge 16 / IE 11† | 522 | 57 | 11 | 44 | Chromium 57 |
@ -166,7 +166,7 @@ Options for the template
- Clone to local development - Clone to local development
```bash ```bash
$ git clone git@github.com:ant-design-blazor/ant-design-blazor.git $ git clone https://github.com/ant-design-blazor/ant-design-blazor.git
$ cd ant-design-blazor $ cd ant-design-blazor
$ npm install $ npm install
$ dotnet build ./site/AntDesign.Docs.Build/AntDesign.Docs.Build.csproj $ dotnet build ./site/AntDesign.Docs.Build/AntDesign.Docs.Build.csproj
@ -221,7 +221,7 @@ If you encounter any problems in the process, feel free to ask for help via foll
<details> <details>
<summary>Scan QR Code with DingTalk</summary> <summary>Scan QR Code with DingTalk</summary>
<img src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/docs/assets/dingtalk.jpg" width="300"> <img src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/master/docs/assets/dingtalk.jpg" width="300">
</details> </details>
## Code of Conduct ## Code of Conduct

View File

@ -121,6 +121,7 @@ namespace AntDesign
{ {
base.OnValueChange(value); base.OnValueChange(value);
RefreshNodeValue(value); RefreshNodeValue(value);
RefreshDisplayText();
} }
/// <summary> /// <summary>
@ -178,13 +179,16 @@ namespace AntDesign
/// <summary> /// <summary>
/// 清除已选择项 /// 清除已选择项
/// </summary> /// </summary>
private void ClearSelected() private async Task ClearSelected()
{ {
_selectedNodes.Clear(); _selectedNodes.Clear();
_hoverSelectedNodes.Clear(); _hoverSelectedNodes.Clear();
_displayText = string.Empty; _displayText = string.Empty;
SetValue(string.Empty); SetValue(string.Empty);
_dropdownOpened = false; _dropdownOpened = false;
_searchValue = string.Empty;
await this.FocusAsync(_inputRef);
} }
/// <summary> /// <summary>

View File

@ -25,15 +25,58 @@ namespace AntDesign
} }
} }
/// <summary>
/// <para>
/// 是否显示右上角的关闭按钮
/// </para>
/// <para>
/// Whether a close (x) button is visible on top right of the Drawer dialog or not.
/// </para>
/// </summary>
[Parameter] [Parameter]
public bool Closable { get; set; } = true; public bool Closable { get; set; } = true;
/// <summary>
/// <para>
/// 点击蒙层是否允许关闭
/// </para>
/// <para>
/// Clicking on the mask (area outside the Drawer) to close the Drawer or not.
/// </para>
/// </summary>
[Parameter] [Parameter]
public bool MaskClosable { get; set; } = true; public bool MaskClosable { get; set; } = true;
/// <summary>
/// <para>
/// 是否显示蒙层
/// </para>
/// <para>
/// Whether to show mask or not.
/// </para>
/// </summary>
[Parameter] [Parameter]
public bool Mask { get; set; } = true; public bool Mask { get; set; } = true;
/// <summary>
/// <para>
/// 蒙层样式
/// </para>
/// <para>
/// Style for Drawer's mask element.
/// </para>
/// </summary>
[Parameter]
public string MaskStyle { get; set; }
/// <summary>
/// <para>
/// 是否支持键盘 esc 关闭
/// </para>
/// <para>
/// Whether to support keyboard esc off
/// </para>
/// </summary>
[Parameter] [Parameter]
public bool Keyboard { get; set; } = true; public bool Keyboard { get; set; } = true;
@ -43,6 +86,14 @@ namespace AntDesign
private OneOf<RenderFragment, string> _title; private OneOf<RenderFragment, string> _title;
/// <summary>
/// <para>
/// 标题
/// </para>
/// <para>
/// The title for Drawer.
/// </para>
/// </summary>
[Parameter] [Parameter]
public OneOf<RenderFragment, string> Title public OneOf<RenderFragment, string> Title
{ {
@ -63,20 +114,68 @@ namespace AntDesign
} }
/// <summary> /// <summary>
/// "left" | "right" | "top" | "bottom" /// <para>
/// Drawer 的位置,字符串, "left" | "right" | "top" | "bottom"
/// </para>
/// <para>
/// The placement of the Drawer, option could be left, top, right, bottom
/// </para>
/// </summary> /// </summary>
[Parameter] public string Placement { get; set; } = "right"; [Parameter]
public string Placement { get; set; } = "right";
[Parameter] public string MaskStyle { get; set; } /// <summary>
/// <para>
/// Drawer body 样式
/// </para>
/// <para>
/// Body style for modal body element. Such as height, padding etc.
/// </para>
/// </summary>
[Parameter]
public string BodyStyle { get; set; }
[Parameter] public string BodyStyle { get; set; } /// <summary>
/// <para>
/// Drawer对话框外层容器的类名
/// </para>
/// <para>
/// The class name of the container of the Drawer dialog.
/// </para>
/// </summary>
[Parameter]
public string WrapClassName { get; set; }
[Parameter] public string WrapClassName { get; set; } /// <summary>
/// <para>
/// 宽度,仅当 <see cref="Placement"/> 为 "left" 或 "right" 时生效
/// </para>
/// <para>
/// Width of the Drawer dialog, only when placement is 'left' or 'right'.
/// </para>
/// </summary>
[Parameter]
public int Width { get; set; } = 256;
[Parameter] public int Width { get; set; } = 256; /// <summary>
/// <para>
[Parameter] public int Height { get; set; } = 256; /// 高度,仅当 <see cref="Placement"/> 为 "top" 或 "bottom" 时生效
/// </para>
/// <para>
/// Height of the Drawer dialog, only when placement is 'top' or 'bottom'.
/// </para>
/// </summary>
[Parameter]
public int Height { get; set; } = 256;
/// <summary>
/// <para>
/// 设置 Drawer 的 z-index
/// </para>
/// <para>
/// The z-index of the Drawer.
/// </para>
/// </summary>
[Parameter] [Parameter]
public int ZIndex public int ZIndex
{ {
@ -93,10 +192,36 @@ namespace AntDesign
private string InnerZIndexStyle => (_status.IsOpen() || _status == ComponentStatus.Closing) ? _zIndexStyle : "z-index:-9999;"; private string InnerZIndexStyle => (_status.IsOpen() || _status == ComponentStatus.Closing) ? _zIndexStyle : "z-index:-9999;";
[Parameter] public int OffsetX { get; set; } = 0; /// <summary>
/// <para>
/// X 轴方向的偏移量,只在方向为 'left'或'right' 时生效.
/// </para>
/// <para>
/// The the X coordinate offset(px), only when placement is 'left' or 'right'.
/// </para>
/// </summary>
[Parameter]
public int OffsetX { get; set; } = 0;
[Parameter] public int OffsetY { get; set; } = 0; /// <summary>
/// <para>
/// Y 轴方向的偏移量,只在方向为 'top'或'bottom' 时生效
/// </para>
/// <para>
/// The the Y coordinate offset(px), only when placement is 'top' or 'bottom'.
/// </para>
/// </summary>
[Parameter]
public int OffsetY { get; set; } = 0;
/// <summary>
/// <para>
/// Drawer 是否可见
/// </para>
/// <para>
/// Whether the Drawer dialog is visible or not.
/// </para>
/// </summary>
[Parameter] [Parameter]
public bool Visible public bool Visible
{ {
@ -115,10 +240,30 @@ namespace AntDesign
} }
} }
[Parameter] public EventCallback OnClose { get; set; } /// <summary>
[Parameter] public RenderFragment Handler { get; set; } /// <para>
/// 在 Drawer 打开前的回调事件
/// </para>
/// <para>
/// Specify a callback that will be called before drawer displayed
/// </para>
/// </summary>
[Parameter]
public Func<Task> OnOpen { get; set; }
#endregion /// <summary>
/// <para>
/// 在 关闭 前的回调事件,应当在 OnClose 将 <see cref="Visible"/> 设置为false
/// </para>
/// <para>
/// Specify a callback that will be called when a user clicks mask, close button or Cancel button.
/// </para>
/// </summary>
[Parameter]
public EventCallback OnClose { get; set; }
[Parameter]
public RenderFragment Handler { get; set; }
private OneOf<RenderFragment, string> _content; private OneOf<RenderFragment, string> _content;
@ -126,6 +271,8 @@ namespace AntDesign
private RenderFragment ContentTemplate { get; set; } private RenderFragment ContentTemplate { get; set; }
#endregion
private ComponentStatus _status; private ComponentStatus _status;
private bool _hasInvokeClosed; private bool _hasInvokeClosed;
private bool _isOpen = default; private bool _isOpen = default;
@ -257,6 +404,12 @@ namespace AntDesign
case ComponentStatus.Opening: case ComponentStatus.Opening:
{ {
_status = ComponentStatus.Opened; _status = ComponentStatus.Opened;
if (OnOpen != null)
{
await OnOpen.Invoke();
}
_hasInvokeClosed = false; _hasInvokeClosed = false;
if (string.IsNullOrWhiteSpace(Style)) if (string.IsNullOrWhiteSpace(Style))
{ {

View File

@ -22,6 +22,7 @@
OffsetX="@drawerConfig.OffsetX" OffsetX="@drawerConfig.OffsetX"
OffsetY="@drawerConfig.OffsetY" OffsetY="@drawerConfig.OffsetY"
Visible="@drawerConfig.Visible" Visible="@drawerConfig.Visible"
OnOpen="@drawerRef.OnOpen"
OnClose="@drawerRef.CloseAsync"> OnClose="@drawerRef.CloseAsync">
@drawerConfig.ChildContent @drawerConfig.ChildContent
</Drawer> </Drawer>

View File

@ -50,8 +50,6 @@ namespace AntDesign
public override async Task OpenAsync() public override async Task OpenAsync()
{ {
await _service.OpenAsync(this); await _service.OpenAsync(this);
if (OnOpen != null)
await OnOpen.Invoke();
} }
/// <summary> /// <summary>

View File

@ -1,29 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Components.Web;
namespace AntDesign
{
public class DrawerClosingEventArgs
{
private bool _rejected;
public DrawerClosingEventArgs() { }
public DrawerClosingEventArgs(bool reject)
{
_rejected = reject;
}
internal bool Rejected { get => _rejected; }
/// <summary>
/// Reject to close
/// </summary>
public void Reject()
{
_rejected = true;
}
}
}

View File

@ -0,0 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
namespace AntDesign;
public class DrawerOpenEventArgs
{
/// <summary>
/// 获取或设置一个值,该值指示是否应取消事件。
/// 返回结果: true 如果应取消事件;否则为 false。
/// Gets or sets a value indicating whether the event should be cancelled.
/// Return result: true if the event should be cancelled; otherwise false.
/// </summary>
public bool Cancel { get; set; }
}

View File

@ -30,7 +30,7 @@ namespace AntDesign
{ {
_step = value; _step = value;
NumberFormatInfo nfi = CultureInfo.NumberFormat; NumberFormatInfo nfi = CultureInfo.NumberFormat;
var stepStr = _step.ToString(); var stepStr = Convert.ToDecimal(_step).ToString(nfi);
if (string.IsNullOrEmpty(_format)) if (string.IsNullOrEmpty(_format))
{ {
_format = string.Join('.', stepStr.Split(nfi.NumberDecimalSeparator).Select(n => new string('0', n.Length))); _format = string.Join('.', stepStr.Split(nfi.NumberDecimalSeparator).Select(n => new string('0', n.Length)));

View File

@ -333,6 +333,7 @@ namespace AntDesign
{ {
if (CurrentValueAsString != args?.Value?.ToString()) if (CurrentValueAsString != args?.Value?.ToString())
{ {
CurrentValueAsString = args?.Value?.ToString();
if (OnChange.HasDelegate) if (OnChange.HasDelegate)
{ {
await OnChange.InvokeAsync(Value); await OnChange.InvokeAsync(Value);
@ -636,11 +637,12 @@ namespace AntDesign
} }
// onchange 和 onblur 事件会导致点击 OnSearch 按钮时不触发 Click 事件,暂时取消这两个事件 // onchange 和 onblur 事件会导致点击 OnSearch 按钮时不触发 Click 事件,暂时取消这两个事件
if (!IgnoreOnChangeAndBlur) //2022-8-3 去掉if后search也能正常工作
{ //if (!IgnoreOnChangeAndBlur)
//{
builder.AddAttribute(70, "onchange", CallbackFactory.Create(this, OnChangeAsync)); builder.AddAttribute(70, "onchange", CallbackFactory.Create(this, OnChangeAsync));
builder.AddAttribute(71, "onblur", CallbackFactory.Create(this, OnBlurAsync)); builder.AddAttribute(71, "onblur", CallbackFactory.Create(this, OnBlurAsync));
} //}
builder.AddAttribute(72, "onkeypress", CallbackFactory.Create(this, OnKeyPressAsync)); builder.AddAttribute(72, "onkeypress", CallbackFactory.Create(this, OnKeyPressAsync));
builder.AddAttribute(73, "onkeydown", CallbackFactory.Create(this, OnkeyDownAsync)); builder.AddAttribute(73, "onkeydown", CallbackFactory.Create(this, OnkeyDownAsync));

View File

@ -44,6 +44,9 @@ namespace AntDesign
} }
} }
[Parameter]
public EventCallback<bool> CollapsedChanged { get; set; }
[Parameter] [Parameter]
public EventCallback<bool> OnCollapse { get; set; } public EventCallback<bool> OnCollapse { get; set; }
@ -132,6 +135,11 @@ namespace AntDesign
{ {
OnCollapse.InvokeAsync(_isCollapsed); OnCollapse.InvokeAsync(_isCollapsed);
} }
if (CollapsedChanged.HasDelegate)
{
CollapsedChanged.InvokeAsync(_isCollapsed);
}
} }
private void OptimizeSize(decimal windowWidth) private void OptimizeSize(decimal windowWidth)
@ -165,6 +173,11 @@ namespace AntDesign
{ {
OnCollapse.InvokeAsync(_isCollapsed); OnCollapse.InvokeAsync(_isCollapsed);
} }
if (CollapsedChanged.HasDelegate)
{
CollapsedChanged.InvokeAsync(_isCollapsed);
}
} }
StateHasChanged(); StateHasChanged();

View File

@ -312,6 +312,21 @@ namespace AntDesign
return style; return style;
} }
/// <summary>
/// clear ant-model enter class, which will disable user-select.
/// more details see style/mixins/modal-mask.less
/// </summary>
/// <returns></returns>
internal async Task CleanShowAnimationAsync()
{
var animationTimeMs = 300;
await Task.Delay(animationTimeMs);
_maskAnimationClsName = "";
_modalAnimationClsName = "";
await InvokeStateHasChangedAsync();
}
/// <summary> /// <summary>
/// Hide Dialog through animation /// Hide Dialog through animation
/// </summary> /// </summary>

View File

@ -102,6 +102,7 @@ namespace AntDesign
_hideDone = false; _hideDone = false;
_hasDestroy = false; _hasDestroy = false;
await _dialog.CleanShowAnimationAsync();
if (OnAfterShow.HasDelegate) if (OnAfterShow.HasDelegate)
{ {
await OnAfterShow.InvokeAsync(null); await OnAfterShow.InvokeAsync(null);

View File

@ -6,7 +6,7 @@ namespace AntDesign
{ {
public sealed class ModalAnimation public sealed class ModalAnimation
{ {
public const string ModalEnter = " ant-zoom-enter ant-zoom-enter-active ant-zoom-enter"; public const string ModalEnter = " ant-zoom-enter ant-zoom-enter-active ant-zoom";
public const string ModalLeave = " ant-zoom-leave ant-zoom-leave-active ant-zoom"; public const string ModalLeave = " ant-zoom-leave ant-zoom-leave-active ant-zoom";
public const string MaskEnter = " ant-fade-enter ant-fade-enter-active ant-fade"; public const string MaskEnter = " ant-fade-enter ant-fade-enter-active ant-fade";

View File

@ -209,6 +209,7 @@
Page="@key" Page="@key"
Active="@(_current == key)" Active="@(_current == key)"
ShowTitle="ShowTitle" ShowTitle="ShowTitle"
Class=""
ItemRender="@ItemRender"/> ItemRender="@ItemRender"/>
); );
} }
@ -239,7 +240,7 @@
Page="@right" Page="@right"
Active="@(_current == right)" Active="@(_current == right)"
ShowTitle="ShowTitle" ShowTitle="ShowTitle"
Class="@($"{PrefixCls}-item-after-jump-prev")" Class="@($"{PrefixCls}-item-before-jump-next")"
ItemRender="@ItemRender"/>; ItemRender="@ItemRender"/>;
pagerList.AddLast(jumpNext); pagerList.AddLast(jumpNext);
} }

View File

@ -46,7 +46,6 @@
var prefixCls = $"{RootPrefixCls}-item"; var prefixCls = $"{RootPrefixCls}-item";
ClassMapper.Add(prefixCls).Add($"{prefixCls}-{Page}") ClassMapper.Add(prefixCls).Add($"{prefixCls}-{Page}")
.If($"{prefixCls}-active", () => Active) .If($"{prefixCls}-active", () => Active)
.If(Class, () => !string.IsNullOrWhiteSpace(Class))
.If($"{prefixCls}-disabled", () => Page == 0); .If($"{prefixCls}-disabled", () => Page == 0);
base.OnInitialized(); base.OnInitialized();

View File

@ -737,8 +737,8 @@ namespace AntDesign
{ {
if (!updateSelectOption.IsSelected) if (!updateSelectOption.IsSelected)
{ {
updateSelectOption.IsSelected = isSelected; //updateSelectOption.IsSelected = isSelected;
SelectedOptionItems.Add(updateSelectOption); //SelectedOptionItems.Add(updateSelectOption);
} }
processedSelectedCount--; processedSelectedCount--;
} }

View File

@ -17,7 +17,7 @@ using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web;
using OneOf; using OneOf;
#endregion #endregion using block
namespace AntDesign namespace AntDesign
{ {
@ -34,7 +34,6 @@ namespace AntDesign
internal ElementReference _inputRef; internal ElementReference _inputRef;
protected bool _isInitialized; protected bool _isInitialized;
protected bool _isPrimitive; protected bool _isPrimitive;
/// <summary> /// <summary>
@ -50,7 +49,6 @@ namespace AntDesign
protected string _prevSearchValue = string.Empty; protected string _prevSearchValue = string.Empty;
protected string _searchValue = string.Empty; protected string _searchValue = string.Empty;
protected SelectContent<TItemValue, TItem> _selectContent; protected SelectContent<TItemValue, TItem> _selectContent;
protected IEnumerable<TItemValue> _selectedValues; protected IEnumerable<TItemValue> _selectedValues;
@ -58,77 +56,93 @@ namespace AntDesign
protected Action<TItem, string> _setLabel; protected Action<TItem, string> _setLabel;
protected Action<TItem, TItemValue> _setValue; protected Action<TItem, TItemValue> _setValue;
/// <summary> /// <summary>
/// Show clear button. Has no effect if <see cref="AntInputComponentBase{TValue}.Value"/> type default /// Show clear button. Has no effect if <see cref="AntInputComponentBase{TValue}.Value"/> type default
/// is also in the list of <see cref="SelectOption{TItemValue, TItem}"/>, /// is also in the list of <see cref="SelectOption{TItemValue, TItem}"/>,
/// unless used with <see cref="ValueOnClear"/>. /// unless used with <see cref="ValueOnClear"/>.
/// </summary> /// </summary>
[Parameter] public bool AllowClear { get; set; } [Parameter] public bool AllowClear { get; set; }
/// <summary> /// <summary>
/// Whether the current search will be cleared on selecting an item. /// Whether the current search will be cleared on selecting an item.
/// </summary> /// </summary>
[Parameter] public bool AutoClearSearchValue { get; set; } = true; [Parameter] public bool AutoClearSearchValue { get; set; } = true;
/// <summary> /// <summary>
/// Whether the Select component is disabled. /// Whether the Select component is disabled.
/// </summary> /// </summary>
[Parameter] public bool Disabled { get; set; } [Parameter] public bool Disabled { get; set; }
/// <summary> /// <summary>
/// Set mode of Select - default | multiple | tags /// Set mode of Select - default | multiple | tags
/// </summary> /// </summary>
[Parameter] public string Mode { get; set; } = "default"; [Parameter] public string Mode { get; set; } = "default";
/// <summary> /// <summary>
/// Indicates whether the search function is active or not. Always true for mode tags. /// Indicates whether the search function is active or not. Always true for mode tags.
/// </summary> /// </summary>
[Parameter] public bool EnableSearch { get; set; } [Parameter] public bool EnableSearch { get; set; }
/// <summary> /// <summary>
/// Delays the processing of the search input event until the user has stopped /// Delays the processing of the search input event until the user has stopped
/// typing for a predetermined amount of time /// typing for a predetermined amount of time
/// </summary> /// </summary>
[Parameter] [Parameter]
public int SearchDebounceMilliseconds { get; set; } public int SearchDebounceMilliseconds { get; set; }
/// <summary> /// <summary>
/// Show loading indicator. You have to write the loading logic on your own. /// Show loading indicator. You have to write the loading logic on your own.
/// </summary> /// </summary>
[Parameter] public bool Loading { get; set; } [Parameter] public bool Loading { get; set; }
/// <summary> /// <summary>
/// Controlled open state of dropdown. /// Controlled open state of dropdown.
/// </summary> /// </summary>
[Parameter] public bool Open { get; set; } [Parameter] public bool Open { get; set; }
/// <summary> /// <summary>
/// Placeholder of select. /// Placeholder of select.
/// </summary> /// </summary>
[Parameter] public string Placeholder { get; set; } [Parameter] public string Placeholder { get; set; }
/// <summary> /// <summary>
/// Called when focus. /// Called when focus.
/// </summary> /// </summary>
[Parameter] public EventCallback OnFocus { get; set; } [Parameter] public EventCallback OnFocus { get; set; }
/// <summary> /// <summary>
/// The name of the property to be used as a group indicator. /// The name of the property to be used as a group indicator.
/// If the value is set, the entries are displayed in groups. /// If the value is set, the entries are displayed in groups.
/// Use additional SortByGroup and SortByLabel. /// Use additional SortByGroup and SortByLabel.
/// </summary> /// </summary>
[Parameter] public SortDirection SortByGroup { get; set; } = SortDirection.None; [Parameter] public SortDirection SortByGroup { get; set; } = SortDirection.None;
/// <summary> /// <summary>
/// Sort items by label value. None | Ascending | Descending /// Sort items by label value. None | Ascending | Descending
/// </summary> /// </summary>
[Parameter] public SortDirection SortByLabel { get; set; } = SortDirection.None; [Parameter] public SortDirection SortByLabel { get; set; } = SortDirection.None;
/// <summary> /// <summary>
/// Hides the selected items when they are selected. /// Hides the selected items when they are selected.
/// </summary> /// </summary>
[Parameter] public bool HideSelected { get; set; } [Parameter] public bool HideSelected { get; set; }
/// <summary> /// <summary>
/// Used for the two-way binding. /// Used for the two-way binding.
/// </summary> /// </summary>
[Parameter] public override EventCallback<TItemValue> ValueChanged { get; set; } [Parameter] public override EventCallback<TItemValue> ValueChanged { get; set; }
/// <summary> /// <summary>
/// Used for the two-way binding. /// Used for the two-way binding.
/// </summary> /// </summary>
[Parameter] public EventCallback<IEnumerable<TItemValue>> ValuesChanged { get; set; } [Parameter] public EventCallback<IEnumerable<TItemValue>> ValuesChanged { get; set; }
/// <summary> /// <summary>
/// The custom suffix icon. /// The custom suffix icon.
/// </summary> /// </summary>
[Parameter] public RenderFragment SuffixIcon { get; set; } [Parameter] public RenderFragment SuffixIcon { get; set; }
/// <summary> /// <summary>
/// The custom prefix icon. /// The custom prefix icon.
/// </summary> /// </summary>
@ -136,6 +150,7 @@ namespace AntDesign
protected IEnumerable<TItemValue> _defaultValues; protected IEnumerable<TItemValue> _defaultValues;
protected bool _defaultValuesHasItems; protected bool _defaultValuesHasItems;
/// <summary> /// <summary>
/// Used when Mode = multiple | tags - The values are used during initialization and when pressing the Reset button within Forms. /// Used when Mode = multiple | tags - The values are used during initialization and when pressing the Reset button within Forms.
/// </summary> /// </summary>
@ -177,6 +192,7 @@ namespace AntDesign
internal HashSet<SelectOptionItem<TItemValue, TItem>> SelectOptionItems { get; } = new(); internal HashSet<SelectOptionItem<TItemValue, TItem>> SelectOptionItems { get; } = new();
internal List<SelectOptionItem<TItemValue, TItem>> SelectedOptionItems { get; } = new(); internal List<SelectOptionItem<TItemValue, TItem>> SelectedOptionItems { get; } = new();
/// <summary> /// <summary>
/// Called when the selected item changes. /// Called when the selected item changes.
/// </summary> /// </summary>
@ -187,8 +203,9 @@ namespace AntDesign
/// </summary> /// </summary>
[Parameter] public EventCallback<IEnumerable<TItem>> OnSelectedItemsChanged { get; set; } [Parameter] public EventCallback<IEnumerable<TItem>> OnSelectedItemsChanged { get; set; }
internal virtual SelectMode SelectMode => Mode.ToSelectMode(); [Parameter] public string Status { get; set; }
internal virtual SelectMode SelectMode => Mode.ToSelectMode();
/// <summary> /// <summary>
/// Currently active (highlighted) option. /// Currently active (highlighted) option.
@ -263,7 +280,6 @@ namespace AntDesign
public Func<string, TItemValue> CustomTagLabelToValue { get; set; } = public Func<string, TItemValue> CustomTagLabelToValue { get; set; } =
label => (TItemValue)TypeDescriptor.GetConverter(typeof(TItemValue)).ConvertFromInvariantString(label); label => (TItemValue)TypeDescriptor.GetConverter(typeof(TItemValue)).ConvertFromInvariantString(label);
/// <summary> /// <summary>
/// Determines if SelectOptions has any selected items /// Determines if SelectOptions has any selected items
/// </summary> /// </summary>
@ -351,7 +367,7 @@ namespace AntDesign
[Parameter] public int MaxTagTextLength { get; set; } [Parameter] public int MaxTagTextLength { get; set; }
/// <summary> /// <summary>
/// Whether to embed label in value, turn the format of value from TItemValue to string (JSON) /// Whether to embed label in value, turn the format of value from TItemValue to string (JSON)
/// e.g. { "value": TItemValue, "label": "Label value" } /// e.g. { "value": TItemValue, "label": "Label value" }
/// </summary> /// </summary>
[Parameter] [Parameter]
@ -383,6 +399,7 @@ namespace AntDesign
private bool _hasValueOnClear; private bool _hasValueOnClear;
private TItemValue _valueOnClear; private TItemValue _valueOnClear;
/// <summary> /// <summary>
/// When Clear button is pressed, Value will be set to /// When Clear button is pressed, Value will be set to
/// whatever is set in ValueOnClear /// whatever is set in ValueOnClear
@ -404,14 +421,12 @@ namespace AntDesign
/// <returns>true if SelectOptions has no values and the searchValue is empty; otherwise false </returns> /// <returns>true if SelectOptions has no values and the searchValue is empty; otherwise false </returns>
protected bool ShowPlaceholder => !HasValue && string.IsNullOrEmpty(_searchValue); protected bool ShowPlaceholder => !HasValue && string.IsNullOrEmpty(_searchValue);
/// <summary> /// <summary>
/// The Method is called every time if the value of the @bind-Values was changed by the two-way binding. /// The Method is called every time if the value of the @bind-Values was changed by the two-way binding.
/// </summary> /// </summary>
protected async Task OnValuesChangeAsync(IEnumerable<TItemValue> values) protected async Task OnValuesChangeAsync(IEnumerable<TItemValue> values)
{ {
if ( if (!_isInitialized) // This is important because otherwise the initial value is overwritten by the EventCallback of ValueChanged and would be NULL.
!_isInitialized) // This is important because otherwise the initial value is overwritten by the EventCallback of ValueChanged and would be NULL.
{ {
return; return;
} }
@ -670,7 +685,6 @@ namespace AntDesign
} }
} }
/// <summary> /// <summary>
/// The method is called every time if the user select/de-select a item by mouse or keyboard. /// The method is called every time if the user select/de-select a item by mouse or keyboard.
/// Don't change the IsSelected property outside of this function. /// Don't change the IsSelected property outside of this function.
@ -827,7 +841,6 @@ namespace AntDesign
_prevSearchValue = string.Empty; _prevSearchValue = string.Empty;
} }
/// <summary> /// <summary>
/// Method is called via EventCallBack after the user clicked on the Clear icon inside the Input element. /// Method is called via EventCallBack after the user clicked on the Clear icon inside the Input element.
/// Set the IsSelected and IsHidden properties for all items to False. It updates the overlay position if /// Set the IsSelected and IsHidden properties for all items to False. It updates the overlay position if
@ -943,8 +956,6 @@ namespace AntDesign
{ {
Focused = true; Focused = true;
SetClassMap();
await FocusAsync(_inputRef); await FocusAsync(_inputRef);
await OnFocus.InvokeAsync(Focused); await OnFocus.InvokeAsync(Focused);
@ -962,7 +973,6 @@ namespace AntDesign
} }
} }
internal async Task OnArrowClick(MouseEventArgs args) internal async Task OnArrowClick(MouseEventArgs args)
{ {
await _dropDown.OnClickDiv(args); await _dropDown.OnClickDiv(args);
@ -985,7 +995,6 @@ namespace AntDesign
_ = ClearSelectedAsync(); _ = ClearSelectedAsync();
} }
/// <summary> /// <summary>
/// Clears the selectValue(s) property and send the null(default) value back through the two-way binding. /// Clears the selectValue(s) property and send the null(default) value back through the two-way binding.
/// </summary> /// </summary>
@ -1005,4 +1014,4 @@ namespace AntDesign
protected abstract void SetClassMap(); protected abstract void SetClassMap();
} }
} }

View File

@ -2,297 +2,306 @@
@namespace AntDesign.Select.Internal @namespace AntDesign.Select.Internal
@typeparam TItemValue @typeparam TItemValue
@typeparam TItem @typeparam TItem
@inherits AntDomComponentBase
@if (ParentSelect.SelectMode == SelectMode.Default) @if (ParentSelect.SelectMode == SelectMode.Default)
{ {
<div class="@Prefix-selector" @ref="@Ref" style="@(ParentSelect.PrefixIcon is null?"":"padding-left: 4px;")"> <div class="@Prefix-selector" @ref="@Ref" style="@(ParentSelect.PrefixIcon is null?"":"padding-left: 4px;")">
@if (ParentSelect.PrefixIcon != null) @if (ParentSelect.PrefixIcon != null)
{
<span class="@Prefix-prefix" unselectable="on" aria-hidden="true" style="user-select: none;display:flex;align-items: center;padding-right: 4px;">
@ParentSelect.PrefixIcon
</span>
}
<span class="@Prefix-selection-search" style="@_inputWidth">
<input @ref="ParentSelect._inputRef"
@oninput="@OnInputChange"
@onkeyup="OnKeyUp"
@onkeydown="OnKeyDown"
@attributes=@AdditonalAttributes()
@bind-value="@SearchValue"
id="@(ParentSelect.Id)_list"
type="search"
readonly="@(!ParentSelect.IsSearchEnabled)"
unselectable="@(ParentSelect.IsSearchEnabled ? false : "on")"
role="combobox"
class="@Prefix-selection-search-input"
autocomplete="off"
aria-owns="@(ParentSelect.Id)_list"
aria-expanded="@IsOverlayShow"
aria-autocomplete="list"
aria-controls="@(ParentSelect.Id)_list"
aria-haspopup="listbox"
style="@_inputStyle"/>
</span>
@if (ShowPlaceholder)
{
<span class="@Prefix-selection-placeholder">@Placeholder</span>
}
else
{
var selectedItem = ParentSelect.SelectedOptionItems.FirstOrDefault();
if (string.IsNullOrEmpty(SearchValue) && selectedItem != null)
{
@if (ParentLabelTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
<CascadingValue Value="@selectedItem" Name="SelectOption">
@ParentLabelTemplate(selectedItem.Item)
</CascadingValue>
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
@selectedItem.Label
</span>
}
}
}
</div>
@if (ParentSelect.SuffixIcon != null)
{ {
<span class="ant-select-arrow" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="@ParentSelect.OnArrowClick" @onclick:stopPropagation="true"> <span class="@Prefix-prefix" unselectable="on" aria-hidden="true" style="user-select: none;display:flex;align-items: center;padding-right: 4px;">
@ParentSelect.SuffixIcon @ParentSelect.PrefixIcon
</span> </span>
} }
else if (ParentSelect.Loading) <span class="@Prefix-selection-search" style="@_inputWidth">
<input @ref="ParentSelect._inputRef"
@oninput="@OnInputChange"
@onkeyup="OnKeyUp"
@onkeydown="OnKeyDown"
@attributes=@AdditonalAttributes()
@bind-value="@SearchValue"
id="@(ParentSelect.Id)_list"
type="search"
readonly="@(!ParentSelect.IsSearchEnabled)"
unselectable="@(ParentSelect.IsSearchEnabled ? false : "on")"
role="combobox"
class="@Prefix-selection-search-input"
autocomplete="off"
aria-owns="@(ParentSelect.Id)_list"
aria-expanded="@IsOverlayShow"
aria-autocomplete="list"
aria-controls="@(ParentSelect.Id)_list"
aria-haspopup="listbox"
style="@_inputStyle" />
</span>
@if (ShowPlaceholder)
{ {
<span class="ant-select-arrow ant-select-arrow-loading" unselectable="on" aria-hidden="true" style="user-select: none;"> <span class="@Prefix-selection-placeholder">@Placeholder</span>
<Icon Type="loading"></Icon>
</span>
} }
else else
{ {
if (ShowArrowIcon) var selectedItem = ParentSelect.SelectedOptionItems.FirstOrDefault();
if (string.IsNullOrEmpty(SearchValue) && selectedItem != null)
{
@if (ParentLabelTemplate != null)
{ {
<span class="ant-select-arrow" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="@ParentSelect.OnArrowClick" @onclick:stopPropagation="true"> <CascadingValue Value="this" Name="SelectContent">
@if (ParentSelect.IsSearchEnabled && IsOverlayShow) <CascadingValue Value="@selectedItem" Name="SelectOption">
{ @ParentLabelTemplate(selectedItem.Item)
if (ShowSearchIcon) </CascadingValue>
{ </CascadingValue>
<Icon Type="search"></Icon>
}
}
else
{
<Icon Type="down"></Icon>
}
</span>
} }
else else
{ {
<span class="ant-select-arrow" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="@ParentSelect.OnArrowClick" @onclick:stopPropagation="true"> <span class="@Prefix-selection-item">
@if (ParentSelect.IsSearchEnabled && IsOverlayShow) @getLabel(selectedItem)
{ </span>
if (ShowSearchIcon)
{
<Icon Type="search"></Icon>
}
}
</span>
}
@if (!ParentSelect.Disabled && ParentSelect.AllowClear && ParentSelect.HasValue)
{
<span class="ant-select-clear" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="OnClearClick" @onclick:stopPropagation="true">
<Icon Type="close-circle" Theme="fill"></Icon>
</span>
} }
}
} }
</div>
@if (ParentSelect.SuffixIcon != null)
{
<span class="ant-select-arrow" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="@ParentSelect.OnArrowClick" @onclick:stopPropagation="true">
@ParentSelect.SuffixIcon
</span>
}
else if (ParentSelect.Loading)
{
<span class="ant-select-arrow ant-select-arrow-loading" unselectable="on" aria-hidden="true" style="user-select: none;">
<Icon Type="loading"></Icon>
</span>
}
else
{
if (ShowArrowIcon)
{
<span class="ant-select-arrow" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="@ParentSelect.OnArrowClick" @onclick:stopPropagation="true">
@if (ParentSelect.IsSearchEnabled && IsOverlayShow)
{
if (ShowSearchIcon)
{
<Icon Type="search"></Icon>
}
}
else
{
<Icon Type="down"></Icon>
}
</span>
}
else
{
<span class="ant-select-arrow" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="@ParentSelect.OnArrowClick" @onclick:stopPropagation="true">
@if (ParentSelect.IsSearchEnabled && IsOverlayShow)
{
if (ShowSearchIcon)
{
<Icon Type="search"></Icon>
}
}
</span>
}
@if (!ParentSelect.Disabled && ParentSelect.AllowClear && ParentSelect.HasValue)
{
<span class="ant-select-clear" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="OnClearClick" @onclick:stopPropagation="true">
<Icon Type="close-circle" Theme="fill"></Icon>
</span>
}
}
} }
else //ParentSelect.SelectMode != SelectMode.Default else //ParentSelect.SelectMode != SelectMode.Default
{ {
<div class="@Prefix-selector" @ref="@Ref" style="@(ParentSelect.PrefixIcon is null?"":"padding-left: 4px;")" > <div class="@Prefix-selector" @ref="@Ref" style="@(ParentSelect.PrefixIcon is null?"":"padding-left: 4px;")">
<div class="@Prefix-selection-overflow" @ref="@_overflow"> <div class="@Prefix-selection-overflow" @ref="@_overflow">
@if (ParentSelect.PrefixIcon != null) @if (ParentSelect.PrefixIcon != null)
{ {
<div class="@Prefix-selection-overflow-item" style="opacity: 1;order:-100;"> <div class="@Prefix-selection-overflow-item" style="opacity: 1;order:-100;">
<span @ref="@_prefixRef" class="@Prefix-prefix" unselectable="on" aria-hidden="true" style="user-select: none;display:flex;align-items: center;padding-right: 4px;min-height:28px;"> <span @ref="@_prefixRef" class="@Prefix-prefix" unselectable="on" aria-hidden="true" style="user-select: none;display:flex;align-items: center;padding-right: 4px;min-height:28px;">
@ParentSelect.PrefixIcon @ParentSelect.PrefixIcon
</span> </span>
</div>
}
@if (!ShowPlaceholder)
{
var selectedItems = ParentSelect.SelectedOptionItems;
@if (ParentSelect.HasTagCount)
{
@for (int i = 0; i < Math.Min(ParentSelect.MaxTagCount.AsT0, selectedItems.Count); i++)
{
var selectedOption = selectedItems[i];
<div class="@Prefix-selection-overflow-item" style="@OverflowStyle(i)">
@if (ParentLabelTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
<CascadingValue Value="@selectedOption" Name="SelectOption">
@ParentLabelTemplate(selectedOption.Item)
</CascadingValue>
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
<span class="@Prefix-selection-item-content">@FormatLabel(selectedOption.Label)</span>
<span unselectable="on" aria-hidden="true" style="user-select: none;" class="@Prefix-selection-item-remove"
@onmousedown="(e)=> RemoveClicked(e, selectedOption)" onclick="event.stopPropagation()">
<Icon Type="close"></Icon>
</span>
</span>
}
</div>
}
@if (selectedItems.Count > ParentSelect.MaxTagCount.AsT0)
{
<div class="@Prefix-selection-overflow-item @Prefix-selection-overflow-item-rest" style="opacity: 1; order: @(selectedItems.Count-1);">
@if (ParentMaxTagPlaceholerTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
@ParentMaxTagPlaceholerTemplate(selectedItems.Skip(ParentSelect.MaxTagCount.AsT0).Select(i => i.Item))
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
<span class="@Prefix-selection-item-content">+ @(selectedItems.Count - ParentSelect.MaxTagCount.AsT0)@Ellipse</span>
</span>
}
</div>
}
}
else if (ParentSelect.IsResponsive)
{
@for (int i = 0; i < selectedItems.Count; i++)
{
var selectedOption = selectedItems[i];
<div class="@Prefix-selection-overflow-item" @key="@selectedOption.InternalId" @ref="@selectedOption.SelectedTagRef" style="@OverflowStyle(i)">
@if (ParentLabelTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
<CascadingValue Value="@selectedOption" Name="SelectOption">
@ParentLabelTemplate(selectedOption.Item)
</CascadingValue>
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
<span class="@Prefix-selection-item-content">@FormatLabel(selectedOption.Label)</span>
<span unselectable="on" aria-hidden="true" style="user-select: none;" class="@Prefix-selection-item-remove"
@onmousedown="(e)=> RemoveClicked(e, selectedOption)" onclick="event.stopPropagation()">
<Icon Type="close"></Icon>
</span>
</span>
}
</div>
}
@if (selectedItems.Count > _calculatedMaxCount)
{
<div class="@Prefix-selection-overflow-item @Prefix-selection-overflow-item-rest" @key="@_internalId" @ref="@_aggregateTag" style="opacity 1; order: @(_calculatedMaxCount-1);">
@if (ParentMaxTagPlaceholerTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
@ParentMaxTagPlaceholerTemplate(selectedItems.Skip(_calculatedMaxCount).Select(i => i.Item))
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
<span class="@Prefix-selection-item-content">+ @(selectedItems.Count-_calculatedMaxCount)@Ellipse</span>
</span>
}
</div>
}
}
else
{
string firstAfterPrefix = $"max-width: {GetFirstItemMaxWidth()}%;";
@foreach (var selectedOption in selectedItems)
{
<div class="@Prefix-selection-overflow-item" style="opacity: 1;@firstAfterPrefix">
@if (ParentLabelTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
<CascadingValue Value="@selectedOption" Name="SelectOption">
@ParentLabelTemplate(selectedOption.Item)
</CascadingValue>
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
<span class="@Prefix-selection-item-content">@FormatLabel(selectedOption.Label)</span>
<span unselectable="on" aria-hidden="true" style="user-select: none;" class="@Prefix-selection-item-remove"
@onmousedown="(e)=> RemoveClicked(e, selectedOption)" onclick="event.stopPropagation()">
<Icon Type="close"></Icon>
</span>
</span>
}
</div>
firstAfterPrefix = "max-width: 98%;";
}
}
}
<div class="@Prefix-selection-overflow-item @Prefix-selection-overflow-item-suffix" style="opacity: 1; order: @(ParentSelect.IsResponsive?_calculatedMaxCount-1:ParentSelect.SelectedOptionItems.Count)">
<div class="@Prefix-selection-search" style="@_inputWidth">
<input @ref="ParentSelect._inputRef"
@oninput="OnInputChange"
@onkeyup="OnKeyUp"
@onkeydown="OnKeyDown"
@attributes=@AdditonalAttributes()
@bind-value="@SearchValue"
id="@ParentSelect.Id"
type="search"
readonly="@(!ParentSelect.IsSearchEnabled)"
unselectable="@(ParentSelect.IsSearchEnabled ? false : "on")"
role="combobox"
class="@Prefix-selection-search-input"
autocomplete="off"
aria-owns="@(ParentSelect.Id)_list"
aria-expanded="@IsOverlayShow"
aria-autocomplete="list"
aria-controls="@(ParentSelect.Id)_list"
aria-haspopup="listbox"
style="@_inputStyle"/>
<span class="@Prefix-selection-search-mirror" aria-hidden="true">&nbsp;</span>
</div>
</div>
@if (ShowPlaceholder)
{
<span class="@Prefix-selection-placeholder" style="@(ParentSelect.PrefixIcon != null?"margin-left: 7px;":"")">@Placeholder</span>
}
</div> </div>
</div> }
@if (!ShowPlaceholder)
{
var selectedItems = ParentSelect.SelectedOptionItems;
@if (ParentSelect.HasTagCount)
{
@for (int i = 0; i < Math.Min(ParentSelect.MaxTagCount.AsT0, selectedItems.Count); i++)
{
var selectedOption = selectedItems[i];
<div class="@Prefix-selection-overflow-item" style="@OverflowStyle(i)">
@if (ParentLabelTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
<CascadingValue Value="@selectedOption" Name="SelectOption">
@ParentLabelTemplate(selectedOption.Item)
</CascadingValue>
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
<span class="@Prefix-selection-item-content">@getTagLabel(this,selectedOption)</span>
<span unselectable="on" aria-hidden="true" style="user-select: none;" class="@Prefix-selection-item-remove"
@onmousedown="(e)=> RemoveClicked(e, selectedOption)" onclick="event.stopPropagation()">
<Icon Type="close"></Icon>
</span>
</span>
}
</div>
}
@if (selectedItems.Count > ParentSelect.MaxTagCount.AsT0)
{
<div class="@Prefix-selection-overflow-item @Prefix-selection-overflow-item-rest" style="opacity: 1; order: @(selectedItems.Count-1);">
@if (ParentMaxTagPlaceholerTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
@ParentMaxTagPlaceholerTemplate(selectedItems.Skip(ParentSelect.MaxTagCount.AsT0).Select(i => i.Item))
</CascadingValue>
}
else
{
@if (ParentSelect.SuffixIcon != null) <span class="@Prefix-selection-item">
{ <span class="@Prefix-selection-item-content">+ @(selectedItems.Count - ParentSelect.MaxTagCount.AsT0)@Ellipse</span>
<span @ref="@_suffixRef" class="ant-select-arrow" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="@ParentSelect.OnArrowClick" @onclick:stopPropagation="true"> </span>
@ParentSelect.SuffixIcon
</span> }
} </div>
else if (ParentSelect.Loading) }
{ }
<span @ref="@_suffixRef" class="ant-select-arrow ant-select-arrow-loading" unselectable="on" aria-hidden="true" style="user-select: none;"> else if (ParentSelect.IsResponsive)
<Icon Type="loading"></Icon> {
</span> @for (int i = 0; i < selectedItems.Count; i++)
} {
@if (!ParentSelect.Disabled && ParentSelect.AllowClear && ParentSelect.HasValue) var selectedOption = selectedItems[i];
{ <div class="@Prefix-selection-overflow-item" @key="@selectedOption.InternalId" @ref="@selectedOption.SelectedTagRef" style="@OverflowStyle(i)">
<span @ref="@_suffixRef" class="ant-select-clear" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="OnClearClickAsync" @onclick:stopPropagation="true"> @if (ParentLabelTemplate != null)
<Icon Type="close-circle" Theme="fill"></Icon> {
</span> <CascadingValue Value="this" Name="SelectContent">
} <CascadingValue Value="@selectedOption" Name="SelectOption">
@ParentLabelTemplate(selectedOption.Item)
</CascadingValue>
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
<span class="@Prefix-selection-item-content">@getTagLabel(this,selectedOption)</span>
<span unselectable="on" aria-hidden="true" style="user-select: none;" class="@Prefix-selection-item-remove"
@onmousedown="(e)=> RemoveClicked(e, selectedOption)" onclick="event.stopPropagation()">
<Icon Type="close"></Icon>
</span>
</span>
}
</div>
}
@if (selectedItems.Count > _calculatedMaxCount)
{
<div class="@Prefix-selection-overflow-item @Prefix-selection-overflow-item-rest" @key="@_internalId" @ref="@_aggregateTag" style="opacity 1; order: @(_calculatedMaxCount-1);">
@if (ParentMaxTagPlaceholerTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
@ParentMaxTagPlaceholerTemplate(selectedItems.Skip(_calculatedMaxCount).Select(i => i.Item))
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
<span class="@Prefix-selection-item-content">+ @(selectedItems.Count-_calculatedMaxCount)@Ellipse</span>
</span>
}
</div>
}
}
else
{
string firstAfterPrefix = $"max-width: {GetFirstItemMaxWidth()}%;";
@foreach (var selectedOption in selectedItems)
{
<div class="@Prefix-selection-overflow-item" style="opacity: 1;@firstAfterPrefix">
@if (ParentLabelTemplate != null)
{
<CascadingValue Value="this" Name="SelectContent">
<CascadingValue Value="@selectedOption" Name="SelectOption">
@ParentLabelTemplate(selectedOption.Item)
</CascadingValue>
</CascadingValue>
}
else
{
<span class="@Prefix-selection-item">
<span class="@Prefix-selection-item-content">@getTagLabel(this,selectedOption)</span>
<span unselectable="on" aria-hidden="true" style="user-select: none;" class="@Prefix-selection-item-remove"
@onmousedown="(e)=> RemoveClicked(e, selectedOption)" onclick="event.stopPropagation()">
<Icon Type="close"></Icon>
</span>
</span>
}
</div>
firstAfterPrefix = "max-width: 98%;";
}
}
}
<div class="@Prefix-selection-overflow-item @Prefix-selection-overflow-item-suffix" style="opacity: 1; order: @(ParentSelect.IsResponsive?_calculatedMaxCount-1:ParentSelect.SelectedOptionItems.Count)">
<div class="@Prefix-selection-search" style="@_inputWidth">
<input @ref="ParentSelect._inputRef"
@oninput="OnInputChange"
@onkeyup="OnKeyUp"
@onkeydown="OnKeyDown"
@attributes=@AdditonalAttributes()
@bind-value="@SearchValue"
id="@ParentSelect.Id"
type="search"
readonly="@(!ParentSelect.IsSearchEnabled)"
unselectable="@(ParentSelect.IsSearchEnabled ? false : "on")"
role="combobox"
class="@Prefix-selection-search-input"
autocomplete="off"
aria-owns="@(ParentSelect.Id)_list"
aria-expanded="@IsOverlayShow"
aria-autocomplete="list"
aria-controls="@(ParentSelect.Id)_list"
aria-haspopup="listbox"
style="@_inputStyle" />
<span class="@Prefix-selection-search-mirror" aria-hidden="true">&nbsp;</span>
</div>
</div>
@if (ShowPlaceholder)
{
<span class="@Prefix-selection-placeholder" style="@(ParentSelect.PrefixIcon != null?"margin-left: 7px;":"")">@Placeholder</span>
}
</div>
</div>
@if (ParentSelect.SuffixIcon != null)
{
<span @ref="@_suffixRef" class="ant-select-arrow" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="@ParentSelect.OnArrowClick" @onclick:stopPropagation="true">
@ParentSelect.SuffixIcon
</span>
}
else if (ParentSelect.Loading)
{
<span @ref="@_suffixRef" class="ant-select-arrow ant-select-arrow-loading" unselectable="on" aria-hidden="true" style="user-select: none;">
<Icon Type="loading"></Icon>
</span>
}
@if (!ParentSelect.Disabled && ParentSelect.AllowClear && ParentSelect.HasValue)
{
<span @ref="@_suffixRef" class="ant-select-clear" unselectable="on" aria-hidden="true" style="user-select: none;" @onclick="OnClearClickAsync" @onclick:stopPropagation="true">
<Icon Type="close-circle" Theme="fill"></Icon>
</span>
}
}
@code {
RenderFragment getLabel(SelectOptionItem<TItemValue, TItem> option) =>
@<Template>@if (option.LabelTemplate != null)@option.LabelTemplate else @option.Label</Template>;
RenderFragment getTagLabel(SelectContent<TItemValue, TItem> content, SelectOptionItem<TItemValue, TItem> option)=>
@<Template>@if (option.LabelTemplate != null) @option.LabelTemplate else @content.FormatLabel(option.Label)</Template>;
} }

View File

@ -18,7 +18,7 @@ using Microsoft.JSInterop;
namespace AntDesign.Select.Internal namespace AntDesign.Select.Internal
{ {
public partial class SelectContent<TItemValue, TItem> : IDisposable public partial class SelectContent<TItemValue, TItem> : AntDomComponentBase
{ {
[CascadingParameter(Name = "ParentSelect")] internal SelectBase<TItemValue, TItem> ParentSelect { get; set; } [CascadingParameter(Name = "ParentSelect")] internal SelectBase<TItemValue, TItem> ParentSelect { get; set; }
[CascadingParameter(Name = "ParentLabelTemplate")] internal RenderFragment<TItem> ParentLabelTemplate { get; set; } [CascadingParameter(Name = "ParentLabelTemplate")] internal RenderFragment<TItem> ParentLabelTemplate { get; set; }
@ -64,21 +64,9 @@ namespace AntDesign.Select.Internal
[Parameter] public EventCallback<MouseEventArgs> OnClearClick { get; set; } [Parameter] public EventCallback<MouseEventArgs> OnClearClick { get; set; }
[Parameter] public EventCallback<SelectOptionItem<TItemValue, TItem>> OnRemoveSelected { get; set; } [Parameter] public EventCallback<SelectOptionItem<TItemValue, TItem>> OnRemoveSelected { get; set; }
[Parameter] public string SearchValue { get; set; } [Parameter] public string SearchValue { get; set; }
[Parameter] public ForwardRef RefBack { get; set; } = new ForwardRef();
[Parameter] public int SearchDebounceMilliseconds { get; set; } [Parameter] public int SearchDebounceMilliseconds { get; set; }
[Inject] protected IJSRuntime Js { get; set; }
[Inject] private IDomEventListener DomEventListener { get; set; } [Inject] private IDomEventListener DomEventListener { get; set; }
protected ElementReference Ref
{
get { return _ref; }
set
{
_ref = value;
RefBack?.Set(value);
}
}
private const char Ellipse = (char)0x2026; private const char Ellipse = (char)0x2026;
private const int ItemMargin = 4; //taken from each tag item private const int ItemMargin = 4; //taken from each tag item
private string _inputStyle = string.Empty; private string _inputStyle = string.Empty;
@ -450,9 +438,7 @@ namespace AntDesign.Select.Internal
//TODO: Use built in @onblur once https://github.com/dotnet/aspnetcore/issues/30070 is solved //TODO: Use built in @onblur once https://github.com/dotnet/aspnetcore/issues/30070 is solved
private async void OnBlurInternal(JsonElement e) => await OnBlur.InvokeAsync(new()); private async void OnBlurInternal(JsonElement e) => await OnBlur.InvokeAsync(new());
public bool IsDisposed { get; private set; } protected override void Dispose(bool disposing)
protected virtual void Dispose(bool disposing)
{ {
if (!_isReloading) if (!_isReloading)
{ {
@ -466,22 +452,6 @@ namespace AntDesign.Select.Internal
}); });
} }
DomEventListener?.Dispose(); DomEventListener?.Dispose();
if (IsDisposed) return;
IsDisposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~SelectContent()
{
// Finalizer calls Dispose(false)
Dispose(false);
} }
} }
} }

View File

@ -28,6 +28,7 @@ namespace AntDesign.Select.Internal
public Guid InternalId { get; set; } = Guid.NewGuid(); public Guid InternalId { get; set; } = Guid.NewGuid();
private TItemValue _value; private TItemValue _value;
public TItemValue Value public TItemValue Value
{ {
get => _value; get => _value;
@ -38,6 +39,7 @@ namespace AntDesign.Select.Internal
} }
private TItem _item; private TItem _item;
public TItem Item public TItem Item
{ {
get => _item; get => _item;
@ -74,6 +76,8 @@ namespace AntDesign.Select.Internal
} }
} }
public RenderFragment LabelTemplate { get; set; }
private string _groupName = string.Empty; private string _groupName = string.Empty;
public string GroupName public string GroupName
@ -102,6 +106,7 @@ namespace AntDesign.Select.Internal
} }
private bool _isSelected; private bool _isSelected;
public bool IsSelected public bool IsSelected
{ {
get => _isSelected; get => _isSelected;
@ -118,6 +123,7 @@ namespace AntDesign.Select.Internal
} }
private bool _isActive; private bool _isActive;
public bool IsActive public bool IsActive
{ {
get => _isActive; get => _isActive;
@ -134,6 +140,7 @@ namespace AntDesign.Select.Internal
} }
private bool _isDisabled; private bool _isDisabled;
public bool IsDisabled public bool IsDisabled
{ {
get => _isDisabled; get => _isDisabled;
@ -150,6 +157,7 @@ namespace AntDesign.Select.Internal
} }
private bool _isHidden; private bool _isHidden;
public bool IsHidden public bool IsHidden
{ {
get => _isHidden; get => _isHidden;
@ -165,7 +173,6 @@ namespace AntDesign.Select.Internal
} }
} }
public bool IsAddedTag { get; set; } public bool IsAddedTag { get; set; }
private SelectOption<TItemValue, TItem> _childComponent; private SelectOption<TItemValue, TItem> _childComponent;

View File

@ -10,26 +10,50 @@ namespace AntDesign
[Parameter] [Parameter]
public string Format { get; set; } = "hh:mm:ss"; public string Format { get; set; } = "hh:mm:ss";
public override DateTime Value
{
get
{
return base.Value;
}
set
{
if (base.Value != value)
{
base.Value = value;
Reset();
}
}
}
[Parameter] [Parameter]
public EventCallback OnFinish { get; set; } public EventCallback OnFinish { get; set; }
[Parameter]
public int RefreshInterval { get; set; } = REFRESH_INTERVAL;
private Timer _timer; private Timer _timer;
private const int REFRESH_INTERVAL = 1000 / 30; private const int REFRESH_INTERVAL = 1000 / 10;
private TimeSpan _countDown = TimeSpan.Zero; private TimeSpan _countDown = TimeSpan.Zero;
protected override void OnInitialized() protected override void OnInitialized()
{ {
base.OnInitialized(); base.OnInitialized();
SetTimer();
}
private void SetTimer()
{
_countDown = Value - DateTime.Now;
_timer = new Timer(StartCountDownForTimeSpan); _timer = new Timer(StartCountDownForTimeSpan);
_timer.Change(0, REFRESH_INTERVAL); _timer.Change(0, RefreshInterval);
} }
private void StartCountDownForTimeSpan(object o) private void StartCountDownForTimeSpan(object o)
{ {
_countDown = Value - DateTime.Now; _countDown = _countDown.Add(TimeSpan.FromMilliseconds(-RefreshInterval));
if (_countDown.Ticks <= 0) if (_countDown.Ticks <= 0)
{ {
_countDown = TimeSpan.Zero; _countDown = TimeSpan.Zero;
@ -39,8 +63,23 @@ namespace AntDesign
InvokeAsync(() => OnFinish.InvokeAsync(o)); InvokeAsync(() => OnFinish.InvokeAsync(o));
} }
} }
InvokeStateHasChanged(); InvokeStateHasChanged();
} }
public void Reset()
{
//避免初始化时调用Reset
if (_timer != null)
{
_timer.Dispose();
SetTimer();
}
}
protected override void Dispose(bool disposing)
{
_timer?.Dispose();
base.Dispose(disposing);
}
} }
} }

View File

@ -32,7 +32,7 @@ namespace AntDesign
/// <summary> /// <summary>
/// 数值内容 /// 数值内容
/// </summary> /// </summary>
[Parameter] public T Value { get; set; } [Parameter] public virtual T Value { get; set; }
/// <summary> /// <summary>
/// 设置数值的样式 /// 设置数值的样式

View File

@ -48,7 +48,12 @@ namespace AntDesign
if (_pending.Value != value.Value) if (_pending.Value != value.Value)
{ {
_pending = value; _pending = value;
if (value.Value == null)
{
_pendingItem = null;
SetItems();
return;
}
_pendingItem = _pending.Value == null ? null : new TimelineItem() _pendingItem = _pending.Value == null ? null : new TimelineItem()
{ {
Class = "ant-timeline-item-pending" Class = "ant-timeline-item-pending"

View File

@ -13,7 +13,7 @@
@onfocusin="OnTriggerFocusIn" @onfocusin="OnTriggerFocusIn"
@onfocusout="OnTriggerFocusOut" @onfocusout="OnTriggerFocusOut"
@oncontextmenu:preventDefault @oncontextmenu:preventDefault
tabindex="0"> tabindex="@TabIndex">
@ChildContent @ChildContent
</div> </div>
} }

View File

@ -20,6 +20,9 @@ namespace AntDesign
[Parameter] [Parameter]
public double MouseLeaveDelay { get; set; } = 0.1; public double MouseLeaveDelay { get; set; } = 0.1;
[Parameter]
public int TabIndex { get; set; } = 0;
public Tooltip() public Tooltip()
{ {
PrefixCls = "ant-tooltip"; PrefixCls = "ant-tooltip";

View File

@ -1,45 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Components;
namespace AntDesign
{
public class SimpleTreeSelect<TItem> : TreeSelect<TItem> where TItem : class
{
protected IEnumerable<TItem> RootData => ChildrenMethodExpression?.Invoke(DataSource, RootValue);
/// <summary>
/// Specifies a method to return a child node
/// </summary>
[Parameter]
public Func<IEnumerable<TItem>, string, IList<TItem>> ChildrenMethodExpression { get; set; }
protected override Func<TreeNode<TItem>, IList<TItem>> TreeNodeChildrenExpression => node => ChildrenMethodExpression(DataSource, TreeNodeKeyExpression(node));
protected override Dictionary<string, object> TreeAttributes
{
get
{
return new()
{
{ "DataSource", RootData },
{ "TitleExpression", TreeNodeTitleExpression },
{ "DefaultExpandAll", TreeDefaultExpandAll },
{ "KeyExpression", TreeNodeKeyExpression },
{ "ChildrenExpression", TreeNodeChildrenExpression },
{ "DisabledExpression", TreeNodeDisabledExpression },
{ "IsLeafExpression", TreeNodeIsLeafExpression }
};
}
}
}
}

View File

@ -6,73 +6,88 @@
@using AntDesign.Select.Internal @using AntDesign.Select.Internal
<CascadingValue Value="this" IsFixed> <CascadingValue Value="this" IsFixed>
<CascadingValue Value=@("ant-select-dropdown") Name="PrefixCls" IsFixed> <CascadingValue Value=@("ant-select-dropdown") Name="PrefixCls" IsFixed>
<div class="@ClassMapper.Class" style="@Style" id="@Id" tabindex="-1" @ref="Ref"> <div class="@ClassMapper.Class" style="@Style" id="@Id" tabindex="-1" @ref="Ref">
<OverlayTrigger @ref="@_dropDown" <OverlayTrigger @ref="@_dropDown"
Visible="Open" Visible="Open"
Disabled="Disabled" Disabled="Disabled"
Trigger="new[] { Trigger.Click }" Trigger="new[] { Trigger.Click }"
HiddenMode HiddenMode
OnMouseEnter="@(() => { OnMouseEnter?.Invoke(); })" OnMouseEnter="@(() => { OnMouseEnter?.Invoke(); })"
OnMouseLeave="@(() => { OnMouseLeave?.Invoke(); })" OnMouseLeave="@(() => { OnMouseLeave?.Invoke(); })"
OnVisibleChange="@OnOverlayVisibleChangeAsync" OnVisibleChange="@OnOverlayVisibleChangeAsync"
PopupContainerSelector="@PopupContainerSelector" PopupContainerSelector="@PopupContainerSelector"
OverlayEnterCls="ant-slide-up-enter ant-slide-up-enter-active ant-slide-up" OverlayEnterCls="ant-slide-up-enter ant-slide-up-enter-active ant-slide-up"
OverlayLeaveCls="ant-slide-up-leave ant-slide-up-leave-active ant-slide-up"> OverlayLeaveCls="ant-slide-up-leave ant-slide-up-leave-active ant-slide-up">
<Overlay > <Overlay>
<div style="@_dropdownStyle"> <div style="@_dropdownStyle">
<div class="" style="max-height: @PopupContainerMaxHeight; overflow-y: auto;"> <div class="" style="max-height: @PopupContainerMaxHeight; overflow-y: auto;">
<div> <div>
<div class="" role="listbox" style="display: flex; flex-direction: column;"> <div class="" role="listbox" style="display: flex; flex-direction: column;">
<Tree TItem="TItem" <Tree @ref="_tree"
BlockNode @ref="_tree" Multiple="Multiple" TItem="TItem"
@attributes="TreeAttributes" BlockNode
SelectedKeys="SelectedKeys" DataSource="DataSource"
OnClick="OnTreeNodeClick" Multiple="Multiple"
OnUnSelect="OnTreeNodeUnSelect"> Selectable="!TreeCheckable"
<Nodes> SelectedKeys="SelectedKeys"
@if (IsInnerModel) Checkable="TreeCheckable"
{ OnClick="OnTreeNodeClick"
<CascadingValue Name="Tree" Value="_tree" IsFixed="true"> OnUnselect="OnTreeNodeUnSelect"
@ChildContent OnCheck="OnTreeCheck"
</CascadingValue> ShowLeafIcon="ShowLeafIcon"
} ShowLine="ShowTreeLine"
</Nodes> TitleExpression="TitleExpression"
KeyExpression="KeyExpression"
</Tree> IconExpression="IconExpression"
</div> IsLeafExpression="IsLeafExpression"
</div> ChildrenExpression="ChildrenExpression"
</div> DisabledExpression="DisabledExpression"
</div> DefaultExpandAll="TreeDefaultExpandAll"
</Overlay> >
<Unbound> <Nodes>
<CascadingValue Value="this" Name=@("ParentSelect") IsFixed> @if (IsTemplatedNodes)
<CascadingValue Value="@LabelTemplate" Name="ParentLabelTemplate"> {
<CascadingValue Value="@ShowSearchIcon" Name="ShowSearchIcon"> <CascadingValue Name="Tree" Value="_tree" IsFixed="true">
<CascadingValue Value="@ShowArrowIcon" Name="ShowArrowIcon"> @ChildContent
<SelectContent Prefix="ant-select"
RefBack="@context"
TItemValue="string"
TItem="TItem"
SearchValue="@_searchValue"
SearchDebounceMilliseconds="@SearchDebounceMilliseconds"
IsOverlayShow="@_dropDown.IsOverlayShow()"
OnInput="@OnInputAsync"
OnKeyUp="@OnKeyUpAsync"
OnKeyDown="@OnKeyDownAsync"
OnFocus="@OnInputFocusAsync"
OnBlur="@OnInputBlurAsync"
OnClearClick="@OnInputClearClickAsync"
OnRemoveSelected="@OnRemoveSelectedAsync"
Placeholder="@Placeholder"
ShowPlaceholder="@ShowPlaceholder" />
</CascadingValue>
</CascadingValue>
</CascadingValue> </CascadingValue>
</CascadingValue> }
</Unbound> </Nodes>
</OverlayTrigger>
</div> </Tree>
</CascadingValue> </div>
</div>
</div>
</div>
</Overlay>
<Unbound>
<CascadingValue Value="this" Name=@("ParentSelect") IsFixed>
<CascadingValue Value="@LabelTemplate" Name="ParentLabelTemplate">
<CascadingValue Value="@ShowSearchIcon" Name="ShowSearchIcon">
<CascadingValue Value="@ShowArrowIcon" Name="ShowArrowIcon">
<SelectContent Prefix="ant-select"
RefBack="@context"
TItemValue="string"
TItem="TItem"
SearchValue="@_searchValue"
SearchDebounceMilliseconds="@SearchDebounceMilliseconds"
IsOverlayShow="@_dropDown.IsOverlayShow()"
OnInput="@OnInputAsync"
OnKeyUp="@OnKeyUpAsync"
OnKeyDown="@OnKeyDownAsync"
OnFocus="@OnInputFocusAsync"
OnBlur="@OnInputBlurAsync"
OnClearClick="@OnInputClearClickAsync"
OnRemoveSelected="@OnRemoveSelectedAsync"
Placeholder="@Placeholder"
ShowPlaceholder="@ShowPlaceholder" />
</CascadingValue>
</CascadingValue>
</CascadingValue>
</CascadingValue>
</Unbound>
</OverlayTrigger>
</div>
</CascadingValue>
</CascadingValue> </CascadingValue>

View File

@ -1,12 +1,13 @@
using System; // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using AntDesign.Internal;
using AntDesign.Select.Internal; using AntDesign.Select.Internal;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web;
using AntDesign.Core.Helpers.MemberPath;
using AntDesign.JsInterop; using AntDesign.JsInterop;
using OneOf; using OneOf;
using System.Linq; using System.Linq;
@ -17,8 +18,6 @@ namespace AntDesign
{ {
[Parameter] public bool ShowExpand { get; set; } = true; [Parameter] public bool ShowExpand { get; set; } = true;
protected Tree<TItem> _tree;
[Parameter] [Parameter]
public bool Multiple public bool Multiple
{ {
@ -56,162 +55,87 @@ namespace AntDesign
[Parameter] public bool TreeDefaultExpandAll { get; set; } [Parameter] public bool TreeDefaultExpandAll { get; set; }
[Parameter] [Parameter]
public Func<IEnumerable<TItem>, string, TItem> DataItemExpression { get; set; }
[Parameter]
public Func<IList<TItem>, IEnumerable<string>, IEnumerable<TItem>> DataItemsExpression { get; set; }
[Parameter]
public string RootValue { get; set; } = "0"; public string RootValue { get; set; } = "0";
protected Func<TreeNode<TItem>, string> TreeNodeTitleExpression [Parameter] public OneOf<bool, string> DropdownMatchSelectWidth { get; set; } = true;
{
get
{
return node => TitleExpression(node.DataItem);
}
}
[Parameter] public string DropdownMaxWidth { get; set; } = "auto";
[Parameter] public string PopupContainerMaxHeight { get; set; } = "256px";
//[Parameter] public IEnumerable<ITreeData<TItem>> TreeData { get; set; }
[Parameter] public string DropdownStyle { get; set; }
[Parameter] public bool ShowTreeLine { get; set; }
[Parameter] public bool ShowLeafIcon { get; set; }
/// <summary>
/// Specifies a method that returns the text of the node.
/// </summary>
[Parameter] [Parameter]
public Func<TItem, string> TitleExpression { get; set; } public Func<TreeNode<TItem>, string> TitleExpression { get; set; }
protected virtual Dictionary<string, object> TreeAttributes
{
get
{
return new()
{
{ "DataSource", DataSource },
{ "TitleExpression", DataSource == null ? null : TreeNodeTitleExpression },
{ "DefaultExpandAll", TreeDefaultExpandAll },
{ "KeyExpression", DataSource == null ? null : TreeNodeKeyExpression },
{ "ChildrenExpression", DataSource == null ? null : TreeNodeChildrenExpression },
{ "DisabledExpression", DataSource == null ? null : TreeNodeDisabledExpression },
{ "IsLeafExpression", DataSource == null ? null : TreeNodeIsLeafExpression }
};
}
}
protected Func<TreeNode<TItem>, string> TreeNodeKeyExpression
{
get
{
return node => KeyExpression(node.DataItem);
}
}
/// <summary>
/// Specifies a method that returns the key of the node.
/// </summary>
[Parameter] [Parameter]
public Func<TItem, string> KeyExpression { get; set; } public Func<TreeNode<TItem>, string> KeyExpression { get; set; }
protected Func<TreeNode<TItem>, string> TreeNodeIconExpression
{
get
{
return node => IconExpression(node.DataItem);
}
}
/// <summary> /// <summary>
/// Specifies a method to return the node icon. /// Specifies a method to return the node icon.
/// </summary> /// </summary>
[Parameter] [Parameter]
public Func<TItem, string> IconExpression { get; set; } public Func<TreeNode<TItem>, string> IconExpression { get; set; }
protected Func<TreeNode<TItem>, bool> TreeNodeIsLeafExpression
{
get
{
return node => IsLeafExpression(DataSource, node.DataItem);
}
}
private bool IsInnerModel => ChildContent != null;
/// <summary> /// <summary>
/// Specifies a method that returns whether the expression is a leaf node. /// Specifies a method that returns whether the expression is a leaf node.
/// </summary> /// </summary>
[Parameter] [Parameter]
public Func<IEnumerable<TItem>, TItem, bool> IsLeafExpression { get; set; } public Func<TreeNode<TItem>, bool> IsLeafExpression { get; set; }
protected virtual Func<TreeNode<TItem>, IList<TItem>> TreeNodeChildrenExpression
{
get
{
return node => ChildrenExpression == null ? null : ChildrenExpression(node.DataItem);
}
}
/// <summary>
/// Specifies a method to return a child node
/// </summary>
[Parameter] [Parameter]
public virtual Func<TItem, IList<TItem>> ChildrenExpression { get; set; } public Func<TreeNode<TItem>, IEnumerable<TItem>> ChildrenExpression { get; set; }
protected Func<TreeNode<TItem>, bool> TreeNodeDisabledExpression
{
get
{
return node => DisabledExpression != null && DisabledExpression(node.DataItem);
}
}
/// <summary> /// <summary>
/// Specifies a method to return a disabled node /// Specifies a method to return a disabled node
/// </summary> /// </summary>
[Parameter] [Parameter]
public Func<TItem, bool> DisabledExpression { get; set; } public Func<TreeNode<TItem>, bool> DisabledExpression { get; set; }
[Parameter] public OneOf<bool, string> DropdownMatchSelectWidth { get; set; } = true;
[Parameter] public string DropdownMaxWidth { get; set; } = "auto";
[Parameter] public string PopupContainerMaxHeight { get; set; } = "256px";
private bool IsMultiple => Multiple || TreeCheckable; private bool IsMultiple => Multiple || TreeCheckable;
private bool IsTemplatedNodes => ChildContent != null;
internal override SelectMode SelectMode => IsMultiple ? SelectMode.Multiple : base.SelectMode; internal override SelectMode SelectMode => IsMultiple ? SelectMode.Multiple : base.SelectMode;
private string[] SelectedKeys => Values?.ToArray(); private string[] SelectedKeys => Values?.ToArray();
//private readonly IList<TreeNode<TItem>> _selectedNodes = new List<TreeNode<TItem>>();
private string _dropdownStyle = string.Empty; private string _dropdownStyle = string.Empty;
private bool _multiple; private bool _multiple;
private readonly string _dir = "ltr"; private readonly string _dir = "ltr";
private Tree<TItem> _tree;
public override string Value public override string Value
{ {
get => base.Value; get => base.Value;
set set
{ {
if (string.IsNullOrEmpty(value))
return;
if (base.Value == value) if (base.Value == value)
return; return;
base.Value = value; base.Value = value;
if (SelectOptionItems.Any(o => o.Value == value)) if (value == null)
{ {
_ = SetValueAsync(SelectOptionItems.First(o => o.Value == value)); ClearOptions();
}
else
{
var data = DataItemExpression?.Invoke(DataSource, value);
if (data != null)
{
var o = CreateOption(data, true);
_ = SetValueAsync(o);
}
} }
UpdateValueAndSelection();
} }
} }
@ -220,12 +144,6 @@ namespace AntDesign
get => base.Values; get => base.Values;
set set
{ {
if (!_isInitialized)
return;
if (!Multiple)
throw new NotImplementedException("not Multiple select, no die");
if (value != null && _selectedValues != null) if (value != null && _selectedValues != null)
{ {
var hasChanged = !value.SequenceEqual(_selectedValues); var hasChanged = !value.SequenceEqual(_selectedValues);
@ -233,31 +151,24 @@ namespace AntDesign
if (!hasChanged) if (!hasChanged)
return; return;
ClearOptions();
_selectedValues = value; _selectedValues = value;
CreateOptions(value);
_ = OnValuesChangeAsync(value);
} }
else if (value != null && _selectedValues == null) else if (value != null && _selectedValues == null)
{ {
_selectedValues = value; _selectedValues = value;
CreateOptions(value);
_ = OnValuesChangeAsync(value);
} }
else if (value == null && _selectedValues != null) else if (value == null && _selectedValues != null)
{ {
_selectedValues = default; _selectedValues = default;
ClearOptions(); ClearOptions();
_ = OnValuesChangeAsync(default);
} }
UpdateValuesSelection();
if (_isNotifyFieldChanged && (Form?.ValidateOnChange == true)) if (_isNotifyFieldChanged && (Form?.ValidateOnChange == true))
{ {
EditContext?.NotifyFieldChanged(FieldIdentifier); EditContext?.NotifyFieldChanged(FieldIdentifier);
} }
} }
} }
@ -265,41 +176,26 @@ namespace AntDesign
{ {
SelectOptionItems.Clear(); SelectOptionItems.Clear();
SelectedOptionItems.Clear(); SelectedOptionItems.Clear();
_tree?._allNodes.ForEach(x => x.SetSelected(false));
} }
private void CreateOptions(IEnumerable<string> data) private void CreateOptions(IEnumerable<string> data)
{ {
if (IsInnerModel) if (IsTemplatedNodes)
{ {
var d1 = data.Where(d => !SelectOptionItems.Any(o => o.Value == d)); var d1 = data.Where(d => !SelectOptionItems.Any(o => o.Value == d));
CreateOptionsByTreeNode(d1); CreateOptionsByTreeNode(d1);
return; return;
} }
// 通过DataItemExpression来生成选中项 data.ForEach(menuId =>
if (DataItemExpression != null)
{ {
data.ForEach(menuId => var d = _tree._allNodes.FirstOrDefault(m => m.Key == menuId);
if (d != null)
{ {
var d = DataItemExpression?.Invoke(DataSource, menuId); var o = CreateOption(d, true);
if (d != null) }
{ });
var o = CreateOption(d, true);
}
});
}
else
{
// 通过目前的树节点生成选中项对于延时的节点建议使用DataItemExpression来加载
data.ForEach(menuId =>
{
var d = _tree._allNodes.FirstOrDefault(m => m.Key == menuId);
if (d != null)
{
var o = CreateOption(d, true);
}
});
}
} }
private void CreateOptionsByTreeNode(IEnumerable<string> data) private void CreateOptionsByTreeNode(IEnumerable<string> data)
@ -319,36 +215,30 @@ namespace AntDesign
var o = new SelectOptionItem<string, TItem>() var o = new SelectOptionItem<string, TItem>()
{ {
Label = data.Title, Label = data.Title,
LabelTemplate = data.TitleTemplate,
Value = data.Key, Value = data.Key,
Item = data.DataItem, Item = data.DataItem,
IsAddedTag = SelectMode != SelectMode.Default IsAddedTag = SelectMode != SelectMode.Default,
}; };
if (append && !SelectOptionItems.Any(m => m.Value == o.Value)) if (append && !SelectOptionItems.Any(m => m.Value == o.Value))
SelectOptionItems.Add(o); SelectOptionItems.Add(o);
return o; return o;
} }
private SelectOptionItem<string, TItem> CreateOption(TItem data, bool append = false) protected override Task OnFirstAfterRenderAsync()
{ {
var o = new SelectOptionItem<string, TItem>() if (Value != null)
{ {
Label = TitleExpression(data), UpdateValueAndSelection();
Value = KeyExpression(data), }
Item = data,
IsAddedTag = SelectMode != SelectMode.Default
};
if (append && !SelectOptionItems.Any(m => m.Value == o.Value))
SelectOptionItems.Add(o);
return o;
}
protected override void OnInitialized() if (Values != null)
{ {
SelectOptions = "".ToRenderFragment(); UpdateValuesSelection();
//_inputValue = Value; }
base.OnInitialized();
}
return base.OnFirstAfterRenderAsync();
}
private void OnKeyDownAsync(KeyboardEventArgs args) private void OnKeyDownAsync(KeyboardEventArgs args)
{ {
@ -377,6 +267,7 @@ namespace AntDesign
await SetDropdownStyleAsync(); await SetDropdownStyleAsync();
} }
} }
protected async Task OnRemoveSelectedAsync(SelectOptionItem<string, TItem> selectOption) protected async Task OnRemoveSelectedAsync(SelectOptionItem<string, TItem> selectOption)
{ {
if (selectOption == null) throw new ArgumentNullException(nameof(selectOption)); if (selectOption == null) throw new ArgumentNullException(nameof(selectOption));
@ -389,43 +280,56 @@ namespace AntDesign
} }
} }
private async Task OnTreeNodeClick(TreeEventArgs<TItem> args) private async Task OnTreeNodeClick(TreeEventArgs<TItem> args)
{ {
if (!args.Node.Selected) var node = args.Node;
if (!TreeCheckable && !node.Selected)
return; return;
var key = args.Node.Key; var key = node.Key;
if (Value != null && Value.Equals(key)) if (Value != null && Value.Equals(key))
return; return;
if (Values != null && Values.Contains(key)) if (Values != null && Values.Contains(key))
return; return;
var data = args.Node; var option = CreateOption(node, true);
SelectOptionItem<string, TItem> item;
if (IsInnerModel)
item = CreateOption(data, true);
else
item = CreateOption(data.DataItem, true);
//_selectedNodes.Add(data); await SetValueAsync(option);
await SetValueAsync(item); if (!Multiple)
{
var unselectedNodes = _tree._allNodes.Where(x => x.Key != node.Key);
unselectedNodes.ForEach(x => x.SetSelected(false));
}
if (SelectMode == SelectMode.Default) if (SelectMode == SelectMode.Default)
{
await CloseAsync(); await CloseAsync();
}
} }
protected async Task OnTreeNodeUnSelect(TreeEventArgs<TItem> args)
protected void OnTreeNodeUnSelect(TreeEventArgs<TItem> args)
{ {
if (args == null) throw new ArgumentNullException(nameof(args)); // Prevent deselect in sigle selection mode
var key = args.Node.Key; if (!Multiple && args.Node.Key == Value)
var nodes = SelectOptionItems.Where(o => o.Value == key).ToArray();
foreach (var item in nodes)
{ {
_ = SetValueAsync(item); args.Node.SetSelected(true);
return;
} }
// Deselect in Multiple mode
var node = SelectOptionItems.Where(o => o.Value == args.Node.Key).FirstOrDefault();
if (node != null)
{
await SetValueAsync(node);
}
}
private async Task OnTreeCheck(TreeEventArgs<TItem> args)
{
var option = CreateOption(args.Node, true);
await SetValueAsync(option);
} }
protected async Task SetDropdownStyleAsync() protected async Task SetDropdownStyleAsync()
@ -444,7 +348,7 @@ namespace AntDesign
} }
if (!DropdownMaxWidth.Equals("auto", StringComparison.CurrentCultureIgnoreCase)) if (!DropdownMaxWidth.Equals("auto", StringComparison.CurrentCultureIgnoreCase))
maxWidth = $"max-width: {DropdownMaxWidth};"; maxWidth = $"max-width: {DropdownMaxWidth};";
_dropdownStyle = minWidth + definedWidth + maxWidth; _dropdownStyle = minWidth + definedWidth + maxWidth + DropdownStyle ?? "";
if (Multiple) if (Multiple)
{ {
@ -458,7 +362,6 @@ namespace AntDesign
} }
} }
protected override void SetClassMap() protected override void SetClassMap()
{ {
var classPrefix = "ant-select"; var classPrefix = "ant-select";
@ -466,17 +369,51 @@ namespace AntDesign
.Add(classPrefix) .Add(classPrefix)
.Add("ant-tree-select") .Add("ant-tree-select")
.If("ant-select-lg", () => Size == "large") .If("ant-select-lg", () => Size == "large")
.If("ant-select-rtl", () => _dir == "rtl") .If("ant-select-sm", () => Size == "small")
.If("ant-select-sm", () => Size == "rtl") .If("ant-select-rtl", () => RTL)
.If("ant-select-disabled", () => Disabled) .If("ant-select-disabled", () => Disabled)
.If("ant-select-single", () => SelectMode == SelectMode.Default) .If("ant-select-single", () => SelectMode == SelectMode.Default)
.If($"ant-select-multiple", () => SelectMode != SelectMode.Default) .If("ant-select-multiple", () => SelectMode != SelectMode.Default)
.If("ant-select-show-arrow", () => !IsMultiple) .If("ant-select-show-arrow", () => !IsMultiple)
.If("ant-select-show-search", () => !IsMultiple) .If("ant-select-show-search", () => !IsMultiple)
.If("ant-select-allow-clear", () => AllowClear) .If("ant-select-allow-clear", () => AllowClear)
.If("ant-select-open", () => Open) .If("ant-select-open", () => Open)
.If("ant-select-focused", () => Open || Focused) .If("ant-select-focused", () => Open || Focused)
.If("ant-select-status-error", () => Status == "error")
.If("ant-select-status-warning", () => Status == "warning")
; ;
} }
private void UpdateValueAndSelection()
{
if (SelectOptionItems.Any(o => o.Value == Value))
{
_ = SetValueAsync(SelectOptionItems.First(o => o.Value == Value));
}
else
{
var data = _tree?._allNodes.FirstOrDefault(x => x.Key == Value);
if (data != null)
{
var o = CreateOption(data, true);
_ = SetValueAsync(o);
}
}
}
private void UpdateValuesSelection()
{
if (_tree == null)
return;
if (_selectedValues?.Any() != true)
{
ClearOptions();
return;
}
CreateOptions(_selectedValues);
_ = OnValuesChangeAsync(_selectedValues);
}
} }
} }

View File

@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Text;
namespace AntDesign
{
public interface ITreeData<TItem>
{
public string Key { get; set; }
public string Title { get; set; }
public TItem Value { get; }
public IEnumerable<TItem> Children { get; set; }
}
}

View File

@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
@ -94,7 +94,7 @@ namespace AntDesign
private bool _hasSetShowLeafIcon; private bool _hasSetShowLeafIcon;
/// <summary> /// <summary>
/// Specific the Icon type of switcher /// Specific the Icon type of switcher
/// </summary> /// </summary>
[Parameter] [Parameter]
public string SwitcherIcon { get; set; } public string SwitcherIcon { get; set; }
@ -190,9 +190,9 @@ namespace AntDesign
if (SelectedNodesDictionary.ContainsKey(treeNode.NodeId) == true) if (SelectedNodesDictionary.ContainsKey(treeNode.NodeId) == true)
SelectedNodesDictionary.Remove(treeNode.NodeId); SelectedNodesDictionary.Remove(treeNode.NodeId);
if (OnUnSelect.HasDelegate) if (OnUnselect.HasDelegate)
{ {
OnUnSelect.InvokeAsync(new TreeEventArgs<TItem>(this, treeNode)); OnUnselect.InvokeAsync(new TreeEventArgs<TItem>(this, treeNode));
} }
} }
@ -355,6 +355,14 @@ namespace AntDesign
} }
} }
public void SelectAll()
{
foreach (var item in ChildNodes)
{
item.SetSelected(true);
}
}
/// <summary> /// <summary>
/// Specifies the keys of the default checked treeNodes /// Specifies the keys of the default checked treeNodes
/// </summary> /// </summary>
@ -377,6 +385,7 @@ namespace AntDesign
_checkedNodes.TryAdd(treeNode.NodeId, treeNode); _checkedNodes.TryAdd(treeNode.NodeId, treeNode);
else else
_checkedNodes.TryRemove(treeNode.NodeId, out TreeNode<TItem> _); _checkedNodes.TryRemove(treeNode.NodeId, out TreeNode<TItem> _);
_checkedKeys = _checkedNodes.Select(x => x.Value.Key).ToArray(); _checkedKeys = _checkedNodes.Select(x => x.Value.Key).ToArray();
if (!old.SequenceEqual(_checkedKeys) && CheckedKeysChanged.HasDelegate) if (!old.SequenceEqual(_checkedKeys) && CheckedKeysChanged.HasDelegate)
@ -419,12 +428,6 @@ namespace AntDesign
private void SearchNodes() private void SearchNodes()
{ {
if (string.IsNullOrWhiteSpace(_searchValue))
{
_allNodes.ForEach(m => { m.Expand(true); m.Matched = false; });
return;
}
var allList = _allNodes.ToList(); var allList = _allNodes.ToList();
List<TreeNode<TItem>> searchDatas = null, exceptList = null; List<TreeNode<TItem>> searchDatas = null, exceptList = null;
@ -489,7 +492,7 @@ namespace AntDesign
/// Specifies a method to return a child node /// Specifies a method to return a child node
/// </summary> /// </summary>
[Parameter] [Parameter]
public Func<TreeNode<TItem>, IList<TItem>> ChildrenExpression { get; set; } public Func<TreeNode<TItem>, IEnumerable<TItem>> ChildrenExpression { get; set; }
/// <summary> /// <summary>
/// Specifies a method to return a disabled node /// Specifies a method to return a disabled node
@ -536,7 +539,7 @@ namespace AntDesign
public EventCallback<TreeEventArgs<TItem>> OnSelect { get; set; } public EventCallback<TreeEventArgs<TItem>> OnSelect { get; set; }
[Parameter] [Parameter]
public EventCallback<TreeEventArgs<TItem>> OnUnSelect { get; set; } public EventCallback<TreeEventArgs<TItem>> OnUnselect { get; set; }
/// <summary> /// <summary>
/// Click the expansion tree node icon to call back /// Click the expansion tree node icon to call back
@ -620,6 +623,33 @@ namespace AntDesign
base.OnInitialized(); base.OnInitialized();
} }
protected override Task OnFirstAfterRenderAsync()
{
this.DefaultCheckedKeys?.ForEach(k =>
{
var node = this._allNodes.FirstOrDefault(x => x.Key == k);
if (node != null)
node.SetCheckedDefault(true);
});
this.DefaultSelectedKeys?.ForEach(k =>
{
var node = this._allNodes.FirstOrDefault(x => x.Key == k);
if (node != null)
node.SetSelected(true);
});
if (!this.DefaultExpandAll)
{
this.DefaultExpandedKeys?.ForEach(k =>
{
var node = this._allNodes.FirstOrDefault(x => x.Key == k);
if (node != null)
node.OpenPropagation();
});
}
return base.OnFirstAfterRenderAsync();
}
/// <summary> /// <summary>
/// Find Node /// Find Node
/// </summary> /// </summary>

View File

@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
@ -50,7 +50,7 @@ namespace AntDesign
public int TreeLevel => (ParentNode?.TreeLevel ?? -1) + 1; public int TreeLevel => (ParentNode?.TreeLevel ?? -1) + 1;
/// <summary> /// <summary>
/// record the index in children nodes list of parent node. /// record the index in children nodes list of parent node.
/// </summary> /// </summary>
internal int NodeIndex { get; set; } internal int NodeIndex { get; set; }
@ -157,7 +157,7 @@ namespace AntDesign
_key = value; _key = value;
} }
} }
private bool _disabled; private bool _disabled;
/// <summary> /// <summary>
@ -193,11 +193,7 @@ namespace AntDesign
public void SetSelected(bool value) public void SetSelected(bool value)
{ {
if (Disabled) return; if (Disabled) return;
if (!TreeComponent.Selectable && TreeComponent.Checkable)
{
SetChecked(!Checked);
return;
}
if (_selected == value) return; if (_selected == value) return;
_selected = value; _selected = value;
if (value == true) if (value == true)
@ -397,12 +393,11 @@ namespace AntDesign
#region Checkbox #region Checkbox
private bool _checked;
/// <summary> /// <summary>
/// According to check the /// According to check the
/// </summary> /// </summary>
[Parameter] [Parameter]
public bool Checked { get; set; } public bool Checked { get; set; }
[Parameter] [Parameter]
public bool Indeterminate { get; set; } public bool Indeterminate { get; set; }
@ -460,6 +455,24 @@ namespace AntDesign
TreeComponent.AddOrRemoveCheckNode(this); TreeComponent.AddOrRemoveCheckNode(this);
StateHasChanged(); StateHasChanged();
} }
/// <summary>
/// Set the checkbox state when ini
/// </summary>
/// <param name="check"></param>
public void SetCheckedDefault(bool check)
{
if (TreeComponent.CheckStrictly)
{
this.Checked = check;
}
else
{
SetChildCheckedDefault(this, check);
if (ParentNode != null)
ParentNode.UpdateCheckStateDefault();
}
StateHasChanged();
}
/// <summary> /// <summary>
/// Sets the checkbox status of child nodes /// Sets the checkbox status of child nodes
@ -476,6 +489,20 @@ namespace AntDesign
foreach (var child in subnode.ChildNodes) foreach (var child in subnode.ChildNodes)
child?.SetChildChecked(child, check); child?.SetChildChecked(child, check);
} }
/// <summary>
/// Sets the checkbox status of child nodes whern bind default
/// </summary>
/// <param name="subnode"></param>
/// <param name="check"></param>
private void SetChildCheckedDefault(TreeNode<TItem> subnode, bool check)
{
this.Checked = check;
this.Indeterminate = false;
TreeComponent.AddOrRemoveCheckNode(this);
if (subnode.HasChildNodes)
foreach (var child in subnode.ChildNodes)
child?.SetChildCheckedDefault(child, check);
}
/// <summary> /// <summary>
/// Update check status /// Update check status
@ -540,6 +567,66 @@ namespace AntDesign
if (ParentNode == null) if (ParentNode == null)
StateHasChanged(); StateHasChanged();
} }
/// <summary>
/// Update check status when bind default
/// </summary>
/// <param name="halfChecked"></param>
private void UpdateCheckStateDefault(bool? halfChecked = null)
{
if (halfChecked == true)
{
//If the child node is indeterminate, the parent node must is indeterminate.
this.Checked = false;
this.Indeterminate = true;
}
else if (HasChildNodes == true && !DisableCheckbox)
{
//Determines the selection status of the current node
bool hasChecked = false;
bool hasUnchecked = false;
foreach (var item in ChildNodes)
{
if (item.Indeterminate)
{
hasChecked = true;
hasUnchecked = true;
break;
}
else if (item.Checked)
{
hasChecked = true;
}
else if (!item.Checked)
{
hasUnchecked = true;
}
}
if (hasChecked && !hasUnchecked)
{
this.Checked = true;
this.Indeterminate = false;
}
else if (!hasChecked && hasUnchecked)
{
this.Checked = false;
this.Indeterminate = false;
}
else if (hasChecked && hasUnchecked)
{
this.Checked = false;
this.Indeterminate = true;
}
}
TreeComponent.AddOrRemoveCheckNode(this);
if (ParentNode != null)
ParentNode.UpdateCheckStateDefault(this.Indeterminate);
if (ParentNode == null)
StateHasChanged();
}
#endregion Checkbox #endregion Checkbox
@ -621,7 +708,7 @@ namespace AntDesign
get get
{ {
if (TreeComponent.ChildrenExpression != null) if (TreeComponent.ChildrenExpression != null)
return TreeComponent.ChildrenExpression(this) ?? new List<TItem>(); return TreeComponent.ChildrenExpression(this)?.ToList() ?? new List<TItem>();
else else
return new List<TItem>(); return new List<TItem>();
} }
@ -789,8 +876,6 @@ namespace AntDesign
#endregion Node data operation #endregion Node data operation
bool _defaultBinding;
protected override void OnInitialized() protected override void OnInitialized()
{ {
SetTreeNodeClassMapper(); SetTreeNodeClassMapper();
@ -817,73 +902,22 @@ namespace AntDesign
if (TreeComponent.Selectable && TreeComponent.SelectedKeys != null) if (TreeComponent.Selectable && TreeComponent.SelectedKeys != null)
{ {
this.Selected = TreeComponent.SelectedKeys.Any(k => k == this.Key); this.Selected = TreeComponent.SelectedKeys.Any(k => k == this.Key);
this.SetChecked(this.Selected);
}
if (TreeComponent.Selectable && TreeComponent.SelectedKeys != null)
{
this.Selected = TreeComponent.SelectedKeys.Any(k => k == this.Key);
}
if (this.Checked)
this.SetChecked(true);
if (!TreeComponent.DefaultExpandAll)
{
if (this.Expanded)
this.OpenPropagation();
} }
base.OnInitialized(); base.OnInitialized();
} }
protected override void OnParametersSet()
{
DefaultBinding();
base.OnParametersSet();
}
private void DefaultBinding()
{
if (!_defaultBinding)
{
_defaultBinding = true;
if (this.Checked)
this.SetChecked(true);
this.SetChecked(TreeComponent?.DefaultCheckedKeys?.Any(k => k == Key) ?? false);
this.SetSelected(TreeComponent?.DefaultSelectedKeys?.Any(k => k == Key) ?? false);
if (!TreeComponent.DefaultExpandAll)
{
if (this.Expanded)
this.OpenPropagation();
if (TreeComponent.DefaultExpandedKeys != null)
{
if (TreeComponent.DefaultExpandedKeys.Contains(this.Key))
{
this.OpenPropagation();
};
}
}
}
}
private void DefaultBindingold()
{
if (!_defaultBinding)
{
_defaultBinding = true;
if (this.Checked)
this.SetChecked(true);
TreeComponent.DefaultCheckedKeys?.ForEach(k =>
{
var node = TreeComponent._allNodes.FirstOrDefault(x => x.Key == k);
if (node != null)
node.SetChecked(true);
});
TreeComponent.DefaultSelectedKeys?.ForEach(k =>
{
var node = TreeComponent._allNodes.FirstOrDefault(x => x.Key == k);
if (node != null)
node.SetSelected(true);
});
if (!TreeComponent.DefaultExpandAll)
{
if (this.Expanded)
this.OpenPropagation();
TreeComponent.DefaultExpandedKeys?.ForEach(k =>
{
var node = TreeComponent._allNodes.FirstOrDefault(x => x.Key == k);
if (node != null)
node.OpenPropagation();
});
}
}
}
} }
} }

View File

@ -39,11 +39,17 @@ namespace AntDesign
return JsonSerializer.Deserialize<TResponseModel>(this.Response, options); return JsonSerializer.Deserialize<TResponseModel>(this.Response, options);
} }
public static string[] ImageExtensions { get; set; } = new[] { ".jpg", ".png", ".gif", ".ico", ".jfif", ".jpeg", ".bmp", ".tga", ".svg", ".tif", ".webp" };
public bool IsPicture() public bool IsPicture()
{ {
string[] imageTypes = new[] { ".jpg", ".png", ".gif", ".ico",".jfif",".jpeg",".bmp",".tga",".svg",".tif" }; if (string.IsNullOrEmpty(Ext))
Ext = FileName.Substring(FileName.LastIndexOf('.')); {
return imageTypes.Any(imageType => imageType.Equals(Ext, StringComparison.InvariantCultureIgnoreCase)); var lastIndex = FileName.LastIndexOf('.');
if (lastIndex < 0) return false;
Ext = FileName[lastIndex..];
}
return ImageExtensions.Any(imageExt => imageExt.Equals(Ext, StringComparison.InvariantCultureIgnoreCase));
} }
} }
} }

View File

@ -47,6 +47,18 @@ $ dotnet publish -c release -o dist
$ dotnet add package AntDesign $ dotnet add package AntDesign
``` ```
### 注册依赖
`Startup.cs` 文件中注册 AntDesign 服务
```cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAntDesign();
}
```
### 引入样式 ### 引入样式
#### 使用样式与脚本 #### 使用样式与脚本

View File

@ -8,7 +8,7 @@ Following the Ant Design specification, we developed a Blazor Components library
<div class="pic-plus"> <div class="pic-plus">
<img width="150" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"> <img width="150" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
<span>+</span> <span>+</span>
<img height="150" src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/docs/assets/blazor.svg"> <img height="150" src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/master/docs/assets/blazor.svg">
</div> </div>
<style> <style>
@ -49,7 +49,7 @@ WebAssembly static hosting examples:
- Run directly on [.NET MAUI](https://dotnet.microsoft.com/zh-cn/apps/maui?WT.mc_id=DT-MVP-5003987) / [WPF](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/wpf?view=aspnetcore-6.0&WT.mc_id=DT-MVP-5003987) / [Windows Forms](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/windows-forms?view=aspnetcore-6.0) and other Blazor Hybrid workloads. - Run directly on [.NET MAUI](https://dotnet.microsoft.com/zh-cn/apps/maui?WT.mc_id=DT-MVP-5003987) / [WPF](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/wpf?view=aspnetcore-6.0&WT.mc_id=DT-MVP-5003987) / [Windows Forms](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/windows-forms?view=aspnetcore-6.0) and other Blazor Hybrid workloads.
- Run directly on [Electron](http://electron.atom.io/) and other Web standards-based environments. - Run directly on [Electron](http://electron.atom.io/) and other Web standards-based environments.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br> Edge / IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br> Edge / IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron |
| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| Edge 16 / IE 11† | 522 | 57 | 11 | 44 | Chromium 57 | | Edge 16 / IE 11† | 522 | 57 | 11 | 44 | Chromium 57 |
@ -77,7 +77,7 @@ We have provided the `dotnet new` template to create a [Boilerplate](https://git
- Install the template - Install the template
```bash ```bash
$ dotnet new --install AntDesign.Templates::0.1.0-* $ dotnet new --install AntDesign.Templates
``` ```
- Create the Boilerplate project with the template - Create the Boilerplate project with the template
@ -101,7 +101,7 @@ Options for the template
- Go to the project folder of the application and install the Nuget package reference - Go to the project folder of the application and install the Nuget package reference
```bash ```bash
$ dotnet add package AntDesign --version 0.1.0-* $ dotnet add package AntDesign
``` ```
- Register the services - Register the services
@ -148,7 +148,7 @@ Options for the template
## 🔨 Local Development ## 🔨 Local Development
- Install [.NET Core SDK](https://dotnet.microsoft.com/download?WT.mc_id=DT-MVP-5003987) 5.0.100 or later. - Install [.NET Core SDK](https://dotnet.microsoft.com/download?WT.mc_id=DT-MVP-5003987) 6.0.x or later.
- Install Node.js (only for building style files and interoperable TypeScript files) - Install Node.js (only for building style files and interoperable TypeScript files)
- Clone to local development - Clone to local development
@ -161,7 +161,7 @@ Options for the template
- Visit https://localhost:5001 in your supported browser and check [local development documentation](https://github.com/ant-design-blazor/ant-design-blazor/wiki) for details. - Visit https://localhost:5001 in your supported browser and check [local development documentation](https://github.com/ant-design-blazor/ant-design-blazor/wiki) for details.
> Visual Studio 2019 is recommended for development. > Visual Studio 2022 is recommended for development.
## 🔗 Links ## 🔗 Links
@ -169,10 +169,6 @@ Options for the template
- [Official Blazor Documentation](https://docs.microsoft.com/en-us/aspnet/core/blazor/?WT.mc_id=DT-MVP-5003987) - [Official Blazor Documentation](https://docs.microsoft.com/en-us/aspnet/core/blazor/?WT.mc_id=DT-MVP-5003987)
- [MS Learn for Blazor Tutorial](https://docs.microsoft.com/en-us/learn/modules/build-blazor-webassembly-visual-studio-code/?WT.mc_id=DT-MVP-5003987) - [MS Learn for Blazor Tutorial](https://docs.microsoft.com/en-us/learn/modules/build-blazor-webassembly-visual-studio-code/?WT.mc_id=DT-MVP-5003987)
## 🗺 Roadmap
Check out this [issue](https://github.com/ant-design-blazor/ant-design-blazor/issues/21) to learn about our development plans for 2020.
## 🤝 Contributing ## 🤝 Contributing
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/ant-design-blazor/ant-design-blazor/pulls) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/ant-design-blazor/ant-design-blazor/pulls)

View File

@ -8,7 +8,7 @@ title: Ant Design of Blazor
<div class="pic-plus"> <div class="pic-plus">
<img width="150" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"> <img width="150" src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg">
<span>+</span> <span>+</span>
<img height="150" src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/docs/assets/blazor.svg"> <img height="150" src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/master/docs/assets/blazor.svg">
</div> </div>
<style> <style>
@ -48,7 +48,7 @@ title: Ant Design of Blazor
- 可直接运行在 [.NET MAUI](https://dotnet.microsoft.com/zh-cn/apps/maui?WT.mc_id=DT-MVP-5003987)、[WPF](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/wpf?view=aspnetcore-6.0&WT.mc_id=DT-MVP-5003987)、[Windows Forms](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/windows-forms?view=aspnetcore-6.0) 等 Blazor 混合客户端环境中。 - 可直接运行在 [.NET MAUI](https://dotnet.microsoft.com/zh-cn/apps/maui?WT.mc_id=DT-MVP-5003987)、[WPF](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/wpf?view=aspnetcore-6.0&WT.mc_id=DT-MVP-5003987)、[Windows Forms](https://docs.microsoft.com/en-us/aspnet/core/blazor/hybrid/tutorials/windows-forms?view=aspnetcore-6.0) 等 Blazor 混合客户端环境中。
- 可直接运行在 [Electron](http://electron.atom.io/) 等基于 Web 标准的环境上 - 可直接运行在 [Electron](http://electron.atom.io/) 等基于 Web 标准的环境上
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br> Edge / IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron | | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br> Edge / IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png" alt="Opera" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Opera | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/electron/electron_48x48.png" alt="Electron" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Electron |
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| Edge 16 / IE 11† | 522 | 57 | 11 | 44 | Chromium 57 | | Edge 16 / IE 11† | 522 | 57 | 11 | 44 | Chromium 57 |
@ -76,7 +76,7 @@ title: Ant Design of Blazor
- 安装模板 - 安装模板
```bash ```bash
$ dotnet new --install AntDesign.Templates::0.1.0-* $ dotnet new --install AntDesign.Templates
``` ```
- 从模板创建 Ant Design Blazor Pro 项目 - 从模板创建 Ant Design Blazor Pro 项目
@ -98,7 +98,7 @@ title: Ant Design of Blazor
- 进入应用的项目文件夹,安装 Nuget 包引用 - 进入应用的项目文件夹,安装 Nuget 包引用
```bash ```bash
$ dotnet add package AntDesign --version 0.1.0-* $ dotnet add package AntDesign
``` ```
- 在项目中注册: - 在项目中注册:
@ -182,7 +182,7 @@ title: Ant Design of Blazor
- [![钉钉群](https://img.shields.io/badge/钉钉-AntBlazor-blue.svg?style=flat-square&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg0KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGNsYXNzPSJpY29uIiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiBmaWxsPSIjZmZmZmZmIj4NCiAgPHBhdGggZD0iTTU3My43IDI1Mi41QzQyMi41IDE5Ny40IDIwMS4zIDk2LjcgMjAxLjMgOTYuN2MtMTUuNy00LjEtMTcuOSAxMS4xLTE3LjkgMTEuMS01IDYxLjEgMzMuNiAxNjAuNSA1My42IDE4Mi44IDE5LjkgMjIuMyAzMTkuMSAxMTMuNyAzMTkuMSAxMTMuN1MzMjYgMzU3LjkgMjcwLjUgMzQxLjljLTU1LjYtMTYtMzcuOSAxNy44LTM3LjkgMTcuOCAxMS40IDYxLjcgNjQuOSAxMzEuOCAxMDcuMiAxMzguNCA0Mi4yIDYuNiAyMjAuMSA0IDIyMC4xIDRzLTM1LjUgNC4xLTkzLjIgMTEuOWMtNDIuNyA1LjgtOTcgMTIuNS0xMTEuMSAxNy44LTMzLjEgMTIuNSAyNCA2Mi42IDI0IDYyLjYgODQuNyA3Ni44IDEyOS43IDUwLjUgMTI5LjcgNTAuNSAzMy4zLTEwLjcgNjEuNC0xOC41IDg1LjItMjQuMkw1NjUgNzQzLjFoODQuNkw2MDMgOTI4bDIwNS4zLTI3MS45SDcwMC44bDIyLjMtMzguN2MuMy41LjQuOC40LjhTNzk5LjggNDk2LjEgODI5IDQzMy44bC42LTFoLS4xYzUtMTAuOCA4LjYtMTkuNyAxMC0yNS44IDE3LTcxLjMtMTE0LjUtOTkuNC0yNjUuOC0xNTQuNXoiLz4NCjwvc3ZnPg0K)](https://h5.dingtalk.com/circle/healthCheckin.html?corpId=dingf3df1949a4aa48627b0128d9a44ecb79&c5df5865-4f41-=be1b34c7-397b-&cbdbhh=qwertyuiop&origin=11) (中文) - [![钉钉群](https://img.shields.io/badge/钉钉-AntBlazor-blue.svg?style=flat-square&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg0KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGNsYXNzPSJpY29uIiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiBmaWxsPSIjZmZmZmZmIj4NCiAgPHBhdGggZD0iTTU3My43IDI1Mi41QzQyMi41IDE5Ny40IDIwMS4zIDk2LjcgMjAxLjMgOTYuN2MtMTUuNy00LjEtMTcuOSAxMS4xLTE3LjkgMTEuMS01IDYxLjEgMzMuNiAxNjAuNSA1My42IDE4Mi44IDE5LjkgMjIuMyAzMTkuMSAxMTMuNyAzMTkuMSAxMTMuN1MzMjYgMzU3LjkgMjcwLjUgMzQxLjljLTU1LjYtMTYtMzcuOSAxNy44LTM3LjkgMTcuOCAxMS40IDYxLjcgNjQuOSAxMzEuOCAxMDcuMiAxMzguNCA0Mi4yIDYuNiAyMjAuMSA0IDIyMC4xIDRzLTM1LjUgNC4xLTkzLjIgMTEuOWMtNDIuNyA1LjgtOTcgMTIuNS0xMTEuMSAxNy44LTMzLjEgMTIuNSAyNCA2Mi42IDI0IDYyLjYgODQuNyA3Ni44IDEyOS43IDUwLjUgMTI5LjcgNTAuNSAzMy4zLTEwLjcgNjEuNC0xOC41IDg1LjItMjQuMkw1NjUgNzQzLjFoODQuNkw2MDMgOTI4bDIwNS4zLTI3MS45SDcwMC44bDIyLjMtMzguN2MuMy41LjQuOC40LjhTNzk5LjggNDk2LjEgODI5IDQzMy44bC42LTFoLS4xYzUtMTAuOCA4LjYtMTkuNyAxMC0yNS44IDE3LTcxLjMtMTE0LjUtOTkuNC0yNjUuOC0xNTQuNXoiLz4NCjwvc3ZnPg0K)](https://h5.dingtalk.com/circle/healthCheckin.html?corpId=dingf3df1949a4aa48627b0128d9a44ecb79&c5df5865-4f41-=be1b34c7-397b-&cbdbhh=qwertyuiop&origin=11) (中文)
<img src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/docs/assets/dingtalk.jpg" width="300"> <img src="https://raw.githubusercontent.com/ant-design-blazor/ant-design-blazor/master/docs/assets/dingtalk.jpg" width="300">
- 另外,我还创立了面向中文开发者的 Blazor 中文社区高手如云只讨论技术无卖课广告。可以加我微信JamesYeungMVP拉进微信群另外也有一个 QQ 群 1012762441。广告勿扰。 - 另外,我还创立了面向中文开发者的 Blazor 中文社区高手如云只讨论技术无卖课广告。可以加我微信JamesYeungMVP拉进微信群另外也有一个 QQ 群 1012762441。广告勿扰。

View File

@ -57,7 +57,7 @@
"husky": "^4.2.3", "husky": "^4.2.3",
"inquirer": "^7.1.0", "inquirer": "^7.1.0",
"jquery": "^3.4.1", "jquery": "^3.4.1",
"jsdom": "^16.0.0", "jsdom": "^16.5.0",
"less": "^4.1.0", "less": "^4.1.0",
"less-plugin-clean-css": "^1.5.1", "less-plugin-clean-css": "^1.5.1",
"less-plugin-npm-import": "^2.1.0", "less-plugin-npm-import": "^2.1.0",
@ -76,4 +76,4 @@
"dependencies": { "dependencies": {
"antblazor.js-ts.tests": "file:tests/AntDesign.Tests.Js" "antblazor.js-ts.tests": "file:tests/AntDesign.Tests.Js"
} }
} }

View File

@ -22,7 +22,7 @@
#if NET5_0_OR_GREATER #if NET5_0_OR_GREATER
var polyfillPath = "_framework/blazor.polyfill.min.js"; var polyfillPath = "_framework/blazor.polyfill.min.js";
#else #else
var polyfillPath = "https://raw.githubusercontent.com/Daddoon/Blazor.Polyfill@3.0.8/Publish/Blazor.Polyfill.Publish/blazor.polyfill.min.js"; var polyfillPath = "https://raw.githubusercontent.com/Daddoon/Blazor.Polyfill/3.0.8/Publish/Blazor.Polyfill.Publish/blazor.polyfill.min.js";
#endif #endif
#if NET6_0 #if NET6_0
var isNET6 = true; var isNET6 = true;

View File

@ -1,17 +1,41 @@
@inject DrawerService DrawerService @inject DrawerService DrawerService
@inject ConfirmService confirmService @inject ConfirmService confirmService
<Input @bind-Value="@value" /> <Space Direction="DirectionVHType.Vertical">
<br /> <SpaceItem>
<br /> <Space>
<Button OnClick="OpenComponent" Type="primary">Use Component</Button> <SpaceItem>
<Input @bind-Value="@value" />
</SpaceItem>
<SpaceItem>
<Button OnClick="OpenComponent" Type="primary">Use Component</Button>
</SpaceItem>
</Space>
</SpaceItem>
<SpaceItem>
<div>
<Button Type="primary" @onclick="@OpenDrawer">OpenDrawer</Button>
<Drawer Closable="true"
Visible="@visible"
Placement="right"
Title='("Basic Drawer")'
OnOpen="@OnOpen"
OnClose="@CloseDrawer">
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</Drawer>
</div>
</SpaceItem>
</Space>
@code{ @code{
// #region use component
private string value = "blazor"; private string value = "blazor";
// use component
private async Task OpenComponent() private async Task OpenComponent()
{ {
var options = new DrawerOptions() var options = new DrawerOptions()
@ -24,13 +48,13 @@
drawerRef.OnOpen = () => drawerRef.OnOpen = () =>
{ {
Console.WriteLine("OnAfterOpen"); Console.WriteLine("drawerRef OnOpen");
return Task.CompletedTask; return Task.CompletedTask;
}; };
drawerRef.OnClosing = async handle => drawerRef.OnClosing = async handle =>
{ {
Console.WriteLine("OnAfterClosing:"); Console.WriteLine("drawerRef OnClosing");
if (await confirmService.Show("Drawer to close?", "Confirm?", ConfirmButtons.YesNo) == ConfirmResult.No) if (await confirmService.Show("Drawer to close?", "Confirm?", ConfirmButtons.YesNo) == ConfirmResult.No)
{ {
@ -40,11 +64,38 @@
drawerRef.OnClosed = async result => drawerRef.OnClosed = async result =>
{ {
Console.WriteLine("OnAfterClosed:" + result); Console.WriteLine("drawerRef OnClosed, value:" + result);
if (result != null) if (result != null)
value = result; value = result;
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
}; };
} }
//# endregion
// #region use <Drawer></Drawer>
bool visible = false;
void OpenDrawer()
{
this.visible = true;
}
async Task OnOpen()
{
var confirmResult = await confirmService.Show("OnOpen event: Are you sure to close the drawer?", "Question", ConfirmButtons.YesNo);
if (confirmResult == ConfirmResult.Yes)
{
this.visible = false;
StateHasChanged();
}
}
void CloseDrawer()
{
this.visible = false;
}
// #endregion
} }

View File

@ -9,7 +9,26 @@ title:
Drawer 的事件处理 Drawer 的事件处理
对于 Drawer 组件:
1. OnOpen: 在打开前执行,并可以通过参数的 `Cancel` 属性取消打开操作。
2. OnClose: 在关闭前执行,你需要通过它来控制 Drawer 组件的 `Visible` 属性。
对于 DrawerService:
1. DrawerRef.OnOpen: 在打开前执行,内部是在 `Drawe.OnOpen` 事件中调用该方法
2. DrawerRef.OnClosing: 在关闭前执行
3. DrawerRef.OnClosed: 在关闭后执行。
## en-US ## en-US
Drawer event handling Drawer event handling
For Drawer component:
1. OnOpen: Execute before opening, and you can cancel the opening operation through the `Cancel` attribute of the parameter.
2. OnClose: Before closing, you need to control the `Visible` paramter of the Drawer component through it.
For DrawerService:
1. DrawerRef.OnOpen: Execute before opening, and call this method in `Drawe.OnOpen` event internally.
2. DrawerRef.OnClosing: Execute before closing
3. DrawerRef.OnClosed: Execute after shutdown

View File

@ -31,17 +31,18 @@ tasks can be achieved more efficiently within thesame context.
| ChildContent | Subcomponent | object | - | | ChildContent | Subcomponent | object | - |
| MaskClosable | Clicking on the mask (area outside the Drawer) to close the Drawer or not. | boolean | true | | MaskClosable | Clicking on the mask (area outside the Drawer) to close the Drawer or not. | boolean | true |
| MaskStyle | Style for Drawer's mask element. | object | - | | MaskStyle | Style for Drawer's mask element. | object | - |
| Mask | Whether to show mask or not. | boolean | true |
| Placement | The placement of the Drawer, option could be `left` , `top`,`right`,`bottom` | string | `right` | | Placement | The placement of the Drawer, option could be `left` , `top`,`right`,`bottom` | string | `right` |
| WrapClassName | The class name of the container of the Drawer dialog. | string | - | | WrapClassName | The class name of the container of the Drawer dialog. | string | - |
| Width | Width of the Drawer dialog. | | int | | Width | Width of the Drawer dialog, only when placement is 'left' or 'right'. | | int |
| Height | placement is top or bottom, height of the Drawer dialog. | int | 256 | | Height | placement is top or bottom, height of the Drawer dialog. | int | 256 |
| ZIndex | The z-index of the Drawer. | int | - | | ZIndex | The z-index of the Drawer. | int | - |
| OffsetX | The the X coordinate offset(px), only when placement is `'left'` or `'right'`. | int | 0 | | OffsetX | The the X coordinate offset(px), only when placement is `'left'` or `'right'`. | int | 0 |
| OffsetY | The the Y coordinate offset(px), only when placement is `'top'` or `'bottom'`. | int | 0 | | OffsetY | The the Y coordinate offset(px), only when placement is `'top'` or `'bottom'`. | int | 0 |
| Visible | Whether the Drawer dialog is visible or not. | boolean | - | | Visible | Whether the Drawer dialog is visible or not. | boolean | - |
| Keyboard | Whether support press esc to close | boolean | true | | Keyboard | Whether support press esc to close | boolean | true |
| OnClose | Specify a callback that will be called when a user clicks mask, close button or Cancel button. | function(e) | - | | OnClose | Specify a callback that will be called when a user clicks mask, close button or Cancel button. | EventCallback | - |
| OnViewInit | Specify a callback that will be called before drawer displayed | function(e) | - | | OnOpen | Specify a callback that will be called after drawer rendered | Func<Task> | - |
### DrawerService ### DrawerService
@ -62,7 +63,7 @@ tasks can be achieved more efficiently within thesame context.
| CloseOnNavigation | Whether to close the drawer when the navigation history changes | `boolean` | `true` | | CloseOnNavigation | Whether to close the drawer when the navigation history changes | `boolean` | `true` |
| Keyboard | Whether to support keyboard esc off | `boolean` | `true` | | Keyboard | Whether to support keyboard esc off | `boolean` | `true` |
| MaskStyle | Style for Drawer's mask element. | `string` | `{}` | | MaskStyle | Style for Drawer's mask element. | `string` | `{}` |
| BodyStyle | Body style for modal body element. Such as height, padding etc. | `string` | `{}` | | BodyStyle | Body style for Drawer body element. Such as height, padding etc. | `string` | `{}` |
| Title | The title for Drawer. | `OneOf<RenderFragment, string>` | - | | Title | The title for Drawer. | `OneOf<RenderFragment, string>` | - |
| Width | Width of the Drawer dialog. | `int` | `256` | | Width | Width of the Drawer dialog. | `int` | `256` |
| Height | Height of the Drawer dialog, only when placement is `'top'` or `'bottom'`. | `int` | `256` | | Height | Height of the Drawer dialog, only when placement is `'top'` or `'bottom'`. | `int` | `256` |

View File

@ -22,22 +22,23 @@ cover: https://gw.alipayobjects.com/zos/alicdn/7z8NJQhFb/Drawer.svg
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
| ------------- | ------------------------------------------------------- | -------------- | ------- | | ------------- | ------------------------------------------------------- | -------------- | ------- |
| Title | 标题 | string or slot | - | | Title | 标题 | string or slot | - |
| BodyStyle | 可用于设置 Drawer 内容部分的样式 | object | - | | BodyStyle | 可用于设置 Drawer 内容部分的样式 | object | - |
| Closable | 是否显示右上角的关闭按钮 | boolean | true | | Closable | 是否显示右上角的关闭按钮 | boolean | true |
| ChildContent | 抽屉元素之间的子组件 | object | - | | ChildContent | 抽屉元素之间的子组件 | object | - |
| MaskClosable | 点击蒙层是否允许关闭 | boolean | true | | MaskClosable | 点击蒙层是否允许关闭 | boolean | true |
| MaskStyle | 遮罩样式 | object | - | | MaskStyle | 遮罩样式 | object | - |
| Placement | 抽屉的方向,可选值为 `left` , `top`,`right`,`bottom` | string | `right` | | Mask | 是否展示遮罩 | boolean | true |
| Placement | 抽屉的方向,可选值为 `left` , `top`,`right`,`bottom` | string | right |
| WrapClassName | 对话框外层容器的类名 | string | - | | WrapClassName | 对话框外层容器的类名 | string | - |
| Width | 宽度 | string\|int | 256 | | Width | 宽度 | string\|int | 256 |
| Height | 高度, 在 placement 为 top 或 bottom 时使用 | | int | | Height | 高度, 在 placement 为 top 或 bottom 时使用 | | int |
| ZIndex | 设置 Drawer 的 z-index | int | - | | ZIndex | 设置 Drawer 的 z-index | int | - |
| OffsetX | X 轴方向的偏移量,只在方向为 `'left'`或`'right'` 时生效 | int | 0 | | OffsetX | X 轴方向的偏移量,只在方向为 `'left'`或`'right'` 时生效 | int | 0 |
| OffsetY | Y 轴方向的偏移量,只在方向为 `'top'`或`'bottom'` 时生效 | int | 0 | | OffsetY | Y 轴方向的偏移量,只在方向为 `'top'`或`'bottom'` 时生效 | int | 0 |
| Visible | Drawer 是否可见 | boolean | - | | Visible | Drawer 是否可见 | boolean | - |
| Keyboard | 是否支持键盘 esc 关闭 | boolean | true | | Keyboard | 是否支持键盘 esc 关闭 | boolean | true |
| OnClose | 点击遮罩层或右上角叉或取消按钮的回调 | function(e) | - | | OnClose | 点击遮罩层或右上角叉或取消按钮的回调 | EventCallback | - |
| OnViewInit | 抽屉显示之前回调事件 | function(e) | - | | OnOpen | 抽屉渲染之后回调事件 | Func<Task> | - |
### DrawerService ### DrawerService
@ -58,7 +59,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/7z8NJQhFb/Drawer.svg
| CloseOnNavigation | 导航历史变化时是否关闭抽屉组件 | `boolean` | `true` | | CloseOnNavigation | 导航历史变化时是否关闭抽屉组件 | `boolean` | `true` |
| Keyboard | 是否支持键盘 esc 关闭 | `boolean` | `true` | | Keyboard | 是否支持键盘 esc 关闭 | `boolean` | `true` |
| MaskStyle | 遮罩样式 | `string` | `{}` | | MaskStyle | 遮罩样式 | `string` | `{}` |
| BodyStyle | Modal body 样式 | `string` | `{}` | | BodyStyle | Drawer body 样式 | `string` | `{}` |
| Title | 标题 | `OneOf<RenderFragment, string>` | - | | Title | 标题 | `OneOf<RenderFragment, string>` | - |
| Width | 宽度 | `int` | `256` | | Width | 宽度 | `int` | `256` |
| Height | 高度, 只在方向为 `'top'`或`'bottom'` 时生效 | `int` | `256` | | Height | 高度, 只在方向为 `'top'`或`'bottom'` 时生效 | `int` | `256` |

View File

@ -15,7 +15,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/ORmcdeaoO/Form.svg
- 需要对输入的数据类型进行校验时。 - 需要对输入的数据类型进行校验时。
## API ## API
### From ### Form
| 名称 | 说明 | 类型 | 默认值 | | 名称 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| Layout | 表单布局 | [FormLayout](https://github.com/ant-design-blazor/ant-design-blazor/blob/master/components/form/types/FormLayout.cs) | FormLayout.Horizontal | | Layout | 表单布局 | [FormLayout](https://github.com/ant-design-blazor/ant-design-blazor/blob/master/components/form/types/FormLayout.cs) | FormLayout.Horizontal |
@ -32,7 +32,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/ORmcdeaoO/Form.svg
| OnFinish | 提交事件 | EventCallback\<EditContext\> | - | | OnFinish | 提交事件 | EventCallback\<EditContext\> | - |
| OnFinishFailed | 提交失败(校验失败)回调事件 | EventCallback\<EditContext\> | - | | OnFinishFailed | 提交失败(校验失败)回调事件 | EventCallback\<EditContext\> | - |
| ValidateOnChange | 是否在更改时校验 | bool | false | | ValidateOnChange | 是否在更改时校验 | bool | false |
### FromItem ### FormItem
| 名称 | 说明 | 类型 | 默认值 | | 名称 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| Label | **label** 标签的文本 | string | input组件的Display或者DisplayName特性 | | Label | **label** 标签的文本 | string | input组件的Display或者DisplayName特性 |

View File

@ -1,15 +1,18 @@
@inject IconService iconService; @inject IconService iconService;
<div class="icons-list"> <div class="icons-list">
<IconFont Type="icon-tuichu" /> <IconFont Type="icon-tuichu" />
<IconFont Type="icon-facebook" /> <IconFont Type="icon-facebook" />
<IconFont Type="icon-twitter" /> <IconFont Type="icon-twitter" />
</div> </div>
@code @code
{ {
protected override async Task OnInitializedAsync() protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{ {
await iconService.CreateFromIconfontCN("//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js"); await iconService.CreateFromIconfontCN("//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js");
} }
} }
}

View File

@ -1,17 +1,20 @@
@inject IconService iconService; @inject IconService iconService;
<div class="icons-list"> <div class="icons-list">
<IconFont Type="icon-javascript" /> <IconFont Type="icon-javascript" />
<IconFont Type="icon-java" /> <IconFont Type="icon-java" />
<IconFont Type="icon-shoppingcart" /> <IconFont Type="icon-shoppingcart" />
<IconFont Type="icon-python" /> <IconFont Type="icon-python" />
</div> </div>
@code @code
{ {
protected override async Task OnInitializedAsync() protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{ {
await iconService.CreateFromIconfontCN("//at.alicdn.com/t/font_1788044_0dwu4guekcwr.js"); await iconService.CreateFromIconfontCN("//at.alicdn.com/t/font_1788044_0dwu4guekcwr.js");
await iconService.CreateFromIconfontCN("//at.alicdn.com/t/font_1788592_a5xf2bdic3u.js"); await iconService.CreateFromIconfontCN("//at.alicdn.com/t/font_1788592_a5xf2bdic3u.js");
} }
}
} }

View File

@ -9,6 +9,10 @@ title:
对于使用 [iconfont.cn](http://iconfont.cn/) 的用户,通过设置 `createFromIconfontCN` 方法参数对象中的 `scriptUrl` 字段, 即可轻松地使用已有项目中的图标。 对于使用 [iconfont.cn](http://iconfont.cn/) 的用户,通过设置 `createFromIconfontCN` 方法参数对象中的 `scriptUrl` 字段, 即可轻松地使用已有项目中的图标。
> 注意这个方法会涉及JS互操作因此需要确保在 `firstRender=true` 时调用。
## en-US ## en-US
If you are using [iconfont.cn](http://iconfont.cn/), you can use the icons in your project gracefully. If you are using [iconfont.cn](http://iconfont.cn/), you can use the icons in your project gracefully.
> Note: This method involves JS interope, so make sure you call it when 'firstRender=true'.

View File

@ -7,8 +7,12 @@ title:
## zh-CN ## zh-CN
`@ant-design/icons@4.1.0` 以后,`scriptUrl` 可引用多个资源,用户可灵活的管理 [iconfont.cn](http://iconfont.cn/) 图标。如果资源的图标出现重名,会按照数组顺序进行覆盖。 使用`scriptUrl` 可引用多个资源,用户可灵活的管理 [iconfont.cn](http://iconfont.cn/) 图标。如果资源的图标出现重名,会按照数组顺序进行覆盖。
> 注意这个方法会涉及JS互操作因此需要确保在 `firstRender=true` 时调用。
## en-US ## en-US
You can use `scriptUrl` as an array after `@ant-design/icons@4.1.0`, manage icons in one `<Icon />` from multiple [iconfont.cn](http://iconfont.cn/) resources. If icon with a duplicate name in resources, it will overrided in array order. You can use `scriptUrl` multiple times, manage icons in one `<Icon />` from multiple [iconfont.cn](http://iconfont.cn/) resources. If icon with a duplicate name in resources, it will overrided in array order.
> Note: This method involves JS interope, so make sure you call it when 'firstRender=true'

View File

@ -1,15 +1,5 @@
@code <Layout>
{ <Sider @bind-Collapsed=@collapsed NoTrigger OnCollapse="OnCollapse">
bool collapsed;
void toggle()
{
collapsed = !collapsed;
}
}
<Layout>
<Sider Collapsible Collapsed=@collapsed NoTrigger OnCollapse="OnCollapse">
<div class="logo" /> <div class="logo" />
<Menu Theme="MenuTheme.Dark" Mode="MenuMode.Inline" DefaultSelectedKeys=@(new[]{"1"})> <Menu Theme="MenuTheme.Dark" Mode="MenuMode.Inline" DefaultSelectedKeys=@(new[]{"1"})>
<MenuItem Key="1"> <MenuItem Key="1">
@ -69,6 +59,12 @@
@code{ @code{
bool collapsed;
void toggle()
{
collapsed = !collapsed;
}
void OnCollapse(bool isCollapsed) void OnCollapse(bool isCollapsed)
{ {

View File

@ -1,5 +0,0 @@
<h3>CustomTriggerDebug</h3>
@code {
}

View File

@ -1,12 +1,8 @@
<Layout> <Layout>
<Sider Breakpoint="@BreakpointType.Lg" <Sider Breakpoint="@BreakpointType.Lg"
CollapsedWidth="64" CollapsedWidth="64"
OnBreakpoint="@(broken => { @bind-Collapsed=@collapsed
Console.WriteLine($"OnBreakpoint:{broken}"); >
})"
OnCollapse="@(collapsed => {
Console.WriteLine($"collapsed:{collapsed}");
})">
<div class="logo" /> <div class="logo" />
<Menu Theme="MenuTheme.Dark" Mode="MenuMode.Inline" DefaultSelectedKeys=@(new[]{"4"})> <Menu Theme="MenuTheme.Dark" Mode="MenuMode.Inline" DefaultSelectedKeys=@(new[]{"4"})>
<MenuItem Key="1"> <MenuItem Key="1">
@ -38,6 +34,10 @@
</Layout> </Layout>
</Layout> </Layout>
@code{
bool collapsed;
}
<style> <style>
#components-layout-demo-responsive .logo { #components-layout-demo-responsive .logo {
height: 32px; height: 32px;

View File

@ -1,11 +0,0 @@
---
order: 99
title:
zh-CN: 自定义触发器 Debug
en-US: Custom trigger debug
debug: true
---
## zh-CN
修改内容前,请尝试此 Demo 查看样式是否抖动。

View File

@ -0,0 +1,44 @@
<Divider Orientation="left">Draggable</Divider>
<AntList Bordered DataSource="@data">
<Header>Header</Header>
<ChildContent Context="item">
<ListItem>
<div draggable="true" @ondrop="e=>OnDrop(e, item)" @ondragstart="e=>OnDragStart(e, item)" ondragover="event.preventDefault()">
<span><Text Mark>[ITEM]</Text></span>@item
</div>
</ListItem>
</ChildContent>
<Footer>Footer</Footer>
</AntList>
@code {
string _dragging;
void OnDrop(DragEventArgs e, string s)
{
if (!string.IsNullOrEmpty(s) && !string.IsNullOrEmpty(_dragging)) {
System.Diagnostics.Trace.WriteLine(s);
int index = data.IndexOf(s);
data.Remove(_dragging);
data.Insert(index, _dragging);
_dragging = null;
StateHasChanged();
}
}
void OnDragStart(DragEventArgs e, string s)
{
e.DataTransfer.DropEffect = "move";
e.DataTransfer.EffectAllowed = "move";
_dragging = s;
}
public List<string> data = new List<string> {
"Racing car sprays burning fuel into crowd.",
"Japanese princess to wed commoner.",
"Australian walks 100km after outback crash.",
"Man charged over missing wedding girl.",
"Los Angeles battles huge wildfires."
};
}

View File

@ -0,0 +1,12 @@
---
order: 8
title:
zh-CN: 可拖拽(Simple)
en-US: Simple Draggable
---
## zh-CN
为ListItem子组件包装一层div, 设置draggable='true', 并为之加上ondrop/ondragstart/ondragover事件处理函数.
## en-US
Add a `div` element wrapping `ListItem` child element, set `draggable='true'`, add `ondrop`/`ondragstart`/`ondragover` event handler.

View File

@ -24,6 +24,7 @@ Radio/Radio.Button
| Checked | Specifies whether the radio is selected. | boolean | | Checked | Specifies whether the radio is selected. | boolean |
| DefaultChecked | Specifies the initial state: whether or not the radio is selected. | boolean |- | | DefaultChecked | Specifies the initial state: whether or not the radio is selected. | boolean |- |
| Disabled | Disable radio | string | - | | Disabled | Disable radio | string | - |
| RadioButton | Set to TRUE to style the radio as button group. | bool | false |
| Value | According to value for comparison, to determine whether the selected | string | - | | Value | According to value for comparison, to determine whether the selected | string | - |
RadioGroup RadioGroup

View File

@ -24,6 +24,7 @@ Radio/Radio.Button
| Checked | 指定当前是否选中 | boolean | | Checked | 指定当前是否选中 | boolean |
| DefaultChecked | 初始是否选中 | boolean |- | | DefaultChecked | 初始是否选中 | boolean |- |
| Disabled | 禁用 Radio | string | - | | Disabled | 禁用 Radio | string | - |
| RadioButton | 设置为 TRUE 以将radio风格设置为按钮组 | bool | false |
| Value | 根据 value 进行比较,判断是否选中 | string | - | | Value | 根据 value 进行比较,判断是否选中 | string | - |
RadioGroup RadioGroup

View File

@ -8,6 +8,8 @@
<Col Span="24"> <Col Span="24">
<CountDown Title="Day Level" Value="@deadline" Format="dd 天 h 小时 m 分钟 s 秒" /> <CountDown Title="Day Level" Value="@deadline" Format="dd 天 h 小时 m 分钟 s 秒" />
</Col> </Col>
<br/>
<Button OnClick="OnReset">Reset Value</Button>
</Row> </Row>
@code @code
@ -18,4 +20,9 @@
{ {
Console.WriteLine("finished!"); Console.WriteLine("finished!");
} }
void OnReset()
{
deadline = DateTime.Now.AddMinutes(10);
}
} }

View File

@ -1,25 +1,22 @@
@using System.ComponentModel @using System.ComponentModel
@using AntDesign.TableModels @using AntDesign.TableModels
<Table TItem="Dictionary<string, object>" DataSource="@data" Loading="data==null" ScrollX="1500" PageSize="5"> <Table TItem="Dictionary<string, object>" OnChange="HanleChange" DataSource="@data" Loading="data==null" ScrollX="1500" PageSize="5" Size="TableSize.Small">
@if (data?.Any() == true) @foreach (var key in data?.FirstOrDefault()?.Keys.Take(10) ??new string[0])
{ {
@foreach (var key in data.FirstOrDefault()?.Keys.Take(10)) <PropertyColumn Property=@(c=>c[key]) Title="@key"></PropertyColumn>
{ }
<Column TData="object" DataIndex=@($"['{key}']") Title="@key"></Column>
}
}
</Table> </Table>
@inject HttpClient httpClient; @inject HttpClient httpClient;
@code { @code {
List<Dictionary<string, object>> data; List<Dictionary<string, object>> data;
string githubUrl = "https://api.github.com/repos/ant-design-blazor/ant-design-blazor/contributors?per_page=200"; string githubUrl = "https://api.github.com/repos/ant-design-blazor/ant-design-blazor/contributors?per_page=200";
protected override async Task OnInitializedAsync() protected async Task HanleChange(QueryModel<Dictionary<string, object>> query)
{ {
data = await httpClient.GetFromJsonAsync<List<Dictionary<string, object>>>(githubUrl); data = await httpClient.GetFromJsonAsync<List<Dictionary<string, object>>>(githubUrl);
} }
} }

View File

@ -2,7 +2,7 @@
DefaultExpandedKeys="@(new[] { "0-0-0", "0-0-1"})" DefaultExpandedKeys="@(new[] { "0-0-0", "0-0-1"})"
DefaultSelectedKeys="@(new[] {"0-0-0", "0-0-1" })" DefaultSelectedKeys="@(new[] {"0-0-0", "0-0-1" })"
DefaultCheckedKeys="@(new[] {"0-0-0", "0-0-1" })" DefaultCheckedKeys="@(new[] {"0-0-0", "0-0-1" })"
SelectedNodeChanged="SelectedNodeChanged" SelectedNodeChanged="SelectedNodeChanged"
OnSelect="OnSelect" OnSelect="OnSelect"
OnCheck="OnCheck"> OnCheck="OnCheck">
<TreeNode Title="parent 1" Key="0-0" TItem="string"> <TreeNode Title="parent 1" Key="0-0" TItem="string">

View File

@ -0,0 +1,5 @@
<h3>Async</h3>
@code {
}

View File

@ -3,14 +3,13 @@
@bind-Value="value" @bind-Value="value"
Placeholder="Please select" Placeholder="Please select"
AllowClear AllowClear
TreeDefaultExpandAll TreeDefaultExpandAll>
OnChange="OnChange">
<TreeNode TItem="string" Key="parent 1" Title="parent 1"> <TreeNode TItem="string" Key="parent 1" Title="parent 1">
<TreeNode TItem="string" Key="parent 1-0" title="parent 1-0"> <TreeNode TItem="string" Key="parent 1-0" Title="parent 1-0">
<TreeNode TItem="string" Key="leaf1" title="leaf1" /> <TreeNode TItem="string" Key="leaf1" Title="leaf1" />
<TreeNode TItem="string" Key="leaf2" title="leaf2" /> <TreeNode TItem="string" Key="leaf2" Title="leaf2" />
</TreeNode> </TreeNode>
<TreeNode TItem="string" Key="parent 1-1" title="parent 1-1"> <TreeNode TItem="string" Key="parent 1-1" Title="parent 1-1">
<TreeNode TItem="string" Key="leaf3"> <TreeNode TItem="string" Key="leaf3">
<TitleTemplate> <TitleTemplate>
<b Style="color:#08c;">leaf3</b> <b Style="color:#08c;">leaf3</b>
@ -22,10 +21,5 @@
@code { @code {
private string value; private string value="leaf3";
public void OnChange()
{
}
} }

View File

@ -0,0 +1,67 @@
<TreeSelect TItem="Data"
Style="width:100%;"
DataSource="treeData"
@bind-Value="@value"
Placeholder="Please select"
AllowClear
Multiple
TreeCheckable
TreeDefaultExpandAll
ChildrenExpression="node=>node.DataItem.Children"
TitleExpression="node=>node.DataItem.Title"
KeyExpression="node=>node.DataItem.Key"
IsLeafExpression="node=>node.DataItem.Children==null">
</TreeSelect>
@code {
private string value;
Data[] treeData = new Data[]
{
new()
{
Title = "Node1",
Key="0-0",
Children = new Data[]
{
new()
{
Title = "Child Node1",
Key="0-0-0",
},
}
},
new()
{
Title = "Node2",
Key="0-1",
Children = new Data[]
{
new()
{
Title ="Child Node3",
Key="0-1-0"
},
new()
{
Title ="Child Node4",
Key="0-1-1",
},
new()
{
Title ="Child Node5",
Key="0-1-2",
}
}
}
};
public class Data : ITreeData<Data>
{
public string Key { get; set; }
public Data Value => this;
public string Title { get; set; }
public IEnumerable<Data> Children { get; set; }
}
}

View File

@ -1,17 +1,17 @@
<TreeSelect TItem="string" <TreeSelect TItem="string"
Style="width:100%;" Style="width:100%;"
@bind-Value="value" @bind-Values="values"
DropdownStyle="max-height:400px;overflow:auto;"
Placeholder="Please select" Placeholder="Please select"
AllowClear AllowClear
Multiple Multiple
TreeDefaultExpandAll TreeDefaultExpandAll>
OnChange="OnValuesChange"> <TreeNode TItem="string" Key="parent 1" Title="parent 1">
<TreeNode TItem="string" Key="parent 1" title="parent 1"> <TreeNode TItem="string" Key="parent 1-0" Title="parent 1-0">
<TreeNode TItem="string" Key="parent 1-0" title="parent 1-0"> <TreeNode TItem="string" Key="leaf1" Title="my leaf" />
<TreeNode TItem="string" Key="leaf1" title="my leaf" /> <TreeNode TItem="string" Key="leaf2" Title="your leaf" />
<TreeNode TItem="string" Key="leaf2" title="your leaf" />
</TreeNode> </TreeNode>
<TreeNode TItem="string" Key="parent 1-1" title="parent 1-1"> <TreeNode TItem="string" Key="parent 1-1" Title="parent 1-1">
<TreeNode TItem="string" Key="sss"> <TreeNode TItem="string" Key="sss">
<TitleTemplate> <TitleTemplate>
<b style=" color: #08c;">sss</b> <b style=" color: #08c;">sss</b>
@ -21,13 +21,10 @@
</TreeNode> </TreeNode>
</TreeSelect> </TreeSelect>
@JsonSerializer.Serialize(values);
@code { @code {
private string value; private IEnumerable<string> values=new[]{"leaf1","leaf2"};
public void OnValuesChange(IEnumerable<string> args)
{
Console.WriteLine(string.Join(',', args));
}
} }

View File

@ -0,0 +1,33 @@
<RadioGroup @bind-Value="_placement">
<Radio RadioButton Value="Placement.TopLeft">topLeft</Radio>
<Radio RadioButton Value="Placement.TopRight">topRight</Radio>
<Radio RadioButton Value="Placement.BottomLeft">bottomLeft</Radio>
<Radio RadioButton Value="Placement.BottomRight">bottomRight</Radio>
</RadioGroup>
<br />
<br />
<TreeSelect TItem="string"
Style="width:100%;"
DropdownStyle="max-height:400px;overflow:auto;"
Placeholder="Please select"
AllowClear
Multiple
TreeDefaultExpandAll>
<TreeNode TItem="string" Value="parent 1" Title="parent 1">
<TreeNode TItem="string" Value="parent 1-0" Title="parent 1-0">
<TreeNode TItem="string" Value="leaf1" Title="leaf1" />
<TreeNode TItem="string" Value="leaf2" Title="leaf2" />
</TreeNode>
<TreeNode TItem="string" Value="parent 1-1" Title="parent 1-1">
<TreeNode TItem="string" Value="leaf3">
<TitleTemplate>
<b style=" color: #08c;">leaf3</b>
</TitleTemplate>
</TreeNode>
</TreeNode>
</TreeNode>
</TreeSelect>
@code {
Placement _placement;
}

View File

@ -1,14 +0,0 @@
---
order: 1
title:
zh-CN: 多选赋值
en-US: SetMultipleValue
---
## zh-CN
展示设置选中多个点击节点,以及默认值功能。
## en-US
The most basic usage, tell you how to use tree-select multiple selected etc.

View File

@ -1,68 +0,0 @@
<SimpleTreeSelect Multiple="true" TItem="WebMenu" @bind-Values="selectMenuId"
DataSource="@(LocalJsonData.Data)" AllowClear="true"
TitleExpression="m => m.MenuName"
KeyExpression="m => m.MenuId"
DataItemExpression="(menus, menuId) => menus.FirstOrDefault(m => m.MenuId == menuId)"
ChildrenMethodExpression="(menus, menuId) => menus.Where(m => m.ParentId == menuId).ToList()"
IsLeafExpression="(menus,m) => menus.All(m => m.ParentId != m.MenuId)"
Placeholder="Please select"
TreeDefaultExpandAll>
</SimpleTreeSelect>
select MenuId: @string.Join(',', selectMenuId ?? new[] { ""})
<Button OnClick="ChangeMenuId" OnClickStopPropagation="true">Update</Button>
@code{
private IEnumerable<string> selectMenuId = new[] { "3", "1"};
private void ChangeMenuId()
{
selectMenuId = new[] { "5", "2" };
}
public class WebMenu
{
public string MenuId { get; set; }
public string MenuHref { get; set; }
public string MenuName { get; set; }
public string Target { get; set; }
public string ParentId { get; set; }
public string Right { get; set; }
public int? OrderBy { get; set; } = 9999;
}
public static class LocalJsonData
{
private static readonly IList<WebMenu> _data;
static LocalJsonData()
{
_data = new List<WebMenu>() {
new WebMenu(){ MenuId="1", MenuName="parent 1", ParentId="0", OrderBy=10},
new WebMenu(){ MenuId="2", MenuName="parent 1-0", ParentId="1", OrderBy=10},
new WebMenu(){ MenuId="3", MenuName="leaf1", ParentId="2", OrderBy=10},
new WebMenu(){ MenuId="4", MenuName="leaf2", ParentId="0", OrderBy=10},
new WebMenu(){ MenuId="5", MenuName="parent1-1", ParentId="0", OrderBy=10},
new WebMenu(){ MenuId="6", MenuName="leaf3", ParentId="5", OrderBy=10}
};
}
public static IList<WebMenu> Data => _data;
public static IList<WebMenu> GetMenusByParentId(string parentId)
{
return _data.Where(m => m.ParentId == parentId).ToList();
}
}
}

View File

@ -1,68 +0,0 @@
<SimpleTreeSelect TItem="WebMenu" @bind-Value="selectMenuId"
DataSource="@(LocalJsonData.Data)"
TitleExpression="m => m.MenuName"
KeyExpression="m => m.MenuId"
DataItemExpression="(menus, menuId) => menus.FirstOrDefault(m => m.MenuId == menuId)"
ChildrenMethodExpression="(menus, menuId) => menus.Where(m => m.ParentId == menuId).ToList()"
IsLeafExpression="(menus,m) => menus.All(m => m.ParentId != m.MenuId)"
Placeholder="Please select"
TreeDefaultExpandAll>
</SimpleTreeSelect>
select MenuId:<Input Placeholder="current Select MenuId" @bind-Value="@selectMenuId" /><Button OnClick="ChangeMenuId" OnClickStopPropagation="true">Update</Button>
@code{
private string selectMenuId = "3";
private void ChangeMenuId()
{
selectMenuId = "5";
}
public class WebMenu
{
public string MenuId { get; set; }
public string MenuHref { get; set; }
public string MenuName { get; set; }
public string Target { get; set; }
public string ParentId { get; set; }
public string Right { get; set; }
public int? OrderBy { get; set; } = 9999;
}
public static class LocalJsonData
{
private static readonly IList<WebMenu> _data;
static LocalJsonData()
{
_data = new List<WebMenu>() {
new WebMenu(){ MenuId="1", MenuName="parent 1", ParentId="0", OrderBy=10},
new WebMenu(){ MenuId="2", MenuName="parent 1-0", ParentId="1", OrderBy=10},
new WebMenu(){ MenuId="3", MenuName="leaf1", ParentId="2", OrderBy=10},
new WebMenu(){ MenuId="4", MenuName="leaf2", ParentId="0", OrderBy=10},
new WebMenu(){ MenuId="5", MenuName="parent1-1", ParentId="0", OrderBy=10},
new WebMenu(){ MenuId="6", MenuName="leaf3", ParentId="5", OrderBy=10}
};
}
public static IList<WebMenu> Data => _data;
public static IList<WebMenu> GetMenusByParentId(string parentId)
{
return _data.Where(m => m.ParentId == parentId).ToList();
}
}
}

View File

@ -1,14 +0,0 @@
---
order: 1
title:
zh-CN: 赋值
en-US: SetValue1
---
## zh-CN
展示设置选中节点以及默认值功能。XXXXXXXXXXX
## en-US
The most basic usage, tell you how to use tree-select multiple selected etc.

View File

@ -1,66 +0,0 @@

<TreeSelect TItem="WebMenu"
Style="width:100%;"
@bind-Value="@ParentDeptId"
DataSource="@(LocalJsonData.Data)"
Placeholder="请选择"
AllowClear="false"
TitleExpression="m => m.MenuName"
KeyExpression="m => m.MenuId"
ChildrenExpression="m => LocalJsonData.GetMenusByParentId(m.MenuId)"
IsLeafExpression="(menus,m) => menus.All(m => m.ParentId != m.MenuId)"
TreeDefaultExpandAll>
</TreeSelect>
@ParentDeptId
@code{
private string ParentDeptId = "1";
public class WebMenu
{
public string MenuId { get; set; }
public string MenuHref { get; set; }
public string MenuName { get; set; }
public string Target { get; set; }
public string ParentId { get; set; }
public string Right { get; set; }
public int? OrderBy { get; set; } = 9999;
}
public static class LocalJsonData
{
private static readonly IList<WebMenu> _data;
static LocalJsonData()
{
_data = new List<WebMenu>() {
new WebMenu(){ MenuId="1", MenuName="parent 1", ParentId="0", OrderBy=10},
new WebMenu(){ MenuId="2", MenuName="parent 1-0", ParentId="1", OrderBy=10},
new WebMenu(){ MenuId="3", MenuName="leaf1", ParentId="2", OrderBy=10},
new WebMenu(){ MenuId="4", MenuName="leaf2", ParentId="0", OrderBy=10},
new WebMenu(){ MenuId="5", MenuName="parent1-1", ParentId="0", OrderBy=10},
new WebMenu(){ MenuId="6", MenuName="leaf3", ParentId="5", OrderBy=10}
};
}
public static IList<WebMenu> Data => _data;
public static IList<WebMenu> GetMenusByParentId(string parentId)
{
return _data.Where(m => m.ParentId == parentId).ToList();
}
}
}

View File

@ -0,0 +1,13 @@
<Space Direction="DirectionVHType.Vertical" Style="width: 100%">
<SpaceItem>
<TreeSelect TItem="string" Status="error" Style="width: 100%" Placeholder="Error" />
</SpaceItem>
<Space>
<TreeSelect TItem="string" Status="warning" Style="width: 100%" Multiple Placeholder="Warning multiple" />
</Space>
</Space>
@code {
}

View File

@ -0,0 +1,30 @@
<TreeSelect TItem="string"
EnableSearch
Style="width:100%;"
@bind-Value="value"
DropdownStyle="max-height:400px;overflow:auto;"
Placeholder="Please select"
AllowClear
Multiple
SuffixIcon="icon"
TreeDefaultExpandAll>
<TreeNode TItem="string" Key="parent 1" Title="parent 1">
<TreeNode TItem="string" Key="parent 1-0" Title="parent 1-0">
<TreeNode TItem="string" Key="leaf1" Title="my leaf" />
<TreeNode TItem="string" Key="leaf2" Title="your leaf" />
</TreeNode>
<TreeNode TItem="string" Key="parent 1-1" Title="parent 1-1">
<TreeNode TItem="string" Key="sss">
<TitleTemplate>
<b style=" color: #08c;">sss</b>
</TitleTemplate>
</TreeNode>
</TreeNode>
</TreeNode>
</TreeSelect>
@code {
private string value;
private RenderFragment icon =@<Icon Type="smile"></Icon>;
}

View File

@ -1,54 +1,53 @@
<TreeSelect TItem="Data"
Style="width:100%;"
<TreeSelect TItem="Data" DataSource="treeData"
Style="width:100%;" @bind-Value="@value"
DataSource="treeData" Placeholder="Please select"
@bind-Value="@value" AllowClear
Placeholder="Please select" Multiple
AllowClear TreeDefaultExpandAll
Multiple ChildrenExpression="node=>node.DataItem.Children"
TitleExpression="data => data.Title" TitleExpression="node=>node.DataItem.Title"
KeyExpression="data => data.Value" KeyExpression="node=>node.DataItem.Key"
ChildrenExpression="data => data.Children " IsLeafExpression="node=>node.DataItem.Children==null">
IsLeafExpression="(menus, data) => data.Children == null "
TreeDefaultExpandAll>
</TreeSelect> </TreeSelect>
@code { @code {
private string value; private string value;
Data[] treeData = new Data[] Data[] treeData = new Data[]
{ {
new() new()
{ {
Title = "Node1", Title = "Node1",
Value = "0-0", Key = "0-0",
Children = new Data[] Children = new Data[]
{ {
new() new()
{ {
Title = "Child Node1", Title = "Child Node1",
Value = "0-0-1", Key = "0-0-1",
}, },
new() new()
{ {
Title = "Child Node2", Title = "Child Node2",
Value = "0-0-2", Key = "0-0-2",
} }
} }
}, },
new() new()
{ {
Title = "Node2", Title = "Node2",
Value = "0-1", Key = "0-1",
} }
}; };
public class Data public class Data : ITreeData<Data>
{ {
public string Value { get; set; } public string Key { get; set; }
public string Title { get; set; } public Data Value => this;
public Data[] Children { get; set; } public string Title { get; set; }
} public IEnumerable<Data> Children { get; set; }
}
} }

View File

@ -0,0 +1,29 @@
<TreeSelect TItem="string"
EnableSearch
Style="width:100%;"
@bind-Value="value"
DropdownStyle="max-height:400px;overflow:auto;"
Placeholder="Please select"
AllowClear
Multiple
TreeLine
TreeDefaultExpandAll>
<TreeNode TItem="string" Key="parent 1" Title="parent 1">
<TreeNode TItem="string" Key="parent 1-0" Title="parent 1-0">
<TreeNode TItem="string" Key="leaf1" Title="my leaf" />
<TreeNode TItem="string" Key="leaf2" Title="your leaf" />
</TreeNode>
<TreeNode TItem="string" Key="parent 1-1" Title="parent 1-1">
<TreeNode TItem="string" Key="sss">
<TitleTemplate>
<b style=" color: #08c;">sss</b>
</TitleTemplate>
</TreeNode>
</TreeNode>
</TreeNode>
</TreeSelect>
@code {
private string value;
}

View File

@ -0,0 +1,72 @@
---
order: 5
debug: true
title:
zh-CN: 异步加载
en-US: Asynchronous loading
---
## zh-CN
异步加载树节点。
## en-US
Asynchronous loading tree node.
```tsx
import React, { useState } from 'react';
import { TreeSelect } from 'antd';
import type { DefaultOptionType } from 'antd/es/select';
import type { TreeSelectProps } from 'antd';
const App: React.FC = () => {
const [value, setValue] = useState<string>();
const [treeData, setTreeData] = useState<Omit<DefaultOptionType, 'label'>[]>([
{ id: 1, pId: 0, value: '1', title: 'Expand to load' },
{ id: 2, pId: 0, value: '2', title: 'Expand to load' },
{ id: 3, pId: 0, value: '3', title: 'Tree Node', isLeaf: true },
]);
const genTreeNode = (parentId: number, isLeaf = false) => {
const random = Math.random().toString(36).substring(2, 6);
return {
id: random,
pId: parentId,
value: random,
title: isLeaf ? 'Tree Node' : 'Expand to load',
isLeaf,
};
};
const onLoadData: TreeSelectProps['loadData'] = ({ id }) =>
new Promise(resolve => {
setTimeout(() => {
setTreeData(
treeData.concat([genTreeNode(id, false), genTreeNode(id, true), genTreeNode(id, true)]),
);
resolve(undefined);
}, 300);
});
const onChange = (newValue: string) => {
console.log(newValue);
setValue(newValue);
};
return (
<TreeSelect
treeDataSimpleMode
style={{ width: '100%' }}
value={value}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
placeholder="Please select"
onChange={onChange}
loadData={onLoadData}
treeData={treeData}
/>
);
};
export default App;
```

View File

@ -7,8 +7,48 @@ title:
## zh-CN ## zh-CN
最简单的用法,展示动态下拉树功能 最简单的用法。
## en-US ## en-US
The most basic usage, tell you how to use tree-select etc. The most basic usage.
```tsx
import React, { useState } from 'react';
import { TreeSelect } from 'antd';
const { TreeNode } = TreeSelect;
const App: React.FC = () => {
const [value, setValue] = useState<string | undefined>(undefined);
const onChange = (newValue: string) => {
setValue(newValue);
};
return (
<TreeSelect
showSearch
style={{ width: '100%' }}
value={value}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
placeholder="Please select"
allowClear
treeDefaultExpandAll
onChange={onChange}
>
<TreeNode value="parent 1" title="parent 1">
<TreeNode value="parent 1-0" title="parent 1-0">
<TreeNode value="leaf1" title="leaf1" />
<TreeNode value="leaf2" title="leaf2" />
</TreeNode>
<TreeNode value="parent 1-1" title="parent 1-1">
<TreeNode value="leaf3" title={<b style={{ color: '#08c' }}>leaf3</b>} />
</TreeNode>
</TreeNode>
</TreeSelect>
);
};
export default App;
```

View File

@ -0,0 +1,84 @@
---
order: 3
debug: true
title:
zh-CN: 可勾选
en-US: Checkable
---
## zh-CN
使用勾选框实现多选功能。
## en-US
Multiple and checkable.
```tsx
import React, { useState } from 'react';
import { TreeSelect } from 'antd';
const { SHOW_PARENT } = TreeSelect;
const treeData = [
{
title: 'Node1',
value: '0-0',
key: '0-0',
children: [
{
title: 'Child Node1',
value: '0-0-0',
key: '0-0-0',
},
],
},
{
title: 'Node2',
value: '0-1',
key: '0-1',
children: [
{
title: 'Child Node3',
value: '0-1-0',
key: '0-1-0',
},
{
title: 'Child Node4',
value: '0-1-1',
key: '0-1-1',
},
{
title: 'Child Node5',
value: '0-1-2',
key: '0-1-2',
},
],
},
];
const App: React.FC = () => {
const [value, setValue] = useState(['0-0-0']);
const onChange = (newValue: string[]) => {
console.log('onChange ', value);
setValue(newValue);
};
const tProps = {
treeData,
value,
onChange,
treeCheckable: true,
showCheckedStrategy: SHOW_PARENT,
placeholder: 'Please select',
style: {
width: '100%',
},
};
return <TreeSelect {...tProps} />;
};
export default App;
```

View File

@ -2,13 +2,55 @@
order: 1 order: 1
title: title:
zh-CN: 多选 zh-CN: 多选
en-US: multiple en-US: Multiple Selection
--- ---
## zh-CN ## zh-CN
最简单的用法展示多选功能。其中RootValue用于筛选DataSources中第一级的节点 多选的树选择
## en-US ## en-US
The most basic usage, tell you how to use tree-select multiple selected etc. Multiple selection usage.
```tsx
import React, { useState } from 'react';
import { TreeSelect } from 'antd';
const { TreeNode } = TreeSelect;
const App: React.FC = () => {
const [value, setValue] = useState<string>();
const onChange = (newValue: string) => {
console.log(newValue);
setValue(newValue);
};
return (
<TreeSelect
showSearch
style={{ width: '100%' }}
value={value}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
placeholder="Please select"
allowClear
multiple
treeDefaultExpandAll
onChange={onChange}
>
<TreeNode value="parent 1" title="parent 1">
<TreeNode value="parent 1-0" title="parent 1-0">
<TreeNode value="leaf1" title="my leaf" />
<TreeNode value="leaf2" title="your leaf" />
</TreeNode>
<TreeNode value="parent 1-1" title="parent 1-1">
<TreeNode value="sss" title={<b style={{ color: '#08c' }}>sss</b>} />
</TreeNode>
</TreeNode>
</TreeSelect>
);
};
export default App;
```

View File

@ -0,0 +1,67 @@
---
order: 8
debug: true
title:
zh-CN: 弹出位置
en-US: Placement
---
## zh-CN
可以通过 `placement` 手动指定弹出的位置。
## en-US
You can manually specify the position of the popup via `placement`.
```tsx
import React, { useState } from 'react';
import { TreeSelect, Radio } from 'antd';
import type { SelectCommonPlacement } from 'antd/es/_util/motion';
import type { RadioChangeEvent } from 'antd';
const { TreeNode } = TreeSelect;
const App: React.FC = () => {
const [placement, SetPlacement] = useState<SelectCommonPlacement>('topLeft');
const placementChange = (e: RadioChangeEvent) => {
SetPlacement(e.target.value);
};
return (
<>
<Radio.Group value={placement} onChange={placementChange}>
<Radio.Button value="topLeft">topLeft</Radio.Button>
<Radio.Button value="topRight">topRight</Radio.Button>
<Radio.Button value="bottomLeft">bottomLeft</Radio.Button>
<Radio.Button value="bottomRight">bottomRight</Radio.Button>
</Radio.Group>
<br />
<br />
<TreeSelect
showSearch
dropdownStyle={{ maxHeight: 400, overflow: 'auto', minWidth: 300 }}
placeholder="Please select"
dropdownMatchSelectWidth={false}
placement={placement}
allowClear
treeDefaultExpandAll
>
<TreeNode value="parent 1" title="parent 1">
<TreeNode value="parent 1-0" title="parent 1-0">
<TreeNode value="leaf1" title="leaf1" />
<TreeNode value="leaf2" title="leaf2" />
</TreeNode>
<TreeNode value="parent 1-1" title="parent 1-1">
<TreeNode value="leaf3" title={<b style={{ color: '#08c' }}>leaf3</b>} />
</TreeNode>
</TreeNode>
</TreeSelect>
</>
);
};
export default App;
```

View File

@ -1,14 +0,0 @@
---
order: 1
title:
zh-CN: 赋值
en-US: setValue
---
## zh-CN
展示设置选中节点,以及默认值功能。
## en-US
The most basic usage, tell you how to use tree-select multiple selected etc.

View File

@ -0,0 +1,34 @@
---
order: 9
debug: true
title:
zh-CN: 自定义状态
en-US: Status
---
## zh-CN
使用 `status` 为 TreeSelect 添加状态,可选 `error` 或者 `warning`
## en-US
Add status to TreeSelect with `status`, which could be `error` or `warning`.
```tsx
import React from 'react';
import { TreeSelect, Space } from 'antd';
const App: React.FC = () => (
<Space direction="vertical" style={{ width: '100%' }}>
<TreeSelect status="error" style={{ width: '100%' }} placeholder="Error" />
<TreeSelect
status="warning"
style={{ width: '100%' }}
multiple
placeholder="Warning multiple"
/>
</Space>
);
export default App;
```

View File

@ -0,0 +1,59 @@
---
order: 12
debug: true
title:
zh-CN: 后缀图标
en-US: Suffix
---
## zh-CN
最简单的用法。
## en-US
The most basic usage.
```tsx
import React, { useState } from 'react';
import { TreeSelect } from 'antd';
import { SmileOutlined } from '@ant-design/icons';
const { TreeNode } = TreeSelect;
const icon = <SmileOutlined />;
const App: React.FC = () => {
const [value, setValue] = useState<string>();
const onChange = (newValue: string) => {
console.log(newValue);
setValue(newValue);
};
return (
<TreeSelect
showSearch
suffixIcon={icon}
style={{ width: '100%' }}
value={value}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
placeholder="Please select"
allowClear
treeDefaultExpandAll
onChange={onChange}
>
<TreeNode value="parent 1" title="parent 1">
<TreeNode value="parent 1-0" title="parent 1-0">
<TreeNode value="leaf1" title="my leaf" />
<TreeNode value="leaf2" title="your leaf" />
</TreeNode>
<TreeNode value="parent 1-1" title="parent 1-1">
<TreeNode value="sss" title={<b style={{ color: '#08c' }}>sss</b>} />
</TreeNode>
</TreeNode>
</TreeSelect>
);
};
export default App;
```

View File

@ -7,8 +7,8 @@ title:
## zh-CN ## zh-CN
使用 `treeData` 把 JSON 数据直接生成树结构。 使用 `DataSource` 把 IEnumerable<T> 数据直接生成树结构。
## en-US ## en-US
The tree structure can be populated using `treeData` property. This is a quick and easy way to provide the tree content. The tree structure can be populated using `DataSource` property. This is a quick and easy way to provide the tree content.

View File

@ -0,0 +1,58 @@
---
order: 6
debug: true
title:
zh-CN: 线性样式
en-US: Show Tree Line
---
## zh-CN
通过 `treeLine` 配置线性样式。
## en-US
Use `treeLine` to show the line style.
```tsx
import React, { useState } from 'react';
import { TreeSelect, Switch, Space } from 'antd';
const { TreeNode } = TreeSelect;
const App: React.FC = () => {
const [treeLine, setTreeLine] = useState(true);
const [showLeafIcon, setShowLeafIcon] = useState(false);
return (
<Space direction="vertical">
<Switch
checkedChildren="treeLine"
unCheckedChildren="treeLine"
checked={treeLine}
onChange={() => setTreeLine(!treeLine)}
/>
<Switch
disabled={!treeLine}
checkedChildren="showLeafIcon"
unCheckedChildren="showLeafIcon"
checked={showLeafIcon}
onChange={() => setShowLeafIcon(!showLeafIcon)}
/>
<TreeSelect treeLine={treeLine && { showLeafIcon }} style={{ width: 300 }}>
<TreeNode value="parent 1" title="parent 1">
<TreeNode value="parent 1-0" title="parent 1-0">
<TreeNode value="leaf1" title="my leaf" />
<TreeNode value="leaf2" title="your leaf" />
</TreeNode>
<TreeNode value="parent 1-1" title="parent 1-1">
<TreeNode value="sss" title="sss" />
</TreeNode>
</TreeNode>
</TreeSelect>
</Space>
);
};
export default App;
```

View File

@ -7,7 +7,7 @@
@Title @Title
</div> </div>
<div class="code-box-description"> <div class="code-box-description">
<Markdown>@Description</Markdown> @Description
</div> </div>
</section> </section>
</div> </div>

View File

@ -1,25 +1,44 @@
@using System.Text.RegularExpressions @using System.Text.RegularExpressions
@inherits AntDesignTestBase @inherits AntDesignTestBase
@code { @code {
[Fact] [Fact]
public void InputNumber_formatter_parser_change_value() public void InputNumber_formatter_parser_change_value()
{ {
//Arrange //Arrange
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
JSInterop.SetupVoid(JSInteropConstants.Focus, _ => true).SetVoidResult(); JSInterop.SetupVoid(JSInteropConstants.Focus, _ => true).SetVoidResult();
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
AntDesign.InputNumber<double>? input = null; AntDesign.InputNumber<double>? input = null;
Func<double, string> formatter = v => "$ " + v.ToString("n0"); Func<double, string> formatter = v => "$ " + v.ToString("n0");
Func<string, string> parser = v => Regex.Replace(v, @"\$\s?|(,*)", ""); Func<string, string> parser = v => Regex.Replace(v, @"\$\s?|(,*)", "");
var cut = Render<AntDesign.InputNumber<double>>( var cut = Render<AntDesign.InputNumber<double>>(
@<AntDesign.InputNumber @ref="@input" Formatter="formatter" Parser="parser" DefaultValue="1000d"/> @<AntDesign.InputNumber @ref="@input" Formatter="formatter" Parser="parser" DefaultValue="1000d" />
); );
//Act //Act
cut.Find("input").Change("$ 10"); cut.Find("input").Change("$ 10");
//Assert //Assert
cut.Instance.Value.Should().Be(10); cut.Instance.Value.Should().Be(10);
} }
[Fact]
public void InputNumber_value_display_check_when_step_notation_is_scientific()
{
//Arrange
#pragma warning disable CS0618 // Type or member is obsolete
JSInterop.SetupVoid(JSInteropConstants.Focus, _ => true).SetVoidResult();
#pragma warning restore CS0618 // Type or member is obsolete
AntDesign.InputNumber<double>? input = null;
var cut = Render<AntDesign.InputNumber<double>>(
@<AntDesign.InputNumber @ref="@input" Step="0.00001" />
);
//Act
var inputElement = cut.Find("input");
inputElement.KeyDown(Key.Up);
//Assert
string decimalSeparator = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator;
inputElement.GetAttribute("value").Should().Be($"0{decimalSeparator}00001");
}
} }