mirror of
https://gitee.com/ant-design-blazor/ant-design-blazor.git
synced 2024-12-04 21:17:36 +08:00
Merge 0.9.4 to feature (#1942)
* fix(module: form): remove `FormItem` from `Form` when it was disposed (#1901) * pref(module: table): put fixed column style into js (#1897) * pref(module: table): put fixed column style into js * fix resize listener * docs: Add building demo assets to the Readme (#1904) * feat(module: table): add `CellData` for `CellRender` (#1907) * docs: add dynamic table demo (#1908) * feat(module: table): add dynamic data demo * add scroll x * fix(module: select): value no longer reset on datasource set (#1906) * fix(module:select): value no longer reset on datasource set * fix(module:select): dataSource change detection * fix: improve datasource detection add item & set value in SelectOption * tests: scenario from issue #1207 * fix: DataSourceEqualityComparer default * docs: Fixed typo (#1915) * fix(module: input): Add stop propagation (#1917) * docs(module: select): update coordinate demo (#1914) Co-authored-by: James Yeung <shunjiey@hotmail.com> * fix(module: textarea): add rows parameter (#1920) doc: adjust to match antD tests: sizing tests * test(module: select): Add some unit tests for Select (#1891) * Add Select clear tests * Add Select DataSource to null test * Change the implement of Throw tests * Change int to int? * fix(module: button): loading icon styles (#1902) * Fix loading icon styles * Fix button render test * feat(module: InputNumber): Add inputmode for mobile keyboard (#1923) * perf: avoid memory leak issue of event listener (#1857) * perf: avoid memory leak #1834 Avoid memory leak by remove the exclusive parameter and logic in the code block on AddEventListener method in DomEventService class. The following are the components affected: components/affix/Affix.razor.cs components/anchor/Anchor.razor.cs components/carousel/Carousel.razor.cs components/core/Component/Overlay/Overlay.razor.cs components/core/Component/Overlay/OverlayTrigger.razor.cs components/core/JsInterop/DomEventService.cs components/descriptions/Descriptions.razor.cs components/dropdown/DropdownButton.cs components/grid/Row.razor.cs components/input/Input.cs components/input/TextArea.razor.cs components/layout/Sider.razor.cs components/list/ListItem.razor.cs components/select/Select.razor.cs components/select/internal/SelectContent.razor.cs components/slider/Slider.razor.cs components/table/Table.razor.cs components/tabs/Tabs.razor.cs * fix override AddEventListener method in AntDesign.TestKit project * add register/remove event listerner for exclusive use in DomEventService class * move _dotNetObjects to DomEventListerner class/service, so that users not required to maintain it in each component. * * move share/reuse dom event listerner methods to DomEventListerner class * remove method 'AddEventListener' that no longer exists in DomEventService class in AntDesign.TestKit project * * change the component referring to an IDomEventListerner interface instead of a concrete class, so that the component can be tested via a mock TestDomEventListerner. * introduce DisposeShared and Dispose method in DomEventListerner to ease user remove callback from DomEventListerner * register IDomEventListerner into DI container instead of create manually * fix FormatKey * fix FormatKey * fix tests * fix test * fix test Co-authored-by: James Yeung <shunjiey@hotmail.com> * fix(module: textarea): replace wrong event (#1927) * tests(module: textarea): include js function mock to avoid bunit exceptions (#1930) * perf(module: overlay): positioning moved to js (#1848) * fix(module:overlay): move postion calculation to js fixes #1836 * docs: TriggerBoundaryAdjustMode explanation * docs: select & datepicker got BoundaryAdjustmetMode cleanup * test: fixes optimization & cleanup * fix(module:overlay): recalculate overlay position when trigger resizes * Minor clean-up * fix(module:overlay): wait for Show to finish in Hide * fix: prevent vertical scrollbar on overlay adding * fix: extract waiting function * fix: overlay not to repostion when trigger vanishes (menu issue) * fix: scroll adjustment for position: fixed * fix: on menu mode change, keep * merge conflict fix * fix: nominal calculation reset on failed adjustment * fix: bugs * test: exclude log method from test coverage in overlay.ts * fix(module: table): It would be load twice at first time if pagesize is not 10 (#1933) * fix(module: menu): collapsed menu title can't hide while use router link (#1934) * fix(module: select): fix data source of type IEnumerable<object> (#1932) * fix(module:select): fix data source of type IEnumerable<object> * Update Select.razor.cs * Update Select.OnDataSourceChangeTests.razor Co-authored-by: James Yeung <shunjiey@hotmail.com> * feat(module: InputNumber): Add OnFocus event (#1931) * Add on textbox focus * Adjust naming Co-authored-by: James Yeung <shunjiey@hotmail.com> * fix(module: list): resposive style doesn't work (#1937) * docs: Update index.zh-CN.md (#1936) Update document ConfigProvider global configuration example code Co-authored-by: James Yeung <shunjiey@hotmail.com> * change log 0.9.4 (#1938) * chore: test cs project to include test runner adapter (#1939) test: add general overlay disposal method mock Co-authored-by: Alan.Liu <lxyruanjian@126.com> Co-authored-by: James Yeung <shunjiey@hotmail.com> Co-authored-by: rabberbock <rabberbock@gmail.com> Co-authored-by: Andrzej Bakun <anddrzejb@poczta.fm> Co-authored-by: Chandan Rauniyar <chandankkrr@gmail.com> Co-authored-by: Luke Parker [SSW] <10430890+Hona@users.noreply.github.com> Co-authored-by: SmallY <45689960+iamSmallY@users.noreply.github.com> Co-authored-by: Maksim <maksalmak@gmail.com> Co-authored-by: Tony Yip <tonyyip1969@gmail.com> Co-authored-by: SmRiley <45205313+SmRiley@users.noreply.github.com>
This commit is contained in:
commit
0ef438cc30
@ -14,6 +14,32 @@ 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.9.4
|
||||||
|
|
||||||
|
2021-09-12
|
||||||
|
|
||||||
|
- Table
|
||||||
|
- 🐞 Fixed an issue that initialization is refreshed twice when PageSize is not equal to 10. [#1933](https://github.com/ant-design-blazor/ant-design-blazor/pull/1933) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
- 🆕 Addd CellData for CellRender. [#1907](https://github.com/ant-design-blazor/ant-design-blazor/pull/1907) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
- ⚡️ Put fixed column style into js. [#1897](https://github.com/ant-design-blazor/ant-design-blazor/pull/1897) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
- 📖 add dynamic table demo. [#1908](https://github.com/ant-design-blazor/ant-design-blazor/pull/1908) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
|
||||||
|
- InputNumber
|
||||||
|
- 🆕 Add OnFocus event [#1931](https://github.com/ant-design-blazor/ant-design-blazor/pull/1931) [@Hona](https://github.com/Hona)
|
||||||
|
- 🐞 Fixed inputmode to support mobile numeric keypad. [#1923](https://github.com/ant-design-blazor/ant-design-blazor/pull/1923) [@CAPCHIK](https://github.com/CAPCHIK)
|
||||||
|
|
||||||
|
- Select
|
||||||
|
- 🐞 Fixed the data source which has members of different types. [#1932](https://github.com/ant-design-blazor/ant-design-blazor/pull/1932) [@anranruye](https://github.com/anranruye)
|
||||||
|
- 🐞 Fixed the problem that the selected item will be reset when setting DataSource [#1906](https://github.com/ant-design-blazor/ant-design-blazor/pull/1906) [@anddrzejb](https://github.com/anddrzejb)
|
||||||
|
|
||||||
|
- 🐞 Fixed Menu that the Title of MenuItem with RouterLink is not hidden when it is collapsed. [#1934](https://github.com/ant-design-blazor/ant-design-blazor/pull/1934) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
- 🐞 Fixed Overlay with a series of issues related to dropdown & popup。 [#1848](https://github.com/ant-design-blazor/ant-design-blazor/pull/1848) [@anddrzejb](https://github.com/anddrzejb)
|
||||||
|
- 💄 Fixed loading icon styles. [#1902](https://github.com/ant-design-blazor/ant-design-blazor/pull/1902) [@CAPCHIK](https://github.com/CAPCHIK)
|
||||||
|
- 🐞 Added parameter `Rows`. [#1920](https://github.com/ant-design-blazor/ant-design-blazor/pull/1920) [@anddrzejb](https://github.com/anddrzejb)
|
||||||
|
- 🐞 Add stop propogation. [#1917](https://github.com/ant-design-blazor/ant-design-blazor/pull/1917) [@Hona](https://github.com/Hona)
|
||||||
|
- 🐞 Fixed Form modifies the bound model to throw an exception in Rule validation mode. [#1901](https://github.com/ant-design-blazor/ant-design-blazor/pull/1901) [@lxyruanjian](https://github.com/lxyruanjian)
|
||||||
|
- 🐞 Fixed List resposive style doesn't work. [#1937](https://github.com/ant-design-blazor/ant-design-blazor/pull/1937) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
- ⚡️ Fixed EventListener avoid memory leak issue. [#1857](https://github.com/ant-design-blazor/ant-design-blazor/pull/1857) [@tonyyip1969](https://github.com/tonyyip1969)
|
||||||
|
|
||||||
### 0.9.3
|
### 0.9.3
|
||||||
|
|
||||||
@ -26,7 +52,7 @@ timeline: true
|
|||||||
- 📖 Add an example of nested table. [#1884](https://github.com/ant-design-blazor/ant-design-blazor/pull/1884) [@ElderJames](https://github.com/ElderJames)
|
- 📖 Add an example of nested table. [#1884](https://github.com/ant-design-blazor/ant-design-blazor/pull/1884) [@ElderJames](https://github.com/ElderJames)
|
||||||
- 🐞 Fixed Time column built-in filter will ignore milliseconds when filtering.[#1864](https://github.com/ant-design-blazor/ant-design-blazor/pull/1864) [@iamSmallY](https://github.com/iamSmallY)
|
- 🐞 Fixed Time column built-in filter will ignore milliseconds when filtering.[#1864](https://github.com/ant-design-blazor/ant-design-blazor/pull/1864) [@iamSmallY](https://github.com/iamSmallY)
|
||||||
- 🐞 Fixed the issue that operations such as page turning, sorting and filtering are not refreshed by using client mode. [#1858](https://github.com/ant-design-blazor/ant-design-blazor/pull/1858) [@ElderJames](https://github.com/ElderJames)
|
- 🐞 Fixed the issue that operations such as page turning, sorting and filtering are not refreshed by using client mode. [#1858](https://github.com/ant-design-blazor/ant-design-blazor/pull/1858) [@ElderJames](https://github.com/ElderJames)
|
||||||
[#1875](https://github.com/ant-design/ant-design/pull/1875) [@nikolaykrondev](https://github.com/nikolaykrondev)
|
[#1875](https://github.com/ant-design-blazor/ant-design-blazor/pull/1875) [@nikolaykrondev](https://github.com/nikolaykrondev)
|
||||||
- 🐞 Fixed the issue that OnChange is called multiple times after initialization. [#1855](https://github.com/ant-design-blazor/ant-design-blazor/pull/1855) [@ElderJames](https://github.com/ElderJames)
|
- 🐞 Fixed the issue that OnChange is called multiple times after initialization. [#1855](https://github.com/ant-design-blazor/ant-design-blazor/pull/1855) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
|
||||||
- 🆕 Breadcrumb add Href and Overlay dropdown. [#1859](https://github.com/ant-design-blazor/ant-design-blazor/pull/1859) [@CAPCHIK](https://github.com/CAPCHIK)
|
- 🆕 Breadcrumb add Href and Overlay dropdown. [#1859](https://github.com/ant-design-blazor/ant-design-blazor/pull/1859) [@CAPCHIK](https://github.com/CAPCHIK)
|
||||||
|
@ -15,6 +15,33 @@ timeline: true
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### 0.9.4
|
||||||
|
|
||||||
|
2021-09-12
|
||||||
|
|
||||||
|
- Table
|
||||||
|
- 🐞 修复 在 PageSize 不等于 10 时,初始化时会被刷新两次的问题。[#1933](https://github.com/ant-design-blazor/ant-design-blazor/pull/1933) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
- 🆕 传递 `CellData` 给 CellRender 模板,可访问当前单元格和行的一些信息。[#1907](https://github.com/ant-design-blazor/ant-design-blazor/pull/1907) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
- ⚡️ 将固定列的样式处理放到 JS,以提升性能。[#1897](https://github.com/ant-design-blazor/ant-design-blazor/pull/1897) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
- 📖 增加 动态表格 demo。[#1908](https://github.com/ant-design-blazor/ant-design-blazor/pull/1908) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
|
||||||
|
- InputNumber
|
||||||
|
- 🆕 增加 OnFocus 事件。[#1931](https://github.com/ant-design-blazor/ant-design-blazor/pull/1931) [@Hona](https://github.com/Hona)
|
||||||
|
- 🐞 修复 inputmode,支持手机数字键盘。[#1923](https://github.com/ant-design-blazor/ant-design-blazor/pull/1923) [@CAPCHIK](https://github.com/CAPCHIK)
|
||||||
|
|
||||||
|
- Select
|
||||||
|
- 🐞 修复 对异构选项类型的支持。[#1932](https://github.com/ant-design-blazor/ant-design-blazor/pull/1932) [@anranruye](https://github.com/anranruye)
|
||||||
|
- 🐞 修复 设置 DataSource 时,选中项会被的重置问题。[#1906](https://github.com/ant-design-blazor/ant-design-blazor/pull/1906) [@anddrzejb](https://github.com/anddrzejb)
|
||||||
|
|
||||||
|
- 🐞 修复 Overlay 与 dropdown、选项框、popup 有关的一系列问题。[#1848](https://github.com/ant-design-blazor/ant-design-blazor/pull/1848) [@anddrzejb](https://github.com/anddrzejb)
|
||||||
|
- 💄 修复 Button 的 loading 样式。[#1902](https://github.com/ant-design-blazor/ant-design-blazor/pull/1902) [@CAPCHIK](https://github.com/CAPCHIK)
|
||||||
|
- 🐞 增加 TextArea 的 `Rows` 属性,支持固定的行数。[#1920](https://github.com/ant-design-blazor/ant-design-blazor/pull/1920) [@anddrzejb](https://github.com/anddrzejb)
|
||||||
|
- 🐞 增加 Input 的 StopPropogation 属性,以减少事件触发,提升性能。[#1917](https://github.com/ant-design-blazor/ant-design-blazor/pull/1917) [@Hona](https://github.com/Hona)
|
||||||
|
- 🐞 修复 Form 移除已释放的 FormItem 实例。[#1901](https://github.com/ant-design-blazor/ant-design-blazor/pull/1901) [@lxyruanjian](https://github.com/lxyruanjian)
|
||||||
|
- ⚡️ 事件订阅器的内存泄漏问题。[#1857](https://github.com/ant-design-blazor/ant-design-blazor/pull/1857) [@tonyyip1969](https://github.com/tonyyip1969)
|
||||||
|
- 🐞 修复 List 组件的响应式无效的问题。 [#1937](https://github.com/ant-design-blazor/ant-design-blazor/pull/1937) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
- 🐞 修复 Menu 有 RouterLink 的 MenuItem 在收起时 Title 不隐藏的问题。[#1934](https://github.com/ant-design-blazor/ant-design-blazor/pull/1934) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
|
||||||
### 0.9.3
|
### 0.9.3
|
||||||
|
|
||||||
2021-08-29
|
2021-08-29
|
||||||
@ -26,7 +53,7 @@ timeline: true
|
|||||||
- 📖 增加 表格嵌套的示例。[#1884](https://github.com/ant-design-blazor/ant-design-blazor/pull/1884) [@ElderJames](https://github.com/ElderJames)
|
- 📖 增加 表格嵌套的示例。[#1884](https://github.com/ant-design-blazor/ant-design-blazor/pull/1884) [@ElderJames](https://github.com/ElderJames)
|
||||||
- 🐞 修复 时间列内置筛选器在筛选时将忽略毫秒。[#1864](https://github.com/ant-design-blazor/ant-design-blazor/pull/1864) [@iamSmallY](https://github.com/iamSmallY)
|
- 🐞 修复 时间列内置筛选器在筛选时将忽略毫秒。[#1864](https://github.com/ant-design-blazor/ant-design-blazor/pull/1864) [@iamSmallY](https://github.com/iamSmallY)
|
||||||
- 🐞 修复 使用客户端模式翻页、排序、筛选等操作不刷新的问题。[#1858](https://github.com/ant-design-blazor/ant-design-blazor/pull/1858) [@ElderJames](https://github.com/ElderJames)
|
- 🐞 修复 使用客户端模式翻页、排序、筛选等操作不刷新的问题。[#1858](https://github.com/ant-design-blazor/ant-design-blazor/pull/1858) [@ElderJames](https://github.com/ElderJames)
|
||||||
[#1875](https://github.com/ant-design/ant-design/pull/1875) [@nikolaykrondev](https://github.com/nikolaykrondev)
|
[#1875](https://github.com/ant-design-blazor/ant-design-blazor/pull/1875) [@nikolaykrondev](https://github.com/nikolaykrondev)
|
||||||
- 🐞 修复 初始化后 OnChange 调用多次的问题。[#1855](https://github.com/ant-design-blazor/ant-design-blazor/pull/1855) [@ElderJames](https://github.com/ElderJames)
|
- 🐞 修复 初始化后 OnChange 调用多次的问题。[#1855](https://github.com/ant-design-blazor/ant-design-blazor/pull/1855) [@ElderJames](https://github.com/ElderJames)
|
||||||
|
|
||||||
- 🆕 新增 Breadcrumb 的 Href 和 Overlay 下拉菜单。 [#1859](https://github.com/ant-design-blazor/ant-design-blazor/pull/1859) [@CAPCHIK](https://github.com/CAPCHIK)
|
- 🆕 新增 Breadcrumb 的 Href 和 Overlay 下拉菜单。 [#1859](https://github.com/ant-design-blazor/ant-design-blazor/pull/1859) [@CAPCHIK](https://github.com/CAPCHIK)
|
||||||
|
@ -159,6 +159,7 @@ WebAssembly 静态托管页面示例
|
|||||||
$ git clone git@github.com:ant-design-blazor/ant-design-blazor.git
|
$ git clone git@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
|
||||||
$ npm start
|
$ npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -165,6 +165,7 @@ Options for the template:
|
|||||||
$ git clone git@github.com:ant-design-blazor/ant-design-blazor.git
|
$ git clone git@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
|
||||||
$ npm start
|
$ npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ namespace AntDesign
|
|||||||
private string _affixStyle;
|
private string _affixStyle;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
#region Parameters
|
#region Parameters
|
||||||
|
|
||||||
@ -92,15 +92,14 @@ namespace AntDesign
|
|||||||
await RenderAffixAsync();
|
await RenderAffixAsync();
|
||||||
if (!_rootListened && string.IsNullOrEmpty(TargetSelector))
|
if (!_rootListened && string.IsNullOrEmpty(TargetSelector))
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener(RootScollSelector, "scroll", OnWindowScroll, false);
|
DomEventListener.AddShared<JsonElement>(RootScollSelector, "scroll", OnWindowScroll);
|
||||||
DomEventService.AddEventListener(RootScollSelector, "resize", OnWindowResize, false);
|
DomEventListener.AddShared<JsonElement>(RootScollSelector, "resize", OnWindowResize);
|
||||||
|
|
||||||
_rootListened = true;
|
_rootListened = true;
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(TargetSelector))
|
else if (!string.IsNullOrEmpty(TargetSelector))
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener(TargetSelector, "scroll", OnTargetScroll);
|
DomEventListener.AddExclusive<JsonElement>(TargetSelector, "scroll", OnTargetScroll);
|
||||||
DomEventService.AddEventListener(TargetSelector, "resize", OnTargetResize);
|
DomEventListener.AddExclusive<JsonElement>(TargetSelector, "resize", OnTargetResize);
|
||||||
_targetListened = true;
|
_targetListened = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,8 +142,8 @@ namespace AntDesign
|
|||||||
containerRect = new DomRect()
|
containerRect = new DomRect()
|
||||||
{
|
{
|
||||||
Top = 0,
|
Top = 0,
|
||||||
Bottom = window.innerHeight,
|
Bottom = window.InnerHeight,
|
||||||
Height = window.innerHeight,
|
Height = window.InnerHeight,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -159,7 +158,7 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
if (domRect.Bottom > bottomDist)
|
if (domRect.Bottom > bottomDist)
|
||||||
{
|
{
|
||||||
_affixStyle = _hiddenStyle + $"bottom: { window.innerHeight - bottomDist}px; position: fixed;";
|
_affixStyle = _hiddenStyle + $"bottom: { window.InnerHeight - bottomDist}px; position: fixed;";
|
||||||
Affixed = true;
|
Affixed = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -189,17 +188,7 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
|
||||||
if (_rootListened)
|
DomEventListener.Dispose();
|
||||||
{
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(RootScollSelector, "scroll", OnWindowScroll);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(RootScollSelector, "resize", OnWindowResize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_targetListened)
|
|
||||||
{
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(TargetSelector, "scroll", OnTargetScroll);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(TargetSelector, "resize", OnTargetResize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace AntDesign
|
|||||||
private bool _linksChanged = false;
|
private bool _linksChanged = false;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
#region Parameters
|
#region Parameters
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
if (GetCurrentAnchor is null)
|
if (GetCurrentAnchor is null)
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener("window", "scroll", OnScroll, false);
|
DomEventListener.AddShared<JsonElement>("window", "scroll", OnScroll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,9 +297,8 @@ namespace AntDesign
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
DomEventListener.Dispose();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "scroll", OnScroll);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
Style="display: inline"
|
Style="display: inline"
|
||||||
IsButton="@true"
|
IsButton="@true"
|
||||||
Disabled="false"
|
Disabled="false"
|
||||||
Trigger="new TriggerType[] { TriggerType.Click }"
|
Trigger="new[] { Trigger.Click }"
|
||||||
|
BoundaryAdjustMode="@BoundaryAdjustMode"
|
||||||
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"
|
||||||
|
@ -163,6 +163,13 @@ namespace AntDesign
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public object ActiveValue { get; set; }
|
public object ActiveValue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overlay adjustment strategy (when for example browser resize is happening). Check
|
||||||
|
/// enum for details.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public TriggerBoundaryAdjustMode BoundaryAdjustMode { get; set; } = TriggerBoundaryAdjustMode.InView;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowPanel { get; set; } = false;
|
public bool ShowPanel { get; set; } = false;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
@if (_overflow)
|
@if (_overflow)
|
||||||
{
|
{
|
||||||
<Popover Trigger="new[] { TriggerType.Hover }"
|
<Popover Trigger="new[] { Trigger.Hover }"
|
||||||
Placement=MaxPopoverPlacement
|
Placement=MaxPopoverPlacement
|
||||||
OverlayClassName="@_popoverClassMapper.Class">
|
OverlayClassName="@_popoverClassMapper.Class">
|
||||||
<ContentTemplate>
|
<ContentTemplate>
|
||||||
|
@ -15,7 +15,7 @@ namespace AntDesign
|
|||||||
public string MaxStyle { get; set; }
|
public string MaxStyle { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public PlacementType MaxPopoverPlacement { get; set; } = PlacementType.Top;
|
public Placement MaxPopoverPlacement { get; set; } = Placement.Top;
|
||||||
|
|
||||||
private ClassMapper _popoverClassMapper = new ClassMapper();
|
private ClassMapper _popoverClassMapper = new ClassMapper();
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ namespace AntDesign
|
|||||||
private bool _visible = false;
|
private bool _visible = false;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Icon { get; set; } = "vertical-align-top";
|
public string Icon { get; set; } = "vertical-align-top";
|
||||||
@ -55,11 +55,11 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(TargetSelector))
|
if (string.IsNullOrWhiteSpace(TargetSelector))
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener("window", "scroll", OnScroll);
|
DomEventListener.AddExclusive<JsonElement>("window", "scroll", OnScroll);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener(TargetSelector, "scroll", OnScroll);
|
DomEventListener.AddExclusive<JsonElement>(TargetSelector, "scroll", OnScroll);
|
||||||
}
|
}
|
||||||
await base.OnFirstAfterRenderAsync();
|
await base.OnFirstAfterRenderAsync();
|
||||||
}
|
}
|
||||||
@ -88,15 +88,8 @@ namespace AntDesign
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
DomEventListener.DisposeExclusive();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
if (string.IsNullOrWhiteSpace(TargetSelector))
|
|
||||||
{
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "scroll", OnScroll);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(TargetSelector, "scroll", OnScroll);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
@if (Overlay != null)
|
@if (Overlay != null)
|
||||||
{
|
{
|
||||||
<Dropdown Placement="@PlacementType.BottomCenter">
|
<Dropdown Placement="@Placement.BottomCenter">
|
||||||
<Unbound>
|
<Unbound>
|
||||||
<span @ref="context.Current" class="ant-breadcrumb-overlay-link">
|
<span @ref="context.Current" class="ant-breadcrumb-overlay-link">
|
||||||
<span class="ant-breadcrumb-link">
|
<span class="ant-breadcrumb-link">
|
||||||
|
@ -2,20 +2,31 @@
|
|||||||
@inherits AntDomComponentBase
|
@inherits AntDomComponentBase
|
||||||
|
|
||||||
<CascadingValue Value="this" IsFixed="@true">
|
<CascadingValue Value="this" IsFixed="@true">
|
||||||
<button class="@ClassMapper.Class" style="@(this.Danger ? this._btnWave + Style:Style)" id="@Id" type="@HtmlType" @ref="@Ref"
|
<button class="@ClassMapper.Class" style="@(this.Danger ? this._btnWave + Style : Style)" id="@Id" type="@HtmlType" @ref="@Ref"
|
||||||
@onclick="HandleOnClick" disabled="@Disabled"
|
@onclick="HandleOnClick" disabled="@Disabled"
|
||||||
@onclick:stopPropagation="@OnClickStopPropagation"
|
@onclick:stopPropagation="@OnClickStopPropagation"
|
||||||
@onmouseup="OnMouseUp"
|
@onmouseup="OnMouseUp"
|
||||||
ant-click-animating-without-extra-node="@(this._animating ? "true":"false")">
|
ant-click-animating-without-extra-node="@(this._animating ? "true":"false")">
|
||||||
@if (Loading)
|
@if (Loading)
|
||||||
{
|
{
|
||||||
<Icon Type="loading"></Icon>
|
<span class="ant-btn-loading-icon">
|
||||||
|
<Icon Type="loading" />
|
||||||
|
</span>
|
||||||
}
|
}
|
||||||
@if (!string.IsNullOrEmpty(Icon))
|
else if (!string.IsNullOrEmpty(Icon))
|
||||||
{
|
{
|
||||||
<Icon Type="@Icon" Style="@IconStyle"></Icon>
|
<Icon Type="@Icon" />
|
||||||
|
}
|
||||||
|
@if (ChildContent != default)
|
||||||
|
{
|
||||||
|
@if (NoSpanWrap)
|
||||||
|
{
|
||||||
|
@ChildContent
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span>@ChildContent</span>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ChildContent
|
|
||||||
</button>
|
</button>
|
||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
|
@ -49,7 +49,7 @@ namespace AntDesign
|
|||||||
public bool Danger { get; set; }
|
public bool Danger { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the `Button` is disabled.
|
/// Whether the `Button` is disabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Disabled { get; set; }
|
public bool Disabled { get; set; }
|
||||||
@ -73,21 +73,10 @@ namespace AntDesign
|
|||||||
public string Icon { get; set; }
|
public string Icon { 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]
|
[Parameter]
|
||||||
public bool Loading
|
public bool Loading { get; set; }
|
||||||
{
|
|
||||||
get => _loading;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_loading != value)
|
|
||||||
{
|
|
||||||
_loading = value;
|
|
||||||
UpdateIconDisplay(_loading);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback when `Button` is clicked
|
/// Callback when `Button` is clicked
|
||||||
@ -114,19 +103,23 @@ namespace AntDesign
|
|||||||
public string Size { get; set; } = AntSizeLDSType.Default;
|
public string Size { get; set; } = AntSizeLDSType.Default;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Type of the button.
|
/// Type of the button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Type { get; set; } = ButtonType.Default;
|
public string Type { get; set; } = ButtonType.Default;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Do not wrap with <span>
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public bool NoSpanWrap { get; set; }
|
||||||
|
|
||||||
public IList<Icon> Icons { get; set; } = new List<Icon>();
|
public IList<Icon> Icons { get; set; } = new List<Icon>();
|
||||||
|
|
||||||
protected string IconStyle { get; set; }
|
|
||||||
|
|
||||||
private bool _animating = false;
|
private bool _animating = false;
|
||||||
|
|
||||||
private string _btnWave = "--antd-wave-shadow-color: rgb(255, 120, 117);";
|
private string _btnWave = "--antd-wave-shadow-color: rgb(255, 120, 117);";
|
||||||
private bool _loading = false;
|
|
||||||
|
|
||||||
protected void SetClassMap()
|
protected void SetClassMap()
|
||||||
{
|
{
|
||||||
@ -152,12 +145,6 @@ namespace AntDesign
|
|||||||
base.OnInitialized();
|
base.OnInitialized();
|
||||||
SetClassMap();
|
SetClassMap();
|
||||||
SetButtonColorStyle();
|
SetButtonColorStyle();
|
||||||
UpdateIconDisplay(_loading);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateIconDisplay(bool loading)
|
|
||||||
{
|
|
||||||
IconStyle = $"display:{(loading ? "none" : "inline-block")}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleOnClick(MouseEventArgs args)
|
private async Task HandleOnClick(MouseEventArgs args)
|
||||||
|
@ -74,7 +74,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
#endregion Parameters
|
#endregion Parameters
|
||||||
|
|
||||||
[Inject] public DomEventService DomEventService { get; set; }
|
[Inject] public IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
public void Next() => GoTo(_slicks.IndexOf(ActiveSlick) + 1);
|
public void Next() => GoTo(_slicks.IndexOf(ActiveSlick) + 1);
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ namespace AntDesign
|
|||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
Resize();
|
Resize();
|
||||||
DomEventService.AddEventListener("window", "resize", Resize, false);
|
DomEventListener.AddShared<JsonElement>("window", "resize", Resize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,10 +208,8 @@ namespace AntDesign
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "resize", Resize);
|
DomEventListener.Dispose();
|
||||||
|
|
||||||
_slicks.Clear();
|
_slicks.Clear();
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@
|
|||||||
<CascadingValue Value=@("ant-cascader-menus") Name="PrefixCls">
|
<CascadingValue Value=@("ant-cascader-menus") Name="PrefixCls">
|
||||||
<OverlayTrigger Visible="@_dropdownOpened"
|
<OverlayTrigger Visible="@_dropdownOpened"
|
||||||
OnMaskClick="CascaderOnBlur"
|
OnMaskClick="CascaderOnBlur"
|
||||||
Trigger="new TriggerType[] { }"
|
Trigger="new Trigger[] { }"
|
||||||
|
BoundaryAdjustMode="@BoundaryAdjustMode"
|
||||||
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">
|
||||||
|
@ -13,6 +13,11 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
[Parameter] public bool AllowClear { get; set; } = true;
|
[Parameter] public bool AllowClear { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overlay adjustment strategy (when for example browser resize is happening)
|
||||||
|
/// </summary>
|
||||||
|
[Parameter] public TriggerBoundaryAdjustMode BoundaryAdjustMode { get; set; } = TriggerBoundaryAdjustMode.None;
|
||||||
|
|
||||||
[Parameter] public bool ChangeOnSelect { get; set; }
|
[Parameter] public bool ChangeOnSelect { get; set; }
|
||||||
|
|
||||||
[Parameter] public string DefaultValue { get; set; }
|
[Parameter] public string DefaultValue { get; set; }
|
||||||
|
@ -11,10 +11,11 @@
|
|||||||
@ref="Ref"
|
@ref="Ref"
|
||||||
@onmouseenter="OnOverlayMouseEnter"
|
@onmouseenter="OnOverlayMouseEnter"
|
||||||
@onmouseleave="OnOverlayMouseLeave"
|
@onmouseleave="OnOverlayMouseLeave"
|
||||||
@onmouseup="OnOverlayMouseUp"
|
@onmouseup="OnOverlayMouseUp"
|
||||||
@onclick:stopPropagation>
|
@onclick:stopPropagation>
|
||||||
<CascadingValue Value="this" Name="Overlay" IsFixed="@true">
|
|
||||||
<CascadingValue Value="Trigger" Name="ParentTrigger">
|
<CascadingValue Value="this" Name="Overlay" IsFixed>
|
||||||
|
<CascadingValue Value="Trigger" Name="ParentTrigger" IsFixed>
|
||||||
@if (!string.IsNullOrEmpty(OverlayChildPrefixCls))
|
@if (!string.IsNullOrEmpty(OverlayChildPrefixCls))
|
||||||
{
|
{
|
||||||
<CascadingValue Value="OverlayChildPrefixCls" Name="PrefixCls">
|
<CascadingValue Value="OverlayChildPrefixCls" Name="PrefixCls">
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AntDesign.Core.JsInterop.Modules.Components;
|
||||||
using AntDesign.JsInterop;
|
using AntDesign.JsInterop;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
@ -9,14 +9,21 @@ namespace AntDesign.Internal
|
|||||||
{
|
{
|
||||||
public sealed partial class Overlay : AntDomComponentBase
|
public sealed partial class Overlay : AntDomComponentBase
|
||||||
{
|
{
|
||||||
[CascadingParameter(Name = "Trigger")]
|
[CascadingParameter(Name = "ArrowPointAtCenter")]
|
||||||
public OverlayTrigger Trigger { get; set; }
|
public bool ArrowPointAtCenter { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used in nested overlays (for example menu -> submenu) when
|
||||||
|
/// trigger is another overlay.
|
||||||
|
/// </summary>
|
||||||
[CascadingParameter(Name = "ParentTrigger")]
|
[CascadingParameter(Name = "ParentTrigger")]
|
||||||
public OverlayTrigger ParentTrigger { get; set; }
|
public OverlayTrigger ParentTrigger { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
/// <summary>
|
||||||
public string OverlayChildPrefixCls { get; set; } = "";
|
/// Component that will trigger the overlay to show.
|
||||||
|
/// </summary>
|
||||||
|
[CascadingParameter(Name = "Trigger")]
|
||||||
|
public OverlayTrigger Trigger { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public RenderFragment ChildContent { get; set; }
|
public RenderFragment ChildContent { get; set; }
|
||||||
@ -31,13 +38,14 @@ namespace AntDesign.Internal
|
|||||||
public EventCallback OnOverlayMouseUp { get; set; }
|
public EventCallback OnOverlayMouseUp { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Action OnShow { get; set; }
|
public EventCallback OnShow { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Action OnHide { get; set; }
|
public EventCallback OnHide { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string OverlayChildPrefixCls { get; set; } = "";
|
||||||
|
|
||||||
[CascadingParameter(Name = "ArrowPointAtCenter")]
|
|
||||||
public bool ArrowPointAtCenter { get; set; }
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int HideMillisecondsDelay { get; set; } = 100;
|
public int HideMillisecondsDelay { get; set; } = 100;
|
||||||
@ -69,7 +77,7 @@ namespace AntDesign.Internal
|
|||||||
public bool HiddenMode { get; set; } = false;
|
public bool HiddenMode { get; set; } = false;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
private bool _hasAddOverlayToBody = false;
|
private bool _hasAddOverlayToBody = false;
|
||||||
private bool _isPreventHide = false;
|
private bool _isPreventHide = false;
|
||||||
@ -80,6 +88,7 @@ namespace AntDesign.Internal
|
|||||||
private bool _isWaitForOverlayFirstRender = false;
|
private bool _isWaitForOverlayFirstRender = false;
|
||||||
|
|
||||||
private bool _preVisible = false;
|
private bool _preVisible = false;
|
||||||
|
private bool _isOverlayDuringShowing = false;
|
||||||
private bool _isOverlayShow = false;
|
private bool _isOverlayShow = false;
|
||||||
private bool _isOverlayHiding = false;
|
private bool _isOverlayHiding = false;
|
||||||
private bool _lastDisabledState = false;
|
private bool _lastDisabledState = false;
|
||||||
@ -87,14 +96,20 @@ namespace AntDesign.Internal
|
|||||||
private int? _overlayLeft = null;
|
private int? _overlayLeft = null;
|
||||||
private int? _overlayTop = null;
|
private int? _overlayTop = null;
|
||||||
|
|
||||||
private string _overlayStyle = "";
|
//if this style needs to be changed, also change
|
||||||
|
//the removal of that style in js interop overlay.ts class (in constructor)
|
||||||
|
private string _overlayStyle = "display: none;"; //initial value prevents from screen flickering when adding overlay to dom; it will be overwritten immediately
|
||||||
private string _overlayCls = "";
|
private string _overlayCls = "";
|
||||||
|
|
||||||
private const int ARROW_SIZE = 13;
|
private bool _shouldRender = true;
|
||||||
private const int HORIZONTAL_ARROW_SHIFT = 13;
|
|
||||||
private const int VERTICAL_ARROW_SHIFT = 5;
|
|
||||||
|
|
||||||
private int _overlayClientWidth = 0;
|
protected override bool ShouldRender()
|
||||||
|
{
|
||||||
|
if (_shouldRender)
|
||||||
|
return base.ShouldRender();
|
||||||
|
_shouldRender = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
@ -121,7 +136,7 @@ namespace AntDesign.Internal
|
|||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener("window", "beforeunload", Reloading, false);
|
DomEventListener.AddShared<JsonElement>("window", "beforeunload", Reloading);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_lastDisabledState != Trigger.Disabled)
|
if (_lastDisabledState != Trigger.Disabled)
|
||||||
@ -143,7 +158,7 @@ namespace AntDesign.Internal
|
|||||||
if (_isWaitForOverlayFirstRender && _isOverlayFirstRender)
|
if (_isWaitForOverlayFirstRender && _isOverlayFirstRender)
|
||||||
{
|
{
|
||||||
_isOverlayFirstRender = false;
|
_isOverlayFirstRender = false;
|
||||||
await Show(_overlayLeft, _overlayTop);
|
//await Show(_overlayLeft, _overlayTop);
|
||||||
|
|
||||||
_isWaitForOverlayFirstRender = false;
|
_isWaitForOverlayFirstRender = false;
|
||||||
_overlayLeft = null;
|
_overlayLeft = null;
|
||||||
@ -159,10 +174,10 @@ namespace AntDesign.Internal
|
|||||||
_ = InvokeAsync(async () =>
|
_ = InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
await JsInvokeAsync(JSInteropConstants.DelElementFrom, Ref, Trigger.PopupContainerSelector);
|
await JsInvokeAsync(JSInteropConstants.OverlayComponentHelper.DeleteOverlayFromContainer, Ref.Id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "beforeunload", Reloading);
|
DomEventListener.Dispose();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,24 +187,14 @@ namespace AntDesign.Internal
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await Task.Yield();
|
_isOverlayDuringShowing = true;
|
||||||
HtmlElement trigger;
|
|
||||||
if (Trigger.ChildContent is not null)
|
if (_isOverlayFirstRender)
|
||||||
{
|
{
|
||||||
trigger = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetFirstChildDomInfo, Trigger.Ref);
|
Trigger.SetShouldRender(false);
|
||||||
// fix bug in submenu: Overlay show when OvelayTrigger is not rendered complete.
|
await Task.Yield();
|
||||||
// I try to render Overlay when OvelayTrigger’s OnAfterRender is called, but is still get negative absoluteLeft
|
|
||||||
// This may be a bad solution, but for now I can only do it this way.
|
|
||||||
while (trigger.AbsoluteLeft <= 0 && trigger.ClientWidth <= 0)
|
|
||||||
{
|
|
||||||
await Task.Delay(50);
|
|
||||||
trigger = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetFirstChildDomInfo, Trigger.Ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else //(Trigger.Unbound != null)
|
|
||||||
{
|
|
||||||
trigger = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, Trigger.Ref);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
|
||||||
_overlayLeft = overlayLeft;
|
_overlayLeft = overlayLeft;
|
||||||
_overlayTop = overlayTop;
|
_overlayTop = overlayTop;
|
||||||
@ -198,66 +203,51 @@ namespace AntDesign.Internal
|
|||||||
{
|
{
|
||||||
_isWaitForOverlayFirstRender = true;
|
_isWaitForOverlayFirstRender = true;
|
||||||
|
|
||||||
StateHasChanged();
|
await InvokeAsync(StateHasChanged);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_isOverlayShow = true;
|
|
||||||
_isOverlayHiding = false;
|
|
||||||
|
|
||||||
await UpdateParentOverlayState(true);
|
await UpdateParentOverlayState(true);
|
||||||
|
|
||||||
await AddOverlayToBody();
|
await AddOverlayToBody(overlayLeft, overlayTop);
|
||||||
|
_isOverlayShow = true;
|
||||||
HtmlElement overlayElement = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, Ref);
|
_isOverlayDuringShowing = false;
|
||||||
HtmlElement containerElement = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, Trigger.PopupContainerSelector);
|
_isOverlayHiding = false;
|
||||||
|
|
||||||
int left = await GetOverlayLeftWithBoundaryAdjust(trigger, overlayElement, containerElement);
|
|
||||||
int top = await GetOverlayTopWithBoundaryAdjust(trigger, overlayElement, containerElement);
|
|
||||||
|
|
||||||
int zIndex = await JsInvokeAsync<int>(JSInteropConstants.GetMaxZIndex);
|
|
||||||
|
|
||||||
if (Trigger.Placement.IsIn(PlacementType.BottomRight, PlacementType.TopRight))
|
|
||||||
{
|
|
||||||
var right = ChangeOverlayLeftToRight(left, overlayElement, containerElement);
|
|
||||||
_overlayStyle = $"z-index:{zIndex};left: unset;right: {right}px;top: {top}px;{GetTransformOrigin()}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_overlayStyle = $"z-index:{zIndex};left: {left}px;top: {top}px;{GetTransformOrigin()}";
|
|
||||||
}
|
|
||||||
|
|
||||||
_overlayCls = Trigger.GetOverlayEnterClass();
|
_overlayCls = Trigger.GetOverlayEnterClass();
|
||||||
|
|
||||||
await Trigger.OnVisibleChange.InvokeAsync(true);
|
await Trigger.OnVisibleChange.InvokeAsync(true);
|
||||||
|
|
||||||
StateHasChanged();
|
await InvokeAsync(StateHasChanged);
|
||||||
|
|
||||||
OnShow?.Invoke();
|
if (OnShow.HasDelegate)
|
||||||
|
OnShow.InvokeAsync(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task Hide(bool force = false)
|
internal async Task Hide(bool force = false)
|
||||||
{
|
{
|
||||||
|
if (_isOverlayDuringShowing)
|
||||||
|
{
|
||||||
|
//If Show() method is processing, wait up to 1000 ms
|
||||||
|
//for it to end processing
|
||||||
|
await WaitFor(() => _isOverlayShow);
|
||||||
|
}
|
||||||
if (!_isOverlayShow)
|
if (!_isOverlayShow)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(HideMillisecondsDelay);
|
await Task.Delay(HideMillisecondsDelay);
|
||||||
|
|
||||||
if (!force && !IsContainTrigger(TriggerType.Click) && (_isPreventHide || _mouseInOverlay || _isChildOverlayShow))
|
if (!force && !IsContainTrigger(TriggerType.Click) && (_isPreventHide || _mouseInOverlay || _isChildOverlayShow))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_isOverlayFirstRender = true;
|
_isOverlayFirstRender = true;
|
||||||
|
|
||||||
_isWaitForOverlayFirstRender = false;
|
_isWaitForOverlayFirstRender = false;
|
||||||
_isOverlayHiding = true;
|
_isOverlayHiding = true;
|
||||||
|
|
||||||
_overlayCls = Trigger.GetOverlayLeaveClass();
|
_overlayCls = Trigger.GetOverlayLeaveClass();
|
||||||
|
|
||||||
await Trigger.OnOverlayHiding.InvokeAsync(true);
|
await Trigger.OnOverlayHiding.InvokeAsync(true);
|
||||||
|
|
||||||
await UpdateParentOverlayState(false);
|
await UpdateParentOverlayState(false);
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
@ -271,7 +261,8 @@ namespace AntDesign.Internal
|
|||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
|
|
||||||
OnHide?.Invoke();
|
if (OnHide.HasDelegate)
|
||||||
|
OnHide.InvokeAsync(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void PreventHide(bool prevent)
|
internal void PreventHide(bool prevent)
|
||||||
@ -308,275 +299,84 @@ namespace AntDesign.Internal
|
|||||||
/// Indicates that a page is being refreshed
|
/// Indicates that a page is being refreshed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool _isReloading;
|
private bool _isReloading;
|
||||||
|
private OverlayPosition _position;
|
||||||
|
|
||||||
private void Reloading(JsonElement jsonElement) => _isReloading = true;
|
private void Reloading(JsonElement jsonElement) => _isReloading = true;
|
||||||
|
|
||||||
private async Task AddOverlayToBody()
|
private int _recurenceGuard = 0;
|
||||||
|
private async Task AddOverlayToBody(int? overlayLeft = null, int? overlayTop = null)
|
||||||
{
|
{
|
||||||
if (!_hasAddOverlayToBody)
|
if (!_hasAddOverlayToBody)
|
||||||
{
|
{
|
||||||
await JsInvokeAsync(JSInteropConstants.AddElementTo, Ref, Trigger.PopupContainerSelector);
|
bool triggerIsWrappedInDiv = Trigger.Unbound is null;
|
||||||
|
_recurenceGuard++;
|
||||||
|
|
||||||
_hasAddOverlayToBody = true;
|
//In ServerSide it may happen that trigger element reference has not yet been retrieved.
|
||||||
}
|
if (!(await WaitFor(() => Trigger.Ref.Id is not null)))
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> GetOverlayTopWithBoundaryAdjust(HtmlElement trigger, HtmlElement overlay, HtmlElement containerElement)
|
|
||||||
{
|
|
||||||
int top = GetOverlayTop(trigger, overlay, containerElement);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 边界检测和方向调整
|
|
||||||
* boundary detection and orientation adjustment
|
|
||||||
*/
|
|
||||||
return await BoundaryAdjust(trigger, overlay, containerElement, top, "top");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> GetOverlayLeftWithBoundaryAdjust(HtmlElement trigger, HtmlElement overlay, HtmlElement containerElement)
|
|
||||||
{
|
|
||||||
int left = GetOverlayLeft(trigger, overlay, containerElement);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 边界检测和方向调整
|
|
||||||
* boundary detection and orientation adjustment
|
|
||||||
*/
|
|
||||||
return await BoundaryAdjust(trigger, overlay, containerElement, left, "left");
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetOverlayTop(HtmlElement trigger, HtmlElement overlay, HtmlElement containerElement)
|
|
||||||
{
|
|
||||||
int top = 0;
|
|
||||||
|
|
||||||
int triggerTop = (int)(containerElement.ScrollTop + trigger.AbsoluteTop - containerElement.AbsoluteTop);
|
|
||||||
int triggerHeight = trigger.ClientHeight != 0 ? trigger.ClientHeight : trigger.OffsetHeight;
|
|
||||||
|
|
||||||
// contextMenu
|
|
||||||
if (_overlayTop != null)
|
|
||||||
{
|
|
||||||
triggerTop += (int)_overlayTop;
|
|
||||||
triggerHeight = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Trigger.Placement.IsIn(PlacementType.Left, PlacementType.Right))
|
|
||||||
{
|
|
||||||
top = triggerTop + triggerHeight / 2 - overlay.ClientHeight / 2;
|
|
||||||
}
|
|
||||||
else if (Trigger.Placement.IsIn(PlacementType.LeftTop, PlacementType.RightTop))
|
|
||||||
{
|
|
||||||
top = triggerTop;
|
|
||||||
|
|
||||||
if (ArrowPointAtCenter)
|
|
||||||
{
|
{
|
||||||
top += -VERTICAL_ARROW_SHIFT - ARROW_SIZE / 2 + triggerHeight / 2;
|
//Place where Error Boundary could be utilized
|
||||||
|
throw new ArgumentNullException("Trigger.Ref.Id cannot be null when attaching overlay to it.");
|
||||||
}
|
}
|
||||||
}
|
_position = await JsInvokeAsync<OverlayPosition>(JSInteropConstants.OverlayComponentHelper.AddOverlayToContainer,
|
||||||
else if (Trigger.Placement.IsIn(PlacementType.LeftBottom, PlacementType.RightBottom))
|
Ref.Id, Ref, Trigger.Ref, Trigger.Placement, Trigger.PopupContainerSelector,
|
||||||
{
|
Trigger.BoundaryAdjustMode, triggerIsWrappedInDiv, Trigger.PrefixCls,
|
||||||
top = triggerTop - overlay.ClientHeight + triggerHeight;
|
VerticalOffset, HorizontalOffset, ArrowPointAtCenter, overlayTop, overlayLeft);
|
||||||
|
if (_position is null && _recurenceGuard <= 10) //up to 10 attempts
|
||||||
if (ArrowPointAtCenter)
|
|
||||||
{
|
{
|
||||||
top += VERTICAL_ARROW_SHIFT + ARROW_SIZE / 2 - triggerHeight / 2;
|
Console.WriteLine($"Failed to add overlay to the container. Container: {Trigger.PopupContainerSelector}, trigger: {Trigger.Ref.Id}, overlay: {Ref.Id}. Awaiting and rerunning.");
|
||||||
|
await Task.Delay(10);
|
||||||
|
await AddOverlayToBody(overlayLeft, overlayTop);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else if (Trigger.Placement.IsIn(PlacementType.BottomLeft, PlacementType.BottomCenter, PlacementType.Bottom, PlacementType.BottomRight))
|
|
||||||
{
|
|
||||||
top = triggerTop + triggerHeight + VerticalOffset;
|
|
||||||
}
|
|
||||||
else if (Trigger.Placement.IsIn(PlacementType.TopLeft, PlacementType.TopCenter, PlacementType.Top, PlacementType.TopRight))
|
|
||||||
{
|
|
||||||
top = triggerTop - overlay.ClientHeight - VerticalOffset;
|
|
||||||
}
|
|
||||||
top -= containerElement.ClientTop;
|
|
||||||
|
|
||||||
return top;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetOverlayLeft(HtmlElement trigger, HtmlElement overlay, HtmlElement containerElement)
|
|
||||||
{
|
|
||||||
int left = 0;
|
|
||||||
|
|
||||||
int triggerLeft = trigger.AbsoluteLeft - containerElement.AbsoluteLeft;
|
|
||||||
int triggerWidth = trigger.ClientWidth != 0 ? trigger.ClientWidth : trigger.OffsetWidth;
|
|
||||||
|
|
||||||
if (overlay.ClientWidth > 0)
|
|
||||||
{
|
|
||||||
_overlayClientWidth = overlay.ClientWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
// contextMenu
|
|
||||||
if (_overlayLeft != null)
|
|
||||||
{
|
|
||||||
triggerLeft += (int)_overlayLeft;
|
|
||||||
triggerWidth = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Trigger.Placement.IsIn(PlacementType.Left, PlacementType.LeftTop, PlacementType.LeftBottom))
|
|
||||||
{
|
|
||||||
left = triggerLeft - _overlayClientWidth - HorizontalOffset;
|
|
||||||
}
|
|
||||||
else if (Trigger.Placement.IsIn(PlacementType.Right, PlacementType.RightTop, PlacementType.RightBottom))
|
|
||||||
{
|
|
||||||
left = triggerLeft + triggerWidth + HorizontalOffset;
|
|
||||||
}
|
|
||||||
else if (Trigger.Placement.IsIn(PlacementType.BottomLeft, PlacementType.TopLeft))
|
|
||||||
{
|
|
||||||
left = triggerLeft;
|
|
||||||
|
|
||||||
if (ArrowPointAtCenter)
|
|
||||||
{
|
{
|
||||||
left += -HORIZONTAL_ARROW_SHIFT - ARROW_SIZE / 2 + triggerWidth / 2;
|
_hasAddOverlayToBody = true;
|
||||||
|
_overlayStyle = _position.PositionCss + GetTransformOrigin();
|
||||||
|
if (_position.Placement != Trigger.Placement)
|
||||||
|
{
|
||||||
|
Trigger.ChangePlacementForShow(PlacementType.Create(_position.Placement));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Trigger.Placement.IsIn(PlacementType.BottomCenter, PlacementType.Bottom, PlacementType.TopCenter, PlacementType.Top))
|
|
||||||
{
|
|
||||||
left = triggerLeft + triggerWidth / 2 - _overlayClientWidth / 2;
|
|
||||||
}
|
|
||||||
else if (Trigger.Placement.IsIn(PlacementType.BottomRight, PlacementType.TopRight))
|
|
||||||
{
|
|
||||||
left = triggerLeft + triggerWidth - _overlayClientWidth;
|
|
||||||
|
|
||||||
if (ArrowPointAtCenter)
|
|
||||||
{
|
|
||||||
left += HORIZONTAL_ARROW_SHIFT + ARROW_SIZE / 2 - triggerWidth / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
left -= containerElement.ClientLeft;
|
|
||||||
|
|
||||||
return left;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 边界检测和方向调整
|
|
||||||
* boundary detection and orientation adjustment
|
|
||||||
*/
|
|
||||||
|
|
||||||
private async Task<int> BoundaryAdjust(
|
|
||||||
HtmlElement trigger, HtmlElement overlay, HtmlElement containerElement,
|
|
||||||
int curPos, string direction)
|
|
||||||
{
|
|
||||||
if (Trigger.BoundaryAdjustMode == TriggerBoundaryAdjustMode.None)
|
|
||||||
{
|
|
||||||
return curPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
int overlaySize = direction == "top" ? overlay.ClientHeight : overlay.ClientWidth;
|
|
||||||
int boundarySize = await GetWindowBoundarySize(direction, containerElement);
|
|
||||||
|
|
||||||
// 距离边界的长度或宽度/distance from top or left boundry
|
|
||||||
int distanceFromBoundry = await GetOverlayDistanceFromBoundary(direction, curPos);
|
|
||||||
|
|
||||||
if (Trigger.Trigger.Contains(TriggerType.ContextMenu))
|
|
||||||
{
|
|
||||||
if (overlaySize + curPos > boundarySize)
|
|
||||||
{
|
|
||||||
curPos -= overlaySize;
|
|
||||||
}
|
|
||||||
else if (curPos < 0)
|
|
||||||
{
|
|
||||||
curPos += overlaySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return curPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
int overlayPosWithSize = GetOverlayPosWithSize(curPos, overlaySize);
|
|
||||||
|
|
||||||
if ((overlayPosWithSize > boundarySize || overlayPosWithSize < 0)
|
|
||||||
&& distanceFromBoundry >= overlaySize) // check if still outof boundary after reverse placement
|
|
||||||
{
|
|
||||||
// 翻转位置/reverse placement
|
|
||||||
Trigger.ChangePlacementForShow(Trigger.Placement.GetReverseType());
|
|
||||||
|
|
||||||
int reversePos = direction switch
|
|
||||||
{
|
|
||||||
"top" => GetOverlayTop(trigger, overlay, containerElement),
|
|
||||||
_ => GetOverlayLeft(trigger, overlay, containerElement)
|
|
||||||
};
|
|
||||||
|
|
||||||
curPos = reversePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return curPos < 0 ? 0 : curPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetOverlayPosWithSize(int overlayPos, int overlaySize)
|
|
||||||
{
|
|
||||||
PlacementDirection placementDirection = Trigger.Placement.GetDirection();
|
|
||||||
|
|
||||||
if (placementDirection.IsIn(PlacementDirection.Top, PlacementDirection.Left))
|
|
||||||
{
|
|
||||||
return overlayPos - overlaySize;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return overlayPos + overlaySize;
|
await UpdatePosition(overlayLeft, overlayTop);
|
||||||
}
|
}
|
||||||
|
_recurenceGuard = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetOverlayBoundaryPos(int overlaySize, int boundarySize)
|
/// <summary>
|
||||||
|
/// Will probe a check predicate every given milliseconds until predicate is true or until
|
||||||
|
/// runs out of number of probings.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="check">A predicate that will be run every time after waitTimeInMilisecondsPerProbing will pass.</param>
|
||||||
|
/// <param name="probings">Maximum number of probings. After this number is reached, the method finishes.</param>
|
||||||
|
/// <param name="waitTimeInMilisecondsPerProbing">How long to wait between each probing.</param>
|
||||||
|
/// <returns>Task</returns>
|
||||||
|
private async Task<bool> WaitFor(Func<bool> check, int probings = 100, int waitTimeInMilisecondsPerProbing = 10)
|
||||||
{
|
{
|
||||||
PlacementDirection placementDirection = Trigger.Placement.GetDirection();
|
if (!check())
|
||||||
|
|
||||||
if (placementDirection.IsIn(PlacementDirection.Top, PlacementDirection.Left))
|
|
||||||
{
|
{
|
||||||
return 0;
|
for (int i = 0; i < probings; i++)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return boundarySize - overlaySize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> GetOverlayDistanceFromBoundary(string direction, int overlayPos)
|
|
||||||
{
|
|
||||||
if (Trigger.BoundaryAdjustMode == TriggerBoundaryAdjustMode.InScroll)
|
|
||||||
{
|
|
||||||
return overlayPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonElement scrollInfo = await JsInvokeAsync<JsonElement>(JSInteropConstants.GetScroll);
|
|
||||||
int windowScrollX = (int)scrollInfo.GetProperty("x").GetDouble();
|
|
||||||
int windowScrollY = (int)scrollInfo.GetProperty("y").GetDouble();
|
|
||||||
|
|
||||||
return direction switch
|
|
||||||
{
|
|
||||||
"top" => overlayPos - windowScrollY,
|
|
||||||
_ => overlayPos - windowScrollX
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> GetWindowBoundarySize(string direction, HtmlElement containerElement)
|
|
||||||
{
|
|
||||||
if (Trigger.BoundaryAdjustMode == TriggerBoundaryAdjustMode.InScroll)
|
|
||||||
{
|
|
||||||
return direction switch
|
|
||||||
{
|
{
|
||||||
"top" => containerElement.ScrollHeight,
|
await Task.Delay(waitTimeInMilisecondsPerProbing);
|
||||||
_ => containerElement.ScrollWidth
|
if (check())
|
||||||
};
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
Window windowElement = await JsInvokeAsync<Window>(JSInteropConstants.GetWindow, Ref);
|
|
||||||
JsonElement scrollInfo = await JsInvokeAsync<JsonElement>(JSInteropConstants.GetScroll);
|
|
||||||
int windowScrollX = (int)scrollInfo.GetProperty("x").GetDouble();
|
|
||||||
int windowScrollY = (int)scrollInfo.GetProperty("y").GetDouble();
|
|
||||||
|
|
||||||
return direction switch
|
|
||||||
{
|
|
||||||
"top" => (int)windowElement.innerHeight + windowScrollY,
|
|
||||||
_ => (int)windowElement.innerWidth + windowScrollX
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetTransformOrigin()
|
private string GetTransformOrigin()
|
||||||
{
|
{
|
||||||
return $"transform-origin: {Trigger.Placement.TranformOrigin}";
|
return $"transform-origin: {Trigger.GetPlacementType().TranformOrigin}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsContainTrigger(TriggerType triggerType)
|
private bool IsContainTrigger(TriggerType triggerType)
|
||||||
{
|
{
|
||||||
foreach (TriggerType trigger in Trigger.Trigger)
|
foreach (TriggerType trigger in Trigger.GetTriggerType())
|
||||||
{
|
{
|
||||||
if (trigger == triggerType)
|
if (trigger == triggerType)
|
||||||
{
|
{
|
||||||
@ -630,44 +430,25 @@ namespace AntDesign.Internal
|
|||||||
if (_hasAddOverlayToBody)
|
if (_hasAddOverlayToBody)
|
||||||
return "visibility: hidden;";
|
return "visibility: hidden;";
|
||||||
|
|
||||||
|
|
||||||
return "display: inline-flex; visibility: hidden;";
|
return "display: inline-flex; visibility: hidden;";
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task UpdatePosition(int? overlayLeft = null, int? overlayTop = null)
|
internal async Task UpdatePosition(int? overlayLeft = null, int? overlayTop = null)
|
||||||
{
|
{
|
||||||
HtmlElement trigger;
|
bool triggerIsWrappedInDiv = Trigger.Unbound is null;
|
||||||
if (Trigger.ChildContent != null)
|
|
||||||
|
_position = await JsInvokeAsync<OverlayPosition>(JSInteropConstants.OverlayComponentHelper.UpdateOverlayPosition,
|
||||||
|
Ref.Id, Ref, Trigger.Ref, Trigger.Placement, Trigger.PopupContainerSelector,
|
||||||
|
Trigger.BoundaryAdjustMode, triggerIsWrappedInDiv, Trigger.PrefixCls,
|
||||||
|
VerticalOffset, HorizontalOffset, ArrowPointAtCenter, overlayTop, overlayLeft);
|
||||||
|
if (_position is not null)
|
||||||
{
|
{
|
||||||
trigger = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetFirstChildDomInfo, Trigger.Ref);
|
if (_position.Placement != Trigger.Placement)
|
||||||
|
{
|
||||||
|
Trigger.ChangePlacementForShow(PlacementType.Create(_position.Placement));
|
||||||
|
}
|
||||||
|
_overlayStyle = _position.PositionCss + GetTransformOrigin();
|
||||||
}
|
}
|
||||||
else //(Trigger.Unbound != null)
|
|
||||||
{
|
|
||||||
trigger = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, Trigger.Ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
_overlayLeft = overlayLeft;
|
|
||||||
_overlayTop = overlayTop;
|
|
||||||
|
|
||||||
HtmlElement overlayElement = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, Ref);
|
|
||||||
HtmlElement containerElement = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, Trigger.PopupContainerSelector);
|
|
||||||
|
|
||||||
int left = await GetOverlayLeftWithBoundaryAdjust(trigger, overlayElement, containerElement);
|
|
||||||
int top = await GetOverlayTopWithBoundaryAdjust(trigger, overlayElement, containerElement);
|
|
||||||
|
|
||||||
int zIndex = await JsInvokeAsync<int>(JSInteropConstants.GetMaxZIndex);
|
|
||||||
|
|
||||||
if (Trigger.Placement.IsIn(PlacementType.BottomRight, PlacementType.TopRight))
|
|
||||||
{
|
|
||||||
var right = ChangeOverlayLeftToRight(left, overlayElement, containerElement);
|
|
||||||
_overlayStyle = $"z-index:{zIndex};left: unset;right: {right}px;top: {top}px;{GetTransformOrigin()}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_overlayStyle = $"z-index:{zIndex};left: {left}px;top: {top}px;{GetTransformOrigin()}";
|
|
||||||
}
|
|
||||||
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ChangeOverlayLeftToRight(int left, HtmlElement overlay, HtmlElement container)
|
private int ChangeOverlayLeftToRight(int left, HtmlElement overlay, HtmlElement container)
|
||||||
|
@ -34,5 +34,5 @@
|
|||||||
OnHide="OnOverlayHide"
|
OnHide="OnOverlayHide"
|
||||||
OnOverlayMouseEnter="OnOverlayMouseEnter"
|
OnOverlayMouseEnter="OnOverlayMouseEnter"
|
||||||
OnOverlayMouseLeave="OnOverlayMouseLeave"
|
OnOverlayMouseLeave="OnOverlayMouseLeave"
|
||||||
OnOverlayMouseUp="OnOverlayMouseUp" />
|
OnOverlayMouseUp="OnOverlayMouseUp" />
|
||||||
</CascadingValue>
|
</CascadingValue>
|
@ -31,7 +31,8 @@ namespace AntDesign.Internal
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Overlay adjustment strategy (when for example browser resize is happening)
|
/// Overlay adjustment strategy (when for example browser resize is happening). Check
|
||||||
|
/// enum for details.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public TriggerBoundaryAdjustMode BoundaryAdjustMode { get; set; } = TriggerBoundaryAdjustMode.InView;
|
public TriggerBoundaryAdjustMode BoundaryAdjustMode { get; set; } = TriggerBoundaryAdjustMode.InView;
|
||||||
@ -90,12 +91,14 @@ namespace AntDesign.Internal
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback when mouse enters trigger boundaries.
|
/// Callback when mouse enters trigger boundaries.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter] public Action OnMouseEnter { get; set; }
|
[Parameter]
|
||||||
|
public EventCallback OnMouseEnter { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback when mouse leaves trigger boundaries.
|
/// Callback when mouse leaves trigger boundaries.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter] public Action OnMouseLeave { get; set; }
|
[Parameter]
|
||||||
|
public EventCallback OnMouseLeave { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback when overlay is hiding.
|
/// Callback when overlay is hiding.
|
||||||
@ -158,19 +161,21 @@ namespace AntDesign.Internal
|
|||||||
private PlacementType _paramPlacement = PlacementType.BottomLeft;
|
private PlacementType _paramPlacement = PlacementType.BottomLeft;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public PlacementType Placement
|
public Placement Placement
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return RTL ? _placement.GetRTLPlacement() : _placement;
|
return (RTL ? _placement.GetRTLPlacement() : _placement).Placement;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_placement = value;
|
_placement = PlacementType.Create(value);
|
||||||
_paramPlacement = value;
|
_paramPlacement = PlacementType.Create(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal PlacementType GetPlacementType() => _placement;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Override default placement class which is based on `Placement` parameter.
|
/// Override default placement class which is based on `Placement` parameter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -189,7 +194,14 @@ namespace AntDesign.Internal
|
|||||||
/// Trigger mode. Could be multiple by passing an array.
|
/// Trigger mode. Could be multiple by passing an array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public TriggerType[] Trigger { get; set; } = new TriggerType[] { TriggerType.Hover };
|
public Trigger[] Trigger //TODO: this should probably be a flag not an array
|
||||||
|
{
|
||||||
|
get { return _trigger.Select(t => t.Trigger).ToArray(); }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_trigger = value.Select(t => TriggerType.Create(t)).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string TriggerCls { get; set; }
|
public string TriggerCls { get; set; }
|
||||||
@ -204,6 +216,8 @@ namespace AntDesign.Internal
|
|||||||
set => Ref = value;
|
set => Ref = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal TriggerType[] GetTriggerType() => _trigger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ChildElement with ElementReference set to avoid wrapping div.
|
/// ChildElement with ElementReference set to avoid wrapping div.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -217,21 +231,31 @@ namespace AntDesign.Internal
|
|||||||
public bool Visible { get; set; } = false;
|
public bool Visible { get; set; } = false;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
protected DomEventService DomEventService { get; set; }
|
protected IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
private bool _mouseInTrigger = false;
|
private bool _mouseInTrigger = false;
|
||||||
private bool _mouseInOverlay = false;
|
private bool _mouseInOverlay = false;
|
||||||
private bool _mouseUpInOverlay = false;
|
private bool _mouseUpInOverlay = false;
|
||||||
|
|
||||||
protected Overlay _overlay = null;
|
protected Overlay _overlay = null;
|
||||||
|
private TriggerType[] _trigger = new TriggerType[] { TriggerType.Hover };
|
||||||
|
private bool _shouldRender = true;
|
||||||
|
|
||||||
|
internal void SetShouldRender(bool shouldRender) => _shouldRender = shouldRender;
|
||||||
|
|
||||||
|
protected override bool ShouldRender()
|
||||||
|
{
|
||||||
|
if (_shouldRender)
|
||||||
|
return base.ShouldRender();
|
||||||
|
_shouldRender = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnAfterRender(bool firstRender)
|
protected override void OnAfterRender(bool firstRender)
|
||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener("document", "mouseup", OnMouseUp, false);
|
DomEventListener.AddShared<JsonElement>("document", "mouseup", OnMouseUp);
|
||||||
DomEventService.AddEventListener("window", "resize", OnWindowResize, false);
|
|
||||||
DomEventService.AddEventListener("document", "scroll", OnWindowScroll, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnAfterRender(firstRender);
|
base.OnAfterRender(firstRender);
|
||||||
@ -245,15 +269,14 @@ namespace AntDesign.Internal
|
|||||||
{
|
{
|
||||||
Ref = RefBack.Current;
|
Ref = RefBack.Current;
|
||||||
|
|
||||||
DomEventService.AddEventListener(Ref, "click", OnUnboundClick, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "click", OnUnboundClick);
|
||||||
DomEventService.AddEventListener(Ref, "mouseover", OnUnboundMouseEnter, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "mouseover", OnUnboundMouseEnter);
|
||||||
DomEventService.AddEventListener(Ref, "mouseout", OnUnboundMouseLeave, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "mouseout", OnUnboundMouseLeave);
|
||||||
DomEventService.AddEventListener(Ref, "focusin", OnUnboundFocusIn, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "focusin", OnUnboundFocusIn);
|
||||||
DomEventService.AddEventListener(Ref, "focusout", OnUnboundFocusOut, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "focusout", OnUnboundFocusOut);
|
||||||
DomEventService.AddEventListener(Ref, "contextmenu", OnContextMenu, true, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "contextmenu", OnContextMenu, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(TriggerCls))
|
if (!string.IsNullOrWhiteSpace(TriggerCls))
|
||||||
{
|
{
|
||||||
if (Unbound != null)
|
if (Unbound != null)
|
||||||
@ -295,19 +318,8 @@ namespace AntDesign.Internal
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("document", "mouseup", OnMouseUp);
|
DomEventListener.Dispose();
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "resize", OnWindowResize);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("document", "scroll", OnWindowScroll);
|
|
||||||
|
|
||||||
if (Unbound != null)
|
|
||||||
{
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "click", OnUnboundClick);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "mouseover", OnUnboundMouseEnter);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "mouseout", OnUnboundMouseLeave);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "focusin", OnUnboundFocusIn);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "focusout", OnUnboundFocusOut);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "contextmenu", OnContextMenu);
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,8 +333,13 @@ namespace AntDesign.Internal
|
|||||||
|
|
||||||
await Show();
|
await Show();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_shouldRender = false;
|
||||||
|
}
|
||||||
|
|
||||||
OnMouseEnter?.Invoke();
|
if (OnMouseEnter.HasDelegate)
|
||||||
|
OnMouseEnter.InvokeAsync(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual async Task OnTriggerMouseLeave()
|
protected virtual async Task OnTriggerMouseLeave()
|
||||||
@ -335,8 +352,13 @@ namespace AntDesign.Internal
|
|||||||
|
|
||||||
await Hide();
|
await Hide();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_shouldRender = false;
|
||||||
|
}
|
||||||
|
|
||||||
OnMouseLeave?.Invoke();
|
if (OnMouseLeave.HasDelegate)
|
||||||
|
OnMouseLeave.InvokeAsync(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual async Task OnTriggerFocusIn()
|
protected virtual async Task OnTriggerFocusIn()
|
||||||
@ -432,8 +454,8 @@ namespace AntDesign.Internal
|
|||||||
{
|
{
|
||||||
int offsetX = 10;
|
int offsetX = 10;
|
||||||
int offsetY = 10;
|
int offsetY = 10;
|
||||||
#if NET5_0
|
#if NET5_0_OR_GREATER
|
||||||
// offsetX/offsetY were only supported in Net5
|
// offsetX/offsetY were only supported in Net5 or grater
|
||||||
offsetX = (int)args.OffsetX;
|
offsetX = (int)args.OffsetX;
|
||||||
offsetY = (int)args.OffsetY;
|
offsetY = (int)args.OffsetY;
|
||||||
#endif
|
#endif
|
||||||
@ -462,24 +484,10 @@ namespace AntDesign.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async void OnWindowResize(JsonElement element)
|
|
||||||
{
|
|
||||||
RestorePlacement();
|
|
||||||
|
|
||||||
if (IsOverlayShow())
|
|
||||||
{
|
|
||||||
await GetOverlayComponent().UpdatePosition();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void OnWindowScroll(JsonElement element)
|
|
||||||
{
|
|
||||||
RestorePlacement();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual bool IsContainTrigger(TriggerType triggerType)
|
protected virtual bool IsContainTrigger(TriggerType triggerType)
|
||||||
{
|
{
|
||||||
return Trigger.Contains(triggerType);
|
return _trigger.Contains(triggerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual async Task OverlayVisibleChange(bool visible)
|
protected virtual async Task OverlayVisibleChange(bool visible)
|
||||||
@ -505,18 +513,13 @@ namespace AntDesign.Internal
|
|||||||
_placement = placement;
|
_placement = placement;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RestorePlacement()
|
|
||||||
{
|
|
||||||
_placement = _paramPlacement;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal virtual string GetPlacementClass()
|
internal virtual string GetPlacementClass()
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(PlacementCls))
|
if (!string.IsNullOrEmpty(PlacementCls))
|
||||||
{
|
{
|
||||||
return PlacementCls;
|
return PlacementCls;
|
||||||
}
|
}
|
||||||
return $"{PrefixCls}-placement-{Placement.Name}";
|
return $"{PrefixCls}-placement-{_placement.Name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
internal virtual string GetOverlayEnterClass()
|
internal virtual string GetOverlayEnterClass()
|
||||||
@ -525,7 +528,7 @@ namespace AntDesign.Internal
|
|||||||
{
|
{
|
||||||
return OverlayEnterCls;
|
return OverlayEnterCls;
|
||||||
}
|
}
|
||||||
return $"ant-slide-{Placement.SlideName}-enter ant-slide-{Placement.SlideName}-enter-active ant-slide-{Placement.SlideName}";
|
return $"ant-slide-{_placement.SlideName}-enter ant-slide-{_placement.SlideName}-enter-active ant-slide-{_placement.SlideName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
internal virtual string GetOverlayLeaveClass()
|
internal virtual string GetOverlayLeaveClass()
|
||||||
@ -534,7 +537,7 @@ namespace AntDesign.Internal
|
|||||||
{
|
{
|
||||||
return OverlayLeaveCls;
|
return OverlayLeaveCls;
|
||||||
}
|
}
|
||||||
return $"ant-slide-{Placement.SlideName}-leave ant-slide-{Placement.SlideName}-leave-active ant-slide-{Placement.SlideName}";
|
return $"ant-slide-{_placement.SlideName}-leave ant-slide-{_placement.SlideName}-leave-active ant-slide-{_placement.SlideName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
internal virtual string GetOverlayHiddenClass()
|
internal virtual string GetOverlayHiddenClass()
|
||||||
|
@ -1,32 +1,72 @@
|
|||||||
namespace AntDesign
|
namespace AntDesign
|
||||||
{
|
{
|
||||||
|
public enum Placement
|
||||||
|
{
|
||||||
|
TopLeft,
|
||||||
|
TopCenter,
|
||||||
|
Top,
|
||||||
|
TopRight,
|
||||||
|
Left,
|
||||||
|
LeftTop,
|
||||||
|
LeftBottom,
|
||||||
|
Right,
|
||||||
|
RightTop,
|
||||||
|
RightBottom,
|
||||||
|
BottomLeft,
|
||||||
|
BottomCenter,
|
||||||
|
Bottom,
|
||||||
|
BottomRight
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class PlacementType : EnumValue<PlacementType>
|
public sealed class PlacementType : EnumValue<PlacementType>
|
||||||
{
|
{
|
||||||
public static readonly PlacementType TopLeft = new PlacementType("topLeft", "down", "33% 100%", 0);
|
public static readonly PlacementType TopLeft = new PlacementType("topLeft", "down", "33% 100%", 0, Placement.TopLeft);
|
||||||
public static readonly PlacementType TopCenter = new PlacementType("topCenter", "down", "50% 100%", 1);
|
public static readonly PlacementType TopCenter = new PlacementType("topCenter", "down", "50% 100%", 1, Placement.TopCenter);
|
||||||
public static readonly PlacementType Top = new PlacementType("top", "down", "50% 100%", 1);
|
public static readonly PlacementType Top = new PlacementType("top", "down", "50% 100%", 1, Placement.Top);
|
||||||
public static readonly PlacementType TopRight = new PlacementType("topRight", "down", "66% 100%", 2);
|
public static readonly PlacementType TopRight = new PlacementType("topRight", "down", "66% 100%", 2, Placement.TopRight);
|
||||||
|
|
||||||
public static readonly PlacementType Left = new PlacementType("left", "up", "100% 50%%", 3);
|
public static readonly PlacementType Left = new PlacementType("left", "up", "100% 50%%", 3, Placement.Left);
|
||||||
public static readonly PlacementType LeftTop = new PlacementType("leftTop", "down", "100% 33%", 4);
|
public static readonly PlacementType LeftTop = new PlacementType("leftTop", "down", "100% 33%", 4, Placement.LeftTop);
|
||||||
public static readonly PlacementType LeftBottom = new PlacementType("leftBottom", "up", "100% 66%", 5);
|
public static readonly PlacementType LeftBottom = new PlacementType("leftBottom", "up", "100% 66%", 5, Placement.LeftBottom);
|
||||||
|
|
||||||
public static readonly PlacementType Right = new PlacementType("right", "up", "0 50%", 6);
|
public static readonly PlacementType Right = new PlacementType("right", "up", "0 50%", 6, Placement.Right);
|
||||||
public static readonly PlacementType RightTop = new PlacementType("rightTop", "down", "0 33%", 7);
|
public static readonly PlacementType RightTop = new PlacementType("rightTop", "down", "0 33%", 7, Placement.RightTop);
|
||||||
public static readonly PlacementType RightBottom = new PlacementType("rightBottom", "up", "0 66%", 8);
|
public static readonly PlacementType RightBottom = new PlacementType("rightBottom", "up", "0 66%", 8, Placement.RightBottom);
|
||||||
|
|
||||||
public static readonly PlacementType BottomLeft = new PlacementType("bottomLeft", "up", "33% 0", 9);
|
public static readonly PlacementType BottomLeft = new PlacementType("bottomLeft", "up", "33% 0", 9, Placement.BottomLeft);
|
||||||
public static readonly PlacementType BottomCenter = new PlacementType("bottomCenter", "up", "50% 0", 10);
|
public static readonly PlacementType BottomCenter = new PlacementType("bottomCenter", "up", "50% 0", 10, Placement.BottomCenter);
|
||||||
public static readonly PlacementType Bottom = new PlacementType("bottom", "up", "50% 0", 10);
|
public static readonly PlacementType Bottom = new PlacementType("bottom", "up", "50% 0", 10, Placement.Bottom);
|
||||||
public static readonly PlacementType BottomRight = new PlacementType("bottomRight", "up", "66% 0", 11);
|
public static readonly PlacementType BottomRight = new PlacementType("bottomRight", "up", "66% 0", 11, Placement.BottomRight);
|
||||||
|
|
||||||
|
public static PlacementType Create(Placement placement) => placement switch
|
||||||
|
{
|
||||||
|
Placement.TopLeft => PlacementType.TopLeft,
|
||||||
|
Placement.TopCenter => PlacementType.TopCenter,
|
||||||
|
Placement.Top => PlacementType.Top,
|
||||||
|
Placement.TopRight => PlacementType.TopRight,
|
||||||
|
Placement.Left => PlacementType.Left,
|
||||||
|
Placement.LeftTop => PlacementType.LeftTop,
|
||||||
|
Placement.LeftBottom => PlacementType.LeftBottom,
|
||||||
|
Placement.Right => PlacementType.Right,
|
||||||
|
Placement.RightTop => PlacementType.RightTop,
|
||||||
|
Placement.RightBottom => PlacementType.RightBottom,
|
||||||
|
Placement.BottomLeft => PlacementType.BottomLeft,
|
||||||
|
Placement.BottomCenter => PlacementType.BottomCenter,
|
||||||
|
Placement.Bottom => PlacementType.Bottom,
|
||||||
|
Placement.BottomRight => PlacementType.BottomRight,
|
||||||
|
_ => PlacementType.BottomLeft
|
||||||
|
};
|
||||||
|
|
||||||
public string SlideName { get; private set; }
|
public string SlideName { get; private set; }
|
||||||
public string TranformOrigin { get; private set; }
|
public string TranformOrigin { get; private set; }
|
||||||
|
|
||||||
public PlacementType(string name, string slideName, string transformOrigin, int value) : base(name, value)
|
public Placement Placement { get; private set; } = Placement.BottomLeft;
|
||||||
|
|
||||||
|
private PlacementType(string name, string slideName, string transformOrigin, int value, Placement placement) : base(name, value)
|
||||||
{
|
{
|
||||||
SlideName = slideName;
|
SlideName = slideName;
|
||||||
TranformOrigin = transformOrigin;
|
TranformOrigin = transformOrigin;
|
||||||
|
Placement = placement;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal PlacementType GetReverseType()
|
internal PlacementType GetReverseType()
|
||||||
|
@ -9,12 +9,18 @@
|
|||||||
None,
|
None,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 在可视范围内(默认模式)
|
/// 在可视范围内(默认模式)
|
||||||
/// in view(default mode)
|
/// The default, the viewport boundaries are the boundaries that are used for calculation if overlay
|
||||||
|
/// is fully visible.
|
||||||
|
/// Attempt to fit the overlay so it is always fully visible in the viewport.
|
||||||
|
/// So if the overlay is outside of the viewport ("overflows"), then reposition calculation is going
|
||||||
|
/// to be attempted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
InView,
|
InView,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 在滚动范围内
|
/// 在滚动范围内
|
||||||
/// in scroll
|
/// The document boundaries are the boundaries used for calculation if overlay needs to be reposition.
|
||||||
|
/// So even if the overlay is outside of the viewport, the overlay may still be shown as long as it
|
||||||
|
/// does not "overflow" the document boundaries.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
InScroll,
|
InScroll,
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,41 @@
|
|||||||
namespace AntDesign
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace AntDesign
|
||||||
{
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum Trigger
|
||||||
|
{
|
||||||
|
Click = 1 << 0,
|
||||||
|
Hover = 1 << 1,
|
||||||
|
Focus = 1 << 2,
|
||||||
|
ContextMenu = 1 << 3
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class TriggerType : EnumValue<TriggerType>
|
public sealed class TriggerType : EnumValue<TriggerType>
|
||||||
{
|
{
|
||||||
public static readonly TriggerType Click = new TriggerType(nameof(Click), 0);
|
public static readonly TriggerType Click = new TriggerType(nameof(Click), 0, Trigger.Click);
|
||||||
public static readonly TriggerType Hover = new TriggerType(nameof(Hover), 1);
|
public static readonly TriggerType Hover = new TriggerType(nameof(Hover), 1, Trigger.Hover);
|
||||||
public static readonly TriggerType Focus = new TriggerType(nameof(Focus), 2);
|
public static readonly TriggerType Focus = new TriggerType(nameof(Focus), 2, Trigger.Focus);
|
||||||
public static readonly TriggerType ContextMenu = new TriggerType(nameof(ContextMenu), 3);
|
public static readonly TriggerType ContextMenu = new TriggerType(nameof(ContextMenu), 3, Trigger.ContextMenu);
|
||||||
|
|
||||||
private TriggerType(string name, int value) : base(name, value)
|
public static TriggerType Create(Trigger trigger)
|
||||||
{
|
{
|
||||||
|
return trigger switch
|
||||||
|
{
|
||||||
|
Trigger.Click => Click,
|
||||||
|
Trigger.Hover => Hover,
|
||||||
|
Trigger.Focus => Focus,
|
||||||
|
Trigger.ContextMenu => ContextMenu,
|
||||||
|
_ => throw new InvalidEnumArgumentException($"Unrecognized value of Trigger enum ({trigger}).")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TriggerType(string name, int value, Trigger trigger) : base(name, value)
|
||||||
|
{
|
||||||
|
Trigger = trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Trigger Trigger { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using AntDesign;
|
|||||||
using AntDesign.JsInterop;
|
using AntDesign.JsInterop;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
@ -12,6 +13,12 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
public static IServiceCollection AddAntDesign(this IServiceCollection services)
|
public static IServiceCollection AddAntDesign(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.TryAddScoped<DomEventService>();
|
services.TryAddScoped<DomEventService>();
|
||||||
|
services.TryAddTransient<IDomEventListener>((sp) =>
|
||||||
|
{
|
||||||
|
var domEventService = sp.GetRequiredService<DomEventService>();
|
||||||
|
return domEventService.CreateDomEventListerner();
|
||||||
|
});
|
||||||
|
|
||||||
services.TryAddScoped(sp => new HtmlRenderService(new HtmlRenderer(sp, sp.GetRequiredService<ILoggerFactory>(),
|
services.TryAddScoped(sp => new HtmlRenderService(new HtmlRenderer(sp, sp.GetRequiredService<ILoggerFactory>(),
|
||||||
s => HtmlEncoder.Default.Encode(s)))
|
s => HtmlEncoder.Default.Encode(s)))
|
||||||
);
|
);
|
||||||
|
255
components/core/JsInterop/DomEventListener.cs
Normal file
255
components/core/JsInterop/DomEventListener.cs
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AntDesign.Core.Extensions;
|
||||||
|
using AntDesign.Core.JsInterop.ObservableApi;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
|
|
||||||
|
namespace AntDesign.JsInterop
|
||||||
|
{
|
||||||
|
public class DomEventListener : IDomEventListener
|
||||||
|
{
|
||||||
|
private Dictionary<string, IDisposable> _dotNetObjectStore = new();
|
||||||
|
private bool? _isResizeObserverSupported = null;
|
||||||
|
|
||||||
|
private readonly IJSRuntime _jsRuntime;
|
||||||
|
private readonly DomEventSubscriptionStore _domEventSubscriptionsStore;
|
||||||
|
private readonly string _id;
|
||||||
|
|
||||||
|
public DomEventListener(IJSRuntime jsRuntime, DomEventSubscriptionStore domEventSubscriptionStore)
|
||||||
|
{
|
||||||
|
_jsRuntime = jsRuntime;
|
||||||
|
_domEventSubscriptionsStore = domEventSubscriptionStore;
|
||||||
|
_id = Guid.NewGuid().ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FormatKey(object dom, string eventName)
|
||||||
|
{
|
||||||
|
var selector = dom is ElementReference eleRef ? eleRef.Id : dom.ToString();
|
||||||
|
if (selector.IsIn("window", "document"))
|
||||||
|
{
|
||||||
|
return $"DEL-{selector}-{eventName}";
|
||||||
|
}
|
||||||
|
return $"DEL-{_id}-{selector}-{eventName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddExclusive<T>(object dom, string eventName, Action<T> callback, bool preventDefault = false)
|
||||||
|
{
|
||||||
|
var key = FormatKey(dom, eventName);
|
||||||
|
if (_dotNetObjectStore.ContainsKey(key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var dotNetObject = DotNetObjectReference.Create(new Invoker<T>((p) =>
|
||||||
|
{
|
||||||
|
callback(p);
|
||||||
|
}));
|
||||||
|
_jsRuntime.InvokeAsync<string>(JSInteropConstants.AddDomEventListener, dom, eventName, preventDefault, dotNetObject);
|
||||||
|
_dotNetObjectStore.Add(key, dotNetObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveExclusive(object dom, string eventName)
|
||||||
|
{
|
||||||
|
var key = FormatKey(dom, eventName);
|
||||||
|
if (_dotNetObjectStore.TryGetValue(key, out IDisposable value))
|
||||||
|
{
|
||||||
|
value.Dispose();
|
||||||
|
}
|
||||||
|
_dotNetObjectStore.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisposeExclusive()
|
||||||
|
{
|
||||||
|
foreach (var (k, v) in _dotNetObjectStore)
|
||||||
|
{
|
||||||
|
v.Dispose();
|
||||||
|
}
|
||||||
|
_dotNetObjectStore.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region SharedEventListerner
|
||||||
|
|
||||||
|
public virtual void AddShared<T>(object dom, string eventName, Action<T> callback, bool preventDefault = false)
|
||||||
|
{
|
||||||
|
string key = FormatKey(dom, eventName);
|
||||||
|
if (!_domEventSubscriptionsStore.ContainsKey(key))
|
||||||
|
{
|
||||||
|
_domEventSubscriptionsStore[key] = new List<DomEventSubscription>();
|
||||||
|
|
||||||
|
var dotNetObject = DotNetObjectReference.Create(new Invoker<string>((p) =>
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _domEventSubscriptionsStore[key].Count; i++)
|
||||||
|
{
|
||||||
|
var subscription = _domEventSubscriptionsStore[key][i];
|
||||||
|
object tP = JsonSerializer.Deserialize(p, subscription.Type);
|
||||||
|
subscription.Delegate.DynamicInvoke(tP);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
_jsRuntime.InvokeAsync<string>(JSInteropConstants.AddDomEventListener, dom, eventName, preventDefault, dotNetObject);
|
||||||
|
}
|
||||||
|
_domEventSubscriptionsStore[key].Add(new DomEventSubscription(callback, typeof(T), _id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveShared<T>(object dom, string eventName, Action<T> callback)
|
||||||
|
{
|
||||||
|
string key = FormatKey(dom, eventName);
|
||||||
|
if (_domEventSubscriptionsStore.ContainsKey(key))
|
||||||
|
{
|
||||||
|
var subscription = _domEventSubscriptionsStore[key].SingleOrDefault(s => s.Delegate == (Delegate)callback);
|
||||||
|
if (subscription != null && subscription.Id == _id)
|
||||||
|
{
|
||||||
|
_domEventSubscriptionsStore[key].Remove(subscription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisposeShared()
|
||||||
|
{
|
||||||
|
bool find = true;
|
||||||
|
|
||||||
|
while (find)
|
||||||
|
{
|
||||||
|
var (key, subscription) = _domEventSubscriptionsStore.FindDomEventSubscription(_id);
|
||||||
|
if (!string.IsNullOrEmpty(key) && subscription != null)
|
||||||
|
{
|
||||||
|
_domEventSubscriptionsStore[key].Remove(subscription);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
find = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ResizeObserver
|
||||||
|
public async ValueTask AddResizeObserver(ElementReference dom, Action<List<ResizeObserverEntry>> callback)
|
||||||
|
{
|
||||||
|
string key = FormatKey(dom.Id, nameof(JSInteropConstants.ObserverConstants.Resize));
|
||||||
|
if (!(await IsResizeObserverSupported()))
|
||||||
|
{
|
||||||
|
Action<JsonElement> action = (je) => callback.Invoke(new List<ResizeObserverEntry> { new ResizeObserverEntry() });
|
||||||
|
AddShared<JsonElement>("window", "resize", action, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_domEventSubscriptionsStore.ContainsKey(key))
|
||||||
|
{
|
||||||
|
_domEventSubscriptionsStore[key] = new List<DomEventSubscription>();
|
||||||
|
await _jsRuntime.InvokeVoidAsync(JSInteropConstants.ObserverConstants.Resize.Create, key, DotNetObjectReference.Create(new Invoker<string>((p) =>
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _domEventSubscriptionsStore[key].Count; i++)
|
||||||
|
{
|
||||||
|
var subscription = _domEventSubscriptionsStore[key][i];
|
||||||
|
object tP = JsonSerializer.Deserialize(p, subscription.Type);
|
||||||
|
subscription.Delegate.DynamicInvoke(tP);
|
||||||
|
}
|
||||||
|
})));
|
||||||
|
await _jsRuntime.InvokeVoidAsync(JSInteropConstants.ObserverConstants.Resize.Observe, key, dom);
|
||||||
|
}
|
||||||
|
_domEventSubscriptionsStore[key].Add(new DomEventSubscription(callback, typeof(List<ResizeObserverEntry>), _id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask RemoveResizeObserver(ElementReference dom, Action<List<ResizeObserverEntry>> callback)
|
||||||
|
{
|
||||||
|
string key = FormatKey(dom.Id, nameof(JSInteropConstants.ObserverConstants.Resize));
|
||||||
|
if (_domEventSubscriptionsStore.ContainsKey(key))
|
||||||
|
{
|
||||||
|
var subscription = _domEventSubscriptionsStore[key].SingleOrDefault(s => s.Delegate == (Delegate)callback);
|
||||||
|
if (subscription != null)
|
||||||
|
{
|
||||||
|
_domEventSubscriptionsStore[key].Remove(subscription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeResizeObserver(ElementReference dom)
|
||||||
|
{
|
||||||
|
string key = FormatKey(dom.Id, nameof(JSInteropConstants.ObserverConstants.Resize));
|
||||||
|
if (await IsResizeObserverSupported())
|
||||||
|
{
|
||||||
|
await _jsRuntime.InvokeVoidAsync(JSInteropConstants.ObserverConstants.Resize.Dispose, key);
|
||||||
|
}
|
||||||
|
_domEventSubscriptionsStore.TryRemove(key, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisconnectResizeObserver(ElementReference dom)
|
||||||
|
{
|
||||||
|
string key = FormatKey(dom.Id, nameof(JSInteropConstants.ObserverConstants.Resize));
|
||||||
|
if (await IsResizeObserverSupported())
|
||||||
|
{
|
||||||
|
await _jsRuntime.InvokeVoidAsync(JSInteropConstants.ObserverConstants.Resize.Disconnect, key);
|
||||||
|
}
|
||||||
|
if (_domEventSubscriptionsStore.ContainsKey(key))
|
||||||
|
{
|
||||||
|
_domEventSubscriptionsStore[key].Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask<bool> IsResizeObserverSupported() => _isResizeObserverSupported ??= await _jsRuntime.IsResizeObserverSupported();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region EventListenerToFirstChild
|
||||||
|
|
||||||
|
public void AddEventListenerToFirstChild(object dom, string eventName, Action<JsonElement> callback, bool preventDefault = false)
|
||||||
|
{
|
||||||
|
AddEventListenerToFirstChildInternal<string>(dom, eventName, preventDefault, (e) =>
|
||||||
|
{
|
||||||
|
JsonElement jsonElement = JsonDocument.Parse(e).RootElement;
|
||||||
|
callback(jsonElement);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddEventListenerToFirstChild<T>(object dom, string eventName, Action<T> callback, bool preventDefault = false)
|
||||||
|
{
|
||||||
|
AddEventListenerToFirstChildInternal<string>(dom, eventName, preventDefault, (e) =>
|
||||||
|
{
|
||||||
|
T obj = JsonSerializer.Deserialize<T>(e);
|
||||||
|
callback(obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddEventListenerToFirstChildInternal<T>(object dom, string eventName, bool preventDefault, Action<T> callback)
|
||||||
|
{
|
||||||
|
var key = FormatKey(dom, eventName);
|
||||||
|
if (!_dotNetObjectStore.ContainsKey(key))
|
||||||
|
{
|
||||||
|
var dotNetObject = DotNetObjectReference.Create(new Invoker<T>((p) =>
|
||||||
|
{
|
||||||
|
callback?.Invoke(p);
|
||||||
|
}));
|
||||||
|
|
||||||
|
_jsRuntime.InvokeAsync<string>(JSInteropConstants.AddDomEventListenerToFirstChild, dom, eventName, preventDefault, dotNetObject);
|
||||||
|
_dotNetObjectStore.Add(key, dotNetObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
DisposeExclusive();
|
||||||
|
DisposeShared();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Invoker<T>
|
||||||
|
{
|
||||||
|
private Action<T> _action;
|
||||||
|
|
||||||
|
public Invoker(Action<T> invoker)
|
||||||
|
{
|
||||||
|
_action = invoker;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JSInvokable]
|
||||||
|
public void Invoke(T param)
|
||||||
|
{
|
||||||
|
_action.Invoke(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,187 +1,21 @@
|
|||||||
using System;
|
using Microsoft.JSInterop;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AntDesign.Core.Extensions;
|
|
||||||
using AntDesign.Core.JsInterop.ObservableApi;
|
|
||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
using Microsoft.JSInterop;
|
|
||||||
|
|
||||||
namespace AntDesign.JsInterop
|
namespace AntDesign.JsInterop
|
||||||
{
|
{
|
||||||
public class DomEventService
|
public class DomEventService
|
||||||
{
|
{
|
||||||
private ConcurrentDictionary<string, List<DomEventSubscription>> _domEventListeners = new ConcurrentDictionary<string, List<DomEventSubscription>>();
|
private DomEventSubscriptionStore _domEventSubscriptionStore = new();
|
||||||
|
|
||||||
private readonly IJSRuntime _jsRuntime;
|
private readonly IJSRuntime _jsRuntime;
|
||||||
private bool? _isResizeObserverSupported = null;
|
|
||||||
|
|
||||||
public DomEventService(IJSRuntime jsRuntime)
|
public DomEventService(IJSRuntime jsRuntime)
|
||||||
{
|
{
|
||||||
_jsRuntime = jsRuntime;
|
_jsRuntime = jsRuntime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddEventListenerToFirstChildInternal<T>(object dom, string eventName, bool preventDefault, Action<T> callback)
|
public virtual IDomEventListener CreateDomEventListerner()
|
||||||
{
|
{
|
||||||
if (!_domEventListeners.ContainsKey(FormatKey(dom, eventName)))
|
return new DomEventListener(_jsRuntime, _domEventSubscriptionStore);
|
||||||
{
|
|
||||||
_jsRuntime.InvokeAsync<string>(JSInteropConstants.AddDomEventListenerToFirstChild, dom, eventName, preventDefault, DotNetObjectReference.Create(new Invoker<T>((p) =>
|
|
||||||
{
|
|
||||||
callback?.Invoke(p);
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEventListener(object dom, string eventName, Action<JsonElement> callback, bool exclusive = true, bool preventDefault = false)
|
|
||||||
{
|
|
||||||
AddEventListener<JsonElement>(dom, eventName, callback, exclusive, preventDefault);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void AddEventListener<T>(object dom, string eventName, Action<T> callback, bool exclusive = true, bool preventDefault = false)
|
|
||||||
{
|
|
||||||
if (exclusive)
|
|
||||||
{
|
|
||||||
_jsRuntime.InvokeAsync<string>(JSInteropConstants.AddDomEventListener, dom, eventName, preventDefault, DotNetObjectReference.Create(new Invoker<T>((p) =>
|
|
||||||
{
|
|
||||||
callback(p);
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string key = FormatKey(dom, eventName);
|
|
||||||
if (!_domEventListeners.ContainsKey(key))
|
|
||||||
{
|
|
||||||
_domEventListeners[key] = new List<DomEventSubscription>();
|
|
||||||
|
|
||||||
_jsRuntime.InvokeAsync<string>(JSInteropConstants.AddDomEventListener, dom, eventName, preventDefault, DotNetObjectReference.Create(new Invoker<string>((p) =>
|
|
||||||
{
|
|
||||||
for (var i = 0; i < _domEventListeners[key].Count; i++)
|
|
||||||
{
|
|
||||||
var subscription = _domEventListeners[key][i];
|
|
||||||
object tP = JsonSerializer.Deserialize(p, subscription.Type);
|
|
||||||
subscription.Delegate.DynamicInvoke(tP);
|
|
||||||
}
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
_domEventListeners[key].Add(new DomEventSubscription(callback, typeof(T)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEventListenerToFirstChild(object dom, string eventName, Action<JsonElement> callback, bool preventDefault = false)
|
|
||||||
{
|
|
||||||
AddEventListenerToFirstChildInternal<string>(dom, eventName, preventDefault, (e) =>
|
|
||||||
{
|
|
||||||
JsonElement jsonElement = JsonDocument.Parse(e).RootElement;
|
|
||||||
callback(jsonElement);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEventListenerToFirstChild<T>(object dom, string eventName, Action<T> callback, bool preventDefault = false)
|
|
||||||
{
|
|
||||||
AddEventListenerToFirstChildInternal<string>(dom, eventName, preventDefault, (e) =>
|
|
||||||
{
|
|
||||||
T obj = JsonSerializer.Deserialize<T>(e);
|
|
||||||
callback(obj);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask AddResizeObserver(ElementReference dom, Action<List<ResizeObserverEntry>> callback)
|
|
||||||
{
|
|
||||||
string key = FormatKey(dom.Id, nameof(JSInteropConstants.ObserverConstants.Resize));
|
|
||||||
if (!(await IsResizeObserverSupported()))
|
|
||||||
{
|
|
||||||
Action<JsonElement> action = (je) => callback.Invoke(new List<ResizeObserverEntry> { new ResizeObserverEntry() });
|
|
||||||
AddEventListener("window", "resize", action, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!_domEventListeners.ContainsKey(key))
|
|
||||||
{
|
|
||||||
_domEventListeners[key] = new List<DomEventSubscription>();
|
|
||||||
await _jsRuntime.InvokeVoidAsync(JSInteropConstants.ObserverConstants.Resize.Create, key, DotNetObjectReference.Create(new Invoker<string>((p) =>
|
|
||||||
{
|
|
||||||
for (var i = 0; i < _domEventListeners[key].Count; i++)
|
|
||||||
{
|
|
||||||
var subscription = _domEventListeners[key][i];
|
|
||||||
object tP = JsonSerializer.Deserialize(p, subscription.Type);
|
|
||||||
subscription.Delegate.DynamicInvoke(tP);
|
|
||||||
}
|
|
||||||
})));
|
|
||||||
await _jsRuntime.InvokeVoidAsync(JSInteropConstants.ObserverConstants.Resize.Observe, key, dom);
|
|
||||||
}
|
|
||||||
_domEventListeners[key].Add(new DomEventSubscription(callback, typeof(List<ResizeObserverEntry>)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask RemoveResizeObserver(ElementReference dom, Action<List<ResizeObserverEntry>> callback)
|
|
||||||
{
|
|
||||||
string key = FormatKey(dom.Id, nameof(JSInteropConstants.ObserverConstants.Resize));
|
|
||||||
if (_domEventListeners.ContainsKey(key))
|
|
||||||
{
|
|
||||||
var subscription = _domEventListeners[key].SingleOrDefault(s => s.Delegate == (Delegate)callback);
|
|
||||||
if (subscription != null)
|
|
||||||
{
|
|
||||||
_domEventListeners[key].Remove(subscription);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask DisposeResizeObserver(ElementReference dom)
|
|
||||||
{
|
|
||||||
string key = FormatKey(dom.Id, nameof(JSInteropConstants.ObserverConstants.Resize));
|
|
||||||
if (await IsResizeObserverSupported())
|
|
||||||
{
|
|
||||||
await _jsRuntime.InvokeVoidAsync(JSInteropConstants.ObserverConstants.Resize.Dispose, key);
|
|
||||||
}
|
|
||||||
_domEventListeners.TryRemove(key, out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask DisconnectResizeObserver(ElementReference dom)
|
|
||||||
{
|
|
||||||
string key = FormatKey(dom.Id, nameof(JSInteropConstants.ObserverConstants.Resize));
|
|
||||||
if (await IsResizeObserverSupported())
|
|
||||||
{
|
|
||||||
await _jsRuntime.InvokeVoidAsync(JSInteropConstants.ObserverConstants.Resize.Disconnect, key);
|
|
||||||
}
|
|
||||||
if (_domEventListeners.ContainsKey(key))
|
|
||||||
{
|
|
||||||
_domEventListeners[key].Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string FormatKey(object dom, string eventName) => $"{dom}-{eventName}";
|
|
||||||
|
|
||||||
public void RemoveEventListerner<T>(object dom, string eventName, Action<T> callback)
|
|
||||||
{
|
|
||||||
string key = FormatKey(dom, eventName);
|
|
||||||
if (_domEventListeners.ContainsKey(key))
|
|
||||||
{
|
|
||||||
var subscription = _domEventListeners[key].SingleOrDefault(s => s.Delegate == (Delegate)callback);
|
|
||||||
if (subscription != null)
|
|
||||||
{
|
|
||||||
_domEventListeners[key].Remove(subscription);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async ValueTask<bool> IsResizeObserverSupported() => _isResizeObserverSupported ??= await _jsRuntime.IsResizeObserverSupported();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Invoker<T>
|
|
||||||
{
|
|
||||||
private Action<T> _action;
|
|
||||||
|
|
||||||
public Invoker(Action<T> invoker)
|
|
||||||
{
|
|
||||||
this._action = invoker;
|
|
||||||
}
|
|
||||||
|
|
||||||
[JSInvokable]
|
|
||||||
public void Invoke(T param)
|
|
||||||
{
|
|
||||||
_action.Invoke(param);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,47 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace AntDesign.JsInterop
|
namespace AntDesign.JsInterop
|
||||||
{
|
{
|
||||||
internal class DomEventSubscription
|
public class DomEventSubscriptionStore : ConcurrentDictionary<string, List<DomEventSubscription>>
|
||||||
|
{
|
||||||
|
public (string key, DomEventSubscription subscription) FindDomEventSubscription(string id)
|
||||||
|
{
|
||||||
|
string key = string.Empty;
|
||||||
|
DomEventSubscription subscription = null;
|
||||||
|
|
||||||
|
foreach (var (k, subscriptionList) in this)
|
||||||
|
{
|
||||||
|
key = k;
|
||||||
|
|
||||||
|
foreach (var item in subscriptionList)
|
||||||
|
{
|
||||||
|
if (item.Id == id)
|
||||||
|
{
|
||||||
|
subscription = item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subscription != null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (key, subscription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DomEventSubscription
|
||||||
{
|
{
|
||||||
internal Delegate Delegate { get; set; }
|
internal Delegate Delegate { get; set; }
|
||||||
internal Type Type { get; set; }
|
internal Type Type { get; set; }
|
||||||
|
internal string Id { get; set; }
|
||||||
|
|
||||||
public DomEventSubscription(Delegate @delegate, Type type)
|
public DomEventSubscription(Delegate @delegate, Type type, string id)
|
||||||
{
|
{
|
||||||
Delegate = @delegate;
|
Delegate = @delegate;
|
||||||
Type = type;
|
Type = type;
|
||||||
|
Id = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
components/core/JsInterop/IDomEventListener.cs
Normal file
26
components/core/JsInterop/IDomEventListener.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AntDesign.Core.JsInterop.ObservableApi;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace AntDesign.JsInterop
|
||||||
|
{
|
||||||
|
public interface IDomEventListener
|
||||||
|
{
|
||||||
|
void AddEventListenerToFirstChild(object dom, string eventName, Action<JsonElement> callback, bool preventDefault = false);
|
||||||
|
void AddEventListenerToFirstChild<T>(object dom, string eventName, Action<T> callback, bool preventDefault = false);
|
||||||
|
void AddExclusive<T>(object dom, string eventName, Action<T> callback, bool preventDefault = false);
|
||||||
|
ValueTask AddResizeObserver(ElementReference dom, Action<List<ResizeObserverEntry>> callback);
|
||||||
|
void AddShared<T>(object dom, string eventName, Action<T> callback, bool preventDefault = false);
|
||||||
|
ValueTask DisconnectResizeObserver(ElementReference dom);
|
||||||
|
void DisposeExclusive();
|
||||||
|
ValueTask DisposeResizeObserver(ElementReference dom);
|
||||||
|
void RemoveExclusive(object dom, string eventName);
|
||||||
|
ValueTask RemoveResizeObserver(ElementReference dom, Action<List<ResizeObserverEntry>> callback);
|
||||||
|
void RemoveShared<T>(object dom, string eventName, Action<T> callback);
|
||||||
|
void DisposeShared();
|
||||||
|
void Dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,8 @@ namespace AntDesign
|
|||||||
public static string GetScroll => DomInfoHelper.GetScroll;
|
public static string GetScroll => DomInfoHelper.GetScroll;
|
||||||
public static string HasFocus => DomInfoHelper.HasFocus;
|
public static string HasFocus => DomInfoHelper.HasFocus;
|
||||||
public static string GetInnerText => DomInfoHelper.GetInnerText;
|
public static string GetInnerText => DomInfoHelper.GetInnerText;
|
||||||
|
public static string GetMaxZIndex => DomInfoHelper.GetMaxZIndex;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region styleManipulation
|
#region styleManipulation
|
||||||
@ -87,12 +89,12 @@ namespace AntDesign
|
|||||||
#region overlay
|
#region overlay
|
||||||
public static string AddPreventEnterOnOverlayVisible => OverlayComponentHelper.AddPreventEnterOnOverlayVisible;
|
public static string AddPreventEnterOnOverlayVisible => OverlayComponentHelper.AddPreventEnterOnOverlayVisible;
|
||||||
public static string RemovePreventEnterOnOverlayVisible => OverlayComponentHelper.RemovePreventEnterOnOverlayVisible;
|
public static string RemovePreventEnterOnOverlayVisible => OverlayComponentHelper.RemovePreventEnterOnOverlayVisible;
|
||||||
public static string GetMaxZIndex => OverlayComponentHelper.GetMaxZIndex;
|
//public static string AddOverlayToContainer => OverlayComponentHelper.AddOverlayToContainer;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region table
|
#region table
|
||||||
public static string BindTableHeaderAndBodyScroll => TableComponentHelper.BindTableHeaderAndBodyScroll;
|
public static string BindTableScroll => TableComponentHelper.BindTableScroll;
|
||||||
public static string UnbindTableHeaderAndBodyScroll => TableComponentHelper.UnbindTableHeaderAndBodyScroll;
|
public static string UnbindTableScroll => TableComponentHelper.UnbindTableScroll;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public static string DisposeObj => $"{FUNC_PREFIX}state.disposeObj";
|
public static string DisposeObj => $"{FUNC_PREFIX}state.disposeObj";
|
||||||
@ -109,6 +111,7 @@ namespace AntDesign
|
|||||||
public static string GetScroll => $"{FUNC_PREFIX}getScroll";
|
public static string GetScroll => $"{FUNC_PREFIX}getScroll";
|
||||||
public static string HasFocus => $"{FUNC_PREFIX}hasFocus";
|
public static string HasFocus => $"{FUNC_PREFIX}hasFocus";
|
||||||
public static string GetInnerText => $"{FUNC_PREFIX}getInnerText";
|
public static string GetInnerText => $"{FUNC_PREFIX}getInnerText";
|
||||||
|
public static string GetMaxZIndex => $"{FUNC_PREFIX}getMaxZIndex";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EventHelper
|
public static class EventHelper
|
||||||
@ -184,6 +187,7 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
private const string FUNC_PREFIX = JSInteropConstants.FUNC_PREFIX + "inputHelper.";
|
private const string FUNC_PREFIX = JSInteropConstants.FUNC_PREFIX + "inputHelper.";
|
||||||
public static string RegisterResizeTextArea => $"{FUNC_PREFIX}registerResizeTextArea";
|
public static string RegisterResizeTextArea => $"{FUNC_PREFIX}registerResizeTextArea";
|
||||||
|
public static string GetTextAreaInfo => $"{FUNC_PREFIX}getTextAreaInfo";
|
||||||
public static string DisposeResizeTextArea => $"{FUNC_PREFIX}disposeResizeTextArea";
|
public static string DisposeResizeTextArea => $"{FUNC_PREFIX}disposeResizeTextArea";
|
||||||
public static string SetSelectionStart => $"{FUNC_PREFIX}setSelectionStart";
|
public static string SetSelectionStart => $"{FUNC_PREFIX}setSelectionStart";
|
||||||
}
|
}
|
||||||
@ -210,14 +214,16 @@ namespace AntDesign
|
|||||||
private const string FUNC_PREFIX = JSInteropConstants.FUNC_PREFIX + "overlayHelper.";
|
private const string FUNC_PREFIX = JSInteropConstants.FUNC_PREFIX + "overlayHelper.";
|
||||||
public static string AddPreventEnterOnOverlayVisible => $"{FUNC_PREFIX}addPreventEnterOnOverlayVisible";
|
public static string AddPreventEnterOnOverlayVisible => $"{FUNC_PREFIX}addPreventEnterOnOverlayVisible";
|
||||||
public static string RemovePreventEnterOnOverlayVisible => $"{FUNC_PREFIX}removePreventEnterOnOverlayVisible";
|
public static string RemovePreventEnterOnOverlayVisible => $"{FUNC_PREFIX}removePreventEnterOnOverlayVisible";
|
||||||
public static string GetMaxZIndex => $"{FUNC_PREFIX}getMaxZIndex";
|
public static string AddOverlayToContainer => $"{FUNC_PREFIX}addOverlayToContainer";
|
||||||
|
public static string UpdateOverlayPosition => $"{FUNC_PREFIX}updateOverlayPosition";
|
||||||
|
public static string DeleteOverlayFromContainer => $"{FUNC_PREFIX}deleteOverlayFromContainer";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TableComponentHelper
|
public static class TableComponentHelper
|
||||||
{
|
{
|
||||||
private const string FUNC_PREFIX = JSInteropConstants.FUNC_PREFIX + "tableHelper.";
|
private const string FUNC_PREFIX = JSInteropConstants.FUNC_PREFIX + "tableHelper.";
|
||||||
public static string BindTableHeaderAndBodyScroll => $"{FUNC_PREFIX}bindTableHeaderAndBodyScroll";
|
public static string BindTableScroll => $"{FUNC_PREFIX}bindTableScroll";
|
||||||
public static string UnbindTableHeaderAndBodyScroll => $"{FUNC_PREFIX}unbindTableHeaderAndBodyScroll";
|
public static string UnbindTableScroll => $"{FUNC_PREFIX}unbindTableScroll";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class UploadComponentHelper
|
public static class UploadComponentHelper
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
import { infoHelper as domInfoHelper } from '../modules/dom/infoHelper';
|
||||||
|
|
||||||
|
export class intersectionObserver {
|
||||||
|
// @ts-ignore: TS2304: Cannot find name 'IntersectionObserver'
|
||||||
|
private static intersectionObservers: Map<string, IntersectionObserver> = new Map<string, IntersectionObserver>();
|
||||||
|
|
||||||
|
|
||||||
|
static create(key: string, invoker, isDotNetInvoker: boolean = true) {
|
||||||
|
// @ts-ignore: TS2304: Cannot find name 'IntersectionObserver'
|
||||||
|
let observer;
|
||||||
|
|
||||||
|
if (isDotNetInvoker) {
|
||||||
|
observer = new IntersectionObserver(mutations => intersectionObserver.observerCallback(mutations, invoker))
|
||||||
|
} else {
|
||||||
|
observer = new IntersectionObserver(mutations => invoker(mutations))
|
||||||
|
}
|
||||||
|
intersectionObserver.intersectionObservers.set(key, observer)
|
||||||
|
}
|
||||||
|
|
||||||
|
static observe(key: string, element, options?: IntersectionObserverInit) {
|
||||||
|
const observer = intersectionObserver.intersectionObservers.get(key);
|
||||||
|
if (observer) {
|
||||||
|
let domElement = domInfoHelper.get(element);
|
||||||
|
observer.observe(domElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static disconnect(key: string): void {
|
||||||
|
const observer = this.intersectionObservers.get(key)
|
||||||
|
if (observer) {
|
||||||
|
observer.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static dispose(key: string): void {
|
||||||
|
this.disconnect(key)
|
||||||
|
this.intersectionObservers.delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static observerCallback(mutations, invoker) {
|
||||||
|
//TODO: serialize a proper object (check resizeObserver.ts for sample)
|
||||||
|
const entriesJson = JSON.stringify(mutations)
|
||||||
|
invoker.invokeMethodAsync('Invoke', entriesJson)
|
||||||
|
}
|
||||||
|
}
|
45
components/core/JsInterop/ObservableApi/mutationObserver.ts
Normal file
45
components/core/JsInterop/ObservableApi/mutationObserver.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { infoHelper as domInfoHelper } from '../modules/dom/infoHelper';
|
||||||
|
|
||||||
|
export class mutationObserver {
|
||||||
|
// @ts-ignore: TS2304: Cannot find name 'MutationObserver'
|
||||||
|
private static mutationObservers: Map<string, MutationObserver> = new Map<string, MutationObserver>();
|
||||||
|
|
||||||
|
|
||||||
|
static create(key: string, invoker, isDotNetInvoker: boolean = true) {
|
||||||
|
// @ts-ignore: TS2304: Cannot find name 'MutationObserver'
|
||||||
|
let observer;
|
||||||
|
|
||||||
|
if (isDotNetInvoker) {
|
||||||
|
observer = new MutationObserver(mutations => mutationObserver.observerCallback(mutations, invoker))
|
||||||
|
} else {
|
||||||
|
observer = new MutationObserver(mutations => invoker(mutations))
|
||||||
|
}
|
||||||
|
mutationObserver.mutationObservers.set(key, observer)
|
||||||
|
}
|
||||||
|
|
||||||
|
static observe(key: string, element, options?: MutationObserverInit) {
|
||||||
|
const observer = mutationObserver.mutationObservers.get(key);
|
||||||
|
if (observer) {
|
||||||
|
let domElement = domInfoHelper.get(element);
|
||||||
|
observer.observe(domElement, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static disconnect(key: string): void {
|
||||||
|
const observer = this.mutationObservers.get(key)
|
||||||
|
if (observer) {
|
||||||
|
observer.disconnect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static dispose(key: string): void {
|
||||||
|
this.disconnect(key)
|
||||||
|
this.mutationObservers.delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static observerCallback(mutations, invoker) {
|
||||||
|
//TODO: serialize a proper object (check resizeObserver.ts for sample)
|
||||||
|
const entriesJson = JSON.stringify(mutations)
|
||||||
|
invoker.invokeMethodAsync('Invoke', entriesJson)
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
export { resizeObserver as resize } from './resizeObserver';
|
export { resizeObserver as resize } from './resizeObserver';
|
||||||
|
export { mutationObserver } from './mutationObserver';
|
@ -17,9 +17,15 @@ export class resizeObserver {
|
|||||||
// @ts-ignore: TS2304: Cannot find name 'ResizeObserver'
|
// @ts-ignore: TS2304: Cannot find name 'ResizeObserver'
|
||||||
private static resizeObservers: Map<string, ResizeObserver> = new Map<string, ResizeObserver>();
|
private static resizeObservers: Map<string, ResizeObserver> = new Map<string, ResizeObserver>();
|
||||||
|
|
||||||
static create(key, invoker) {
|
static create(key, invoker, isDotNetInvoker: boolean = true ) {
|
||||||
// @ts-ignore: TS2304: Cannot find name 'ResizeObserver'
|
// @ts-ignore: TS2304: Cannot find name 'ResizeObserver'
|
||||||
const observer = new ResizeObserver((entries, observer) => resizeObserver.observerCallBack(entries, observer, invoker));
|
let observer;
|
||||||
|
|
||||||
|
if (isDotNetInvoker) {
|
||||||
|
observer = new ResizeObserver((entries, observer) => resizeObserver.observerCallBack(entries, observer, invoker));
|
||||||
|
} else {
|
||||||
|
observer = new ResizeObserver((entries, observer) => invoker(entries, observer));
|
||||||
|
}
|
||||||
resizeObserver.resizeObservers.set(key, observer)
|
resizeObserver.resizeObservers.set(key, observer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,17 +54,14 @@ export class resizeObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static dispose(key: string): void {
|
static dispose(key: string): void {
|
||||||
console.log("dispose", key);
|
|
||||||
this.disconnect(key)
|
this.disconnect(key)
|
||||||
this.resizeObservers.delete(key)
|
this.resizeObservers.delete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static observerCallBack(entries, observer, invoker) {
|
private static observerCallBack(entries, observer, invoker) {
|
||||||
console.log("observerCallBack start", entries)
|
|
||||||
if (invoker) {
|
if (invoker) {
|
||||||
const mappedEntries = new Array<ResizeObserverEntry>()
|
const mappedEntries = new Array<ResizeObserverEntry>()
|
||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
console.log("observerCallBack entry", entry)
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
const mEntry = new ResizeObserverEntry()
|
const mEntry = new ResizeObserverEntry()
|
||||||
if (entry.borderBoxSize) {
|
if (entry.borderBoxSize) {
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace AntDesign.JsInterop
|
namespace AntDesign.JsInterop
|
||||||
{
|
{
|
||||||
public class Window
|
public class Window
|
||||||
{
|
{
|
||||||
public decimal innerHeight { get; set; }
|
[JsonPropertyName("innerWidth")]
|
||||||
|
public decimal InnerWidth { get; set; }
|
||||||
|
|
||||||
public decimal innerWidth { get; set; }
|
[JsonPropertyName("innerHeight")]
|
||||||
|
public decimal InnerHeight { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
namespace AntDesign.Core.JsInterop.Modules.Components
|
||||||
|
{
|
||||||
|
public class OverlayPosition
|
||||||
|
{
|
||||||
|
public decimal? Top { get; set; }
|
||||||
|
public string TopCss => $"top: " + GetAsString(Top);
|
||||||
|
public decimal? Bottom { get; set; }
|
||||||
|
public string BottomCss => $"bottom: " + GetAsString(Bottom);
|
||||||
|
public decimal? Left { get; set; }
|
||||||
|
public string LeftCss => $"left: " + GetAsString(Left);
|
||||||
|
public decimal? Right { get; set; }
|
||||||
|
public string RightCss => $"right: " + GetAsString(Right);
|
||||||
|
public string PositionCss => ZIndexCss + LeftCss + RightCss + TopCss + BottomCss;
|
||||||
|
|
||||||
|
public int ZIndex { get; set; }
|
||||||
|
public string ZIndexCss => $"z-index:{ZIndex};";
|
||||||
|
|
||||||
|
public Placement Placement { get; set; }
|
||||||
|
|
||||||
|
private string GetAsString(decimal? value)
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
return "unset;";
|
||||||
|
else
|
||||||
|
return value.ToString() + "px;";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
import { domInfoHelper, eventHelper } from '../dom/exports'
|
import { domInfoHelper } from '../dom/exports'
|
||||||
import { state } from '../stateProvider';
|
import { state } from '../stateProvider';
|
||||||
|
|
||||||
|
|
||||||
export class inputHelper {
|
export class inputHelper {
|
||||||
|
|
||||||
private static getTextAreaInfo(element) {
|
static getTextAreaInfo(element) {
|
||||||
var result = {};
|
var result = {};
|
||||||
var dom = domInfoHelper.get(element);
|
var dom = domInfoHelper.get(element);
|
||||||
if (!dom) return null;
|
if (!dom) return null;
|
||||||
@ -32,7 +32,7 @@ export class inputHelper {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static registerResizeTextArea(element, minRows, maxRows, objReference) {
|
static registerResizeTextArea(element: HTMLTextAreaElement, minRows: number, maxRows: number, objReference) {
|
||||||
if (!objReference) {
|
if (!objReference) {
|
||||||
this.disposeResizeTextArea(element);
|
this.disposeResizeTextArea(element);
|
||||||
}
|
}
|
||||||
@ -44,22 +44,25 @@ export class inputHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static disposeResizeTextArea(element) {
|
static disposeResizeTextArea(element: HTMLTextAreaElement) {
|
||||||
element.removeEventListener("input", state.eventCallbackRegistry[element.id + "input"]);
|
element.removeEventListener("input", state.eventCallbackRegistry[element.id + "input"]);
|
||||||
state.objReferenceDict[element.id] = null;
|
state.objReferenceDict[element.id] = null;
|
||||||
state.eventCallbackRegistry[element.id + "input"] = null;
|
state.eventCallbackRegistry[element.id + "input"] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static resizeTextArea(element, minRows, maxRows) {
|
static resizeTextArea(element: HTMLTextAreaElement, minRows: number, maxRows: number) {
|
||||||
var dims = this.getTextAreaInfo(element);
|
let dims = this.getTextAreaInfo(element);
|
||||||
var rowHeight = dims["lineHeight"];
|
let rowHeight = dims["lineHeight"];
|
||||||
var offsetHeight = dims["paddingTop"] + dims["paddingBottom"] + dims["borderTop"] + dims["borderBottom"];
|
let offsetHeight = dims["paddingTop"] + dims["paddingBottom"] + dims["borderTop"] + dims["borderBottom"];
|
||||||
var oldHeight = parseFloat(element.style.height);
|
let oldHeight = parseFloat(element.style.height);
|
||||||
|
//use rows attribute to evaluate real scroll height
|
||||||
|
let oldRows = element.rows;
|
||||||
|
element.rows = minRows;
|
||||||
element.style.height = 'auto';
|
element.style.height = 'auto';
|
||||||
|
|
||||||
var rows = Math.trunc(element.scrollHeight / rowHeight);
|
var rows = Math.trunc(element.scrollHeight / rowHeight);
|
||||||
|
element.rows = oldRows;
|
||||||
rows = Math.max(minRows, rows);
|
rows = Math.max(minRows, rows);
|
||||||
|
|
||||||
var newHeight = 0;
|
var newHeight = 0;
|
||||||
if (rows > maxRows) {
|
if (rows > maxRows) {
|
||||||
rows = maxRows;
|
rows = maxRows;
|
||||||
@ -75,7 +78,7 @@ export class inputHelper {
|
|||||||
}
|
}
|
||||||
if (oldHeight !== newHeight) {
|
if (oldHeight !== newHeight) {
|
||||||
let textAreaObj = state.objReferenceDict[element.id];
|
let textAreaObj = state.objReferenceDict[element.id];
|
||||||
textAreaObj.invokeMethodAsync("ChangeSizeAsyncJs", parseFloat(element.scrollWidth), newHeight);
|
textAreaObj.invokeMethodAsync("ChangeSizeAsyncJs", element.scrollWidth, newHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1119
components/core/JsInterop/modules/components/overlay.ts
Normal file
1119
components/core/JsInterop/modules/components/overlay.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,77 @@
|
|||||||
import { domInfoHelper, eventHelper } from '../dom/exports'
|
import { domInfoHelper, eventHelper, domManipulationHelper, domTypes } from '../dom/exports'
|
||||||
|
import { Placement, TriggerBoundyAdjustMode, overlayConstraints, overlayPosition, Overlay } from './overlay'
|
||||||
import { state } from '../stateProvider';
|
import { state } from '../stateProvider';
|
||||||
|
|
||||||
export class overlayHelper {
|
export class overlayHelper {
|
||||||
|
static overlayRegistry: { [key: string]: Overlay} = {};
|
||||||
|
|
||||||
|
static addOverlayToContainer(blazorId: string,
|
||||||
|
overlaySelector, triggerSelector, placement: Placement, containerSelector: string,
|
||||||
|
triggerBoundyAdjustMode: TriggerBoundyAdjustMode, triggerIsWrappedInDiv: boolean, triggerPrefixCls: string,
|
||||||
|
verticalOffset: number, horizontalOffset: number, arrowPointAtCenter: boolean,
|
||||||
|
overlayTop?: number, overlayLeft?: number
|
||||||
|
): overlayPosition {
|
||||||
|
const overlayElement = domInfoHelper.get(overlaySelector) as HTMLDivElement;
|
||||||
|
const containerElement = domInfoHelper.get(containerSelector) as HTMLElement;
|
||||||
|
const triggerElement = domInfoHelper.get(triggerSelector) as HTMLElement;
|
||||||
|
|
||||||
|
if (!domManipulationHelper.addElementTo(overlaySelector, containerElement)) {
|
||||||
|
console.log("Failed to add overlay. Details:", {
|
||||||
|
triggerPrefixCls: triggerPrefixCls,
|
||||||
|
overlaySelector: overlaySelector,
|
||||||
|
containerElement: containerElement
|
||||||
|
} );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let overlayPresets: domTypes.position;
|
||||||
|
if (overlayTop || overlayLeft) {
|
||||||
|
overlayPresets = { x: overlayLeft, y: overlayTop };
|
||||||
|
}
|
||||||
|
|
||||||
|
let overlayConstraints: overlayConstraints = {
|
||||||
|
verticalOffset: verticalOffset,
|
||||||
|
horizontalOffset: horizontalOffset,
|
||||||
|
arrowPointAtCenter: arrowPointAtCenter
|
||||||
|
};
|
||||||
|
|
||||||
|
let overlay = new Overlay(blazorId, overlayElement, containerElement, triggerElement, placement, triggerBoundyAdjustMode, triggerIsWrappedInDiv, triggerPrefixCls, overlayConstraints);
|
||||||
|
//register object in store, so it can be retrieved during update/dispose
|
||||||
|
this.overlayRegistry[blazorId] = overlay;
|
||||||
|
|
||||||
|
return overlay.calculatePosition(false, true, overlayPresets);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static updateOverlayPosition(blazorId: string, overlaySelector, triggerSelector, placement: Placement, containerSelector: string,
|
||||||
|
triggerBoundyAdjustMode: TriggerBoundyAdjustMode, triggerIsWrappedInDiv: boolean, triggerPrefixCls: string,
|
||||||
|
verticalOffset: number, horizontalOffset: number, arrowPointAtCenter: boolean,
|
||||||
|
overlayTop?: number, overlayLeft?: number): overlayPosition {
|
||||||
|
const overlay = this.overlayRegistry[blazorId];
|
||||||
|
if (overlay){
|
||||||
|
let overlayPresets: domTypes.position;
|
||||||
|
if (overlayTop || overlayLeft) {
|
||||||
|
overlayPresets = { x: overlayLeft, y: overlayTop };
|
||||||
|
}
|
||||||
|
return overlay.calculatePosition(false, false, overlayPresets);
|
||||||
|
} else {
|
||||||
|
//When page is slow, it may happen that rendering of an overlay may not happen, even if
|
||||||
|
//blazor thinks it did happen. In such a case, when overlay object is not found, just try
|
||||||
|
//to render it again.
|
||||||
|
return overlayHelper.addOverlayToContainer(blazorId, overlaySelector, triggerSelector, placement, containerSelector,triggerBoundyAdjustMode, triggerIsWrappedInDiv, triggerPrefixCls,
|
||||||
|
verticalOffset, horizontalOffset, arrowPointAtCenter,
|
||||||
|
overlayTop, overlayLeft);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteOverlayFromContainer(blazorId: string) {
|
||||||
|
const overlay = this.overlayRegistry[blazorId];
|
||||||
|
if (overlay) {
|
||||||
|
overlay.dispose();
|
||||||
|
delete this.overlayRegistry[blazorId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static addPreventEnterOnOverlayVisible(element, overlayElement) {
|
static addPreventEnterOnOverlayVisible(element, overlayElement) {
|
||||||
if (element && overlayElement) {
|
if (element && overlayElement) {
|
||||||
let dom: HTMLElement = domInfoHelper.get(element);
|
let dom: HTMLElement = domInfoHelper.get(element);
|
||||||
@ -21,8 +91,5 @@ export class overlayHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getMaxZIndex() {
|
|
||||||
return [...document.all].reduce((r, e) => Math.max(r, +window.getComputedStyle(e).zIndex || 0), 0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,52 @@
|
|||||||
export class tableHelper {
|
export class tableHelper {
|
||||||
static bindTableHeaderAndBodyScroll(bodyRef, headerRef) {
|
static bindTableScroll(bodyRef, tableRef, headerRef, scrollX, scrollY) {
|
||||||
bodyRef.bindScrollLeftToHeader = () => {
|
bodyRef.bindScroll = () => {
|
||||||
headerRef.scrollLeft = bodyRef.scrollLeft;
|
if (scrollX) {
|
||||||
|
tableHelper.SetScrollPositionClassName(bodyRef, tableRef);
|
||||||
|
}
|
||||||
|
if (scrollY) {
|
||||||
|
headerRef.scrollLeft = bodyRef.scrollLeft;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bodyRef.addEventListener('scroll', bodyRef.bindScrollLeftToHeader);
|
bodyRef.bindScroll();
|
||||||
|
bodyRef.addEventListener('scroll', bodyRef.bindScroll);
|
||||||
|
window.addEventListener('resize', bodyRef.bindScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unbindTableHeaderAndBodyScroll(bodyRef) {
|
static unbindTableScroll(bodyRef) {
|
||||||
if (bodyRef) {
|
if (bodyRef) {
|
||||||
bodyRef.removeEventListener('scroll', bodyRef.bindScrollLeftToHeader);
|
bodyRef.removeEventListener('scroll', bodyRef.bindScroll);
|
||||||
|
window.removeEventListener('resize', bodyRef.bindScroll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SetScrollPositionClassName(bodyRef, tableRef) {
|
||||||
|
|
||||||
|
let scrollLeft = bodyRef.scrollLeft;
|
||||||
|
let scrollWidth = bodyRef.scrollWidth;
|
||||||
|
let clientWidth = bodyRef.clientWidth;
|
||||||
|
|
||||||
|
let pingLeft = false;
|
||||||
|
let pingRight = false;
|
||||||
|
|
||||||
|
if ((scrollWidth == clientWidth && scrollWidth != 0)) {
|
||||||
|
pingLeft = false;
|
||||||
|
pingRight = false;
|
||||||
|
}
|
||||||
|
else if (scrollLeft == 0) {
|
||||||
|
pingLeft = false;
|
||||||
|
pingRight = true;
|
||||||
|
}
|
||||||
|
else if (Math.abs(scrollWidth - (scrollLeft + clientWidth)) <= 1) {
|
||||||
|
pingRight = false;
|
||||||
|
pingLeft = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pingLeft = true;
|
||||||
|
pingRight = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pingLeft ? tableRef.classList.add("ant-table-ping-left") : tableRef.classList.remove("ant-table-ping-left");
|
||||||
|
pingRight ? tableRef.classList.add("ant-table-ping-right") : tableRef.classList.remove("ant-table-ping-right");
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,20 +5,20 @@ export class eventHelper {
|
|||||||
static triggerEvent(element: HTMLInputElement, eventType: string, eventName: string) {
|
static triggerEvent(element: HTMLInputElement, eventType: string, eventName: string) {
|
||||||
//TODO: replace with event constructors https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
|
//TODO: replace with event constructors https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
|
||||||
//Not used
|
//Not used
|
||||||
var evt = document.createEvent(eventType);
|
const evt = document.createEvent(eventType);
|
||||||
evt.initEvent(eventName);
|
evt.initEvent(eventName);
|
||||||
return element.dispatchEvent(evt);
|
return element.dispatchEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static addDomEventListener(element, eventName: string, preventDefault: boolean, invoker: any) {
|
static addDomEventListener(element, eventName: string, preventDefault: boolean, invoker: any) {
|
||||||
let callback = args => {
|
const callback = args => {
|
||||||
const obj = {};
|
const obj = {};
|
||||||
for (let k in args) {
|
for (let k in args) {
|
||||||
if (k !== 'originalTarget') { //firefox occasionally raises Permission Denied when this property is being stringified
|
if (k !== 'originalTarget') { //firefox occasionally raises Permission Denied when this property is being stringified
|
||||||
obj[k] = args[k];
|
obj[k] = args[k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let json = JSON.stringify(obj, (k, v) => {
|
const json = JSON.stringify(obj, (k, v) => {
|
||||||
if (v instanceof Node) return 'Node';
|
if (v instanceof Node) return 'Node';
|
||||||
if (v instanceof Window) return 'Window';
|
if (v instanceof Window) return 'Window';
|
||||||
return v;
|
return v;
|
||||||
@ -29,14 +29,14 @@ export class eventHelper {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (element == 'window') {
|
if (element === 'window') {
|
||||||
if (eventName == 'resize') {
|
if (eventName === 'resize') {
|
||||||
window.addEventListener(eventName, this.debounce(() => callback({ innerWidth: window.innerWidth, innerHeight: window.innerHeight }), 200, false));
|
window.addEventListener(eventName, this.debounce(() => callback({ innerWidth: window.innerWidth, innerHeight: window.innerHeight }), 200, false));
|
||||||
} else {
|
} else {
|
||||||
window.addEventListener(eventName, callback);
|
window.addEventListener(eventName, callback);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let dom = domInfoHelper.get(element);
|
const dom = domInfoHelper.get(element);
|
||||||
if (dom) {
|
if (dom) {
|
||||||
(dom as HTMLElement).addEventListener(eventName, callback);
|
(dom as HTMLElement).addEventListener(eventName, callback);
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ export class eventHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static addDomEventListenerToFirstChild(element, eventName, preventDefault, invoker) {
|
static addDomEventListenerToFirstChild(element, eventName, preventDefault, invoker) {
|
||||||
var dom = domInfoHelper.get(element);
|
const dom = domInfoHelper.get(element);
|
||||||
|
|
||||||
if (dom && dom.firstElementChild) {
|
if (dom && dom.firstElementChild) {
|
||||||
this.addDomEventListener(dom.firstElementChild, eventName, preventDefault, invoker);
|
this.addDomEventListener(dom.firstElementChild, eventName, preventDefault, invoker);
|
||||||
@ -53,7 +53,7 @@ export class eventHelper {
|
|||||||
|
|
||||||
static addPreventKeys(inputElement, keys: string[]) {
|
static addPreventKeys(inputElement, keys: string[]) {
|
||||||
if (inputElement) {
|
if (inputElement) {
|
||||||
let dom = domInfoHelper.get(inputElement);
|
const dom = domInfoHelper.get(inputElement);
|
||||||
keys = keys.map(function (x) { return x.toUpperCase(); })
|
keys = keys.map(function (x) { return x.toUpperCase(); })
|
||||||
state.eventCallbackRegistry[inputElement.id + "keydown"] = (e) => this.preventKeys(e, keys);
|
state.eventCallbackRegistry[inputElement.id + "keydown"] = (e) => this.preventKeys(e, keys);
|
||||||
(dom as HTMLElement).addEventListener("keydown", state.eventCallbackRegistry[inputElement.id + "keydown"], false);
|
(dom as HTMLElement).addEventListener("keydown", state.eventCallbackRegistry[inputElement.id + "keydown"], false);
|
||||||
@ -69,7 +69,7 @@ export class eventHelper {
|
|||||||
|
|
||||||
static removePreventKeys(inputElement) {
|
static removePreventKeys(inputElement) {
|
||||||
if (inputElement) {
|
if (inputElement) {
|
||||||
let dom = domInfoHelper.get(inputElement);
|
const dom = domInfoHelper.get(inputElement);
|
||||||
if (dom) {
|
if (dom) {
|
||||||
(dom as HTMLElement).removeEventListener("keydown", state.eventCallbackRegistry[inputElement.id + "keydown"]);
|
(dom as HTMLElement).removeEventListener("keydown", state.eventCallbackRegistry[inputElement.id + "keydown"]);
|
||||||
state.eventCallbackRegistry[inputElement.id + "keydown"] = null;
|
state.eventCallbackRegistry[inputElement.id + "keydown"] = null;
|
||||||
|
@ -47,7 +47,7 @@ export class infoHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getElementAbsolutePos(element: any): domTypes.position {
|
static getElementAbsolutePos(element: any): domTypes.position {
|
||||||
let res: domTypes.position = {
|
const res: domTypes.position = {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
};
|
};
|
||||||
@ -68,7 +68,7 @@ export class infoHelper {
|
|||||||
static getBoundingClientRect(element: any): domTypes.domRect {
|
static getBoundingClientRect(element: any): domTypes.domRect {
|
||||||
const domElement = this.get(element);
|
const domElement = this.get(element);
|
||||||
if (domElement && domElement.getBoundingClientRect) {
|
if (domElement && domElement.getBoundingClientRect) {
|
||||||
let rect = domElement.getBoundingClientRect();
|
const rect = domElement.getBoundingClientRect();
|
||||||
// Fixes #1468. This wrapping is necessary for old browsers. Remove this when one day we no longer support them.
|
// Fixes #1468. This wrapping is necessary for old browsers. Remove this when one day we no longer support them.
|
||||||
return {
|
return {
|
||||||
width: rect.width,
|
width: rect.width,
|
||||||
@ -107,13 +107,43 @@ export class infoHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static hasFocus(selector) {
|
static hasFocus(selector) {
|
||||||
let dom = this.get(selector);
|
const dom = this.get(selector);
|
||||||
return (document.activeElement === dom);
|
return (document.activeElement === dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getInnerText(element) {
|
static getInnerText(element) {
|
||||||
let dom = this.get(element);
|
const dom = this.get(element);
|
||||||
if (dom) return dom.innerText;
|
if (dom) return dom.innerText;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getMaxZIndex(): number {
|
||||||
|
return [...document.querySelectorAll("*")].reduce((r, e) => Math.max(r, +window.getComputedStyle(e).zIndex || 0), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
static isFixedPosition(element) {
|
||||||
|
let node = this.get(element);
|
||||||
|
while (node && node.nodeName.toLowerCase() !== 'body') {
|
||||||
|
if (window.getComputedStyle(node).getPropertyValue('position').toLowerCase() === 'fixed')
|
||||||
|
{ return true; }
|
||||||
|
node = node.parentNode;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static findAncestorWithZIndex(element: HTMLElement): number {
|
||||||
|
let node = this.get(element);
|
||||||
|
let zIndexAsString: string;
|
||||||
|
let zIndex: number;
|
||||||
|
while (node && node.nodeName.toLowerCase() !== 'body') {
|
||||||
|
zIndexAsString = window.getComputedStyle(node).zIndex;
|
||||||
|
zIndex = Number.parseInt(zIndexAsString);
|
||||||
|
if (!Number.isNaN(zIndex)) {
|
||||||
|
return zIndex;
|
||||||
|
}
|
||||||
|
node = node.parentNode;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -12,11 +12,17 @@ export class manipulationHelper {
|
|||||||
document.body.removeChild(element);
|
document.body.removeChild(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
static addElementTo(addElement, elementSelector) {
|
static addElementTo(addElement, elementSelector): boolean {
|
||||||
let parent = domInfoHelper.get(elementSelector);
|
let parent = domInfoHelper.get(elementSelector);
|
||||||
if (parent && addElement) {
|
if (parent && addElement) {
|
||||||
parent.appendChild(addElement);
|
if (parent instanceof Node && addElement instanceof Node) {
|
||||||
|
parent.appendChild(addElement);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
console.log("does not implement node", parent, addElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static delElementFrom(delElement, elementSelector) {
|
static delElementFrom(delElement, elementSelector) {
|
||||||
@ -95,6 +101,7 @@ export class manipulationHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static blur(selector) {
|
static blur(selector) {
|
||||||
let dom = domInfoHelper.get(selector);
|
let dom = domInfoHelper.get(selector);
|
||||||
if (dom) {
|
if (dom) {
|
||||||
@ -102,20 +109,21 @@ export class manipulationHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static scrollTo(selector: Element | string) {
|
static scrollTo(selector: Element | string, parentElement?: HTMLElement) {
|
||||||
let element = domInfoHelper.get(selector);
|
const element = domInfoHelper.get(selector);
|
||||||
|
if (parentElement && element && element instanceof HTMLElement) {
|
||||||
if (element && element instanceof HTMLElement) {
|
parentElement.scrollTop = element.offsetTop;
|
||||||
element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
|
} else if (element && element instanceof HTMLElement) {
|
||||||
|
element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static slideTo(targetPageY) {
|
static slideTo(targetPageY) {
|
||||||
var timer = setInterval(function () {
|
const timer = setInterval(function () {
|
||||||
var currentY = document.documentElement.scrollTop || document.body.scrollTop;
|
const currentY = document.documentElement.scrollTop || document.body.scrollTop;
|
||||||
var distance = targetPageY > currentY ? targetPageY - currentY : currentY - targetPageY;
|
const distance = targetPageY > currentY ? targetPageY - currentY : currentY - targetPageY;
|
||||||
var speed = Math.ceil(distance / 10);
|
const speed = Math.ceil(distance / 10);
|
||||||
if (currentY == targetPageY) {
|
if (currentY === targetPageY) {
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
} else {
|
} else {
|
||||||
window.scrollTo(0, targetPageY > currentY ? currentY + speed : currentY - speed);
|
window.scrollTo(0, targetPageY > currentY ? currentY + speed : currentY - speed);
|
||||||
|
@ -60,5 +60,4 @@ export class styleHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -7,12 +7,13 @@
|
|||||||
<OverlayTrigger @ref="@_dropDown"
|
<OverlayTrigger @ref="@_dropDown"
|
||||||
Visible="Open"
|
Visible="Open"
|
||||||
IsButton="@true"
|
IsButton="@true"
|
||||||
|
BoundaryAdjustMode="@BoundaryAdjustMode"
|
||||||
Disabled="IsDisabled(0)"
|
Disabled="IsDisabled(0)"
|
||||||
PopupContainerSelector="@PopupContainerSelector"
|
PopupContainerSelector="@PopupContainerSelector"
|
||||||
OnVisibleChange="OverlayVisibleChange"
|
OnVisibleChange="OverlayVisibleChange"
|
||||||
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"
|
||||||
Trigger="new TriggerType[] { TriggerType.Click }">
|
Trigger="new[] { Trigger.Click }">
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<div class="@(PrefixCls)-panel-container" @onclick="@PickerClicked">
|
<div class="@(PrefixCls)-panel-container" @onclick="@PickerClicked">
|
||||||
<div class="@_panelClassMapper.Class">
|
<div class="@_panelClassMapper.Class">
|
||||||
|
@ -9,11 +9,12 @@
|
|||||||
IsButton="@true"
|
IsButton="@true"
|
||||||
Disabled="IsDisabled()"
|
Disabled="IsDisabled()"
|
||||||
PopupContainerSelector="@PopupContainerSelector"
|
PopupContainerSelector="@PopupContainerSelector"
|
||||||
|
BoundaryAdjustMode="@BoundaryAdjustMode"
|
||||||
OnVisibleChange="OverlayVisibleChange"
|
OnVisibleChange="OverlayVisibleChange"
|
||||||
OverlayClassName="ant-picker-dropdown-range"
|
OverlayClassName="ant-picker-dropdown-range"
|
||||||
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"
|
||||||
Trigger="new TriggerType[] { TriggerType.Click }">
|
Trigger="new[] { Trigger.Click }">
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<div class="@(PrefixCls)-range-arrow" style="@_rangeArrowStyle" />
|
<div class="@(PrefixCls)-range-arrow" style="@_rangeArrowStyle" />
|
||||||
<div class="@(PrefixCls)-panel-container" @onclick="@PickerClicked">
|
<div class="@(PrefixCls)-panel-container" @onclick="@PickerClicked">
|
||||||
|
@ -70,6 +70,12 @@ namespace AntDesign
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public OneOf<bool, bool[]> Disabled { get; set; } = new bool[] { false, false };
|
public OneOf<bool, bool[]> Disabled { get; set; } = new bool[] { false, false };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overlay adjustment strategy (when for example browser resize is happening)
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public TriggerBoundaryAdjustMode BoundaryAdjustMode { get; set; } = TriggerBoundaryAdjustMode.InView;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Bordered { get; set; } = true;
|
public bool Bordered { get; set; } = true;
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ namespace AntDesign
|
|||||||
private List<List<(IDescriptionsItem item, int realSpan)>> _itemMatrix = new List<List<(IDescriptionsItem item, int realSpan)>>();
|
private List<List<(IDescriptionsItem item, int realSpan)>> _itemMatrix = new List<List<(IDescriptionsItem item, int realSpan)>>();
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
private int _realColumn;
|
private int _realColumn;
|
||||||
|
|
||||||
@ -84,7 +84,6 @@ namespace AntDesign
|
|||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
SetClassMap();
|
SetClassMap();
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +91,7 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
if (firstRender && Column.IsT1)
|
if (firstRender && Column.IsT1)
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener<object>("window", "resize", OnResize, false);
|
DomEventListener.AddShared<object>("window", "resize", OnResize);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnAfterRender(firstRender);
|
base.OnAfterRender(firstRender);
|
||||||
@ -100,9 +99,8 @@ namespace AntDesign
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
DomEventListener.Dispose();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
|
||||||
DomEventService.RemoveEventListerner<object>("window", "resize", OnResize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnResize(object o)
|
private async void OnResize(object o)
|
||||||
|
@ -1,55 +1,56 @@
|
|||||||
@namespace AntDesign
|
@namespace AntDesign
|
||||||
@inherits AntDomComponentBase
|
@inherits AntDomComponentBase
|
||||||
|
<CascadingValue Value="@($"#ant-drawer-wrap_{Id}")" Name="PopupContainerSelector">
|
||||||
|
<div class="@ClassMapper.Class" @ref="@Ref" style="@_drawerStyle @InnerZIndexStyle @Style" id="@Id">
|
||||||
|
@if (Mask)
|
||||||
|
{
|
||||||
|
<div class="ant-drawer-mask" @onclick="_=>MaskClick()" style="@MaskStyle"></div>
|
||||||
|
}
|
||||||
|
<div class="ant-drawer-content-wrapper @WrapClassName " style="@WrapperStyle" id="@($"ant-drawer-wrap_{Id}")">
|
||||||
|
<div class="ant-drawer-content">
|
||||||
|
<div class="ant-drawer-wrapper-body" style="@(IsLeftOrRight?"height:100%":"")">
|
||||||
|
@if (_title.Value != null || Closable)
|
||||||
|
{
|
||||||
|
|
||||||
<div class="@ClassMapper.Class" @ref="@Ref" style="@_drawerStyle @InnerZIndexStyle @Style" id="@Id">
|
<div class="@TitleClassMapper.Class">
|
||||||
@if (Mask)
|
@if (_title.Value != null)
|
||||||
{
|
{
|
||||||
<div class="ant-drawer-mask" @onclick="_=>MaskClick()" style="@MaskStyle"></div>
|
<div class="ant-drawer-title">
|
||||||
}
|
@if (TitleTemplate != null)
|
||||||
<div class="ant-drawer-content-wrapper @WrapClassName " style="@WrapperStyle">
|
{
|
||||||
<div class="ant-drawer-content">
|
@TitleTemplate
|
||||||
<div class="ant-drawer-wrapper-body" style="@(IsLeftOrRight?"height:100%":"")">
|
}
|
||||||
@if (_title.Value != null || Closable)
|
@if (!string.IsNullOrEmpty(TitleString))
|
||||||
{
|
{
|
||||||
|
@((MarkupString)TitleString)
|
||||||
<div class="@TitleClassMapper.Class">
|
}
|
||||||
@if (_title.Value != null)
|
</div>
|
||||||
|
}
|
||||||
|
@if (Closable)
|
||||||
|
{
|
||||||
|
<button @onclick="_=>CloseClick()" aria-label="Close" class="ant-drawer-close">
|
||||||
|
<Icon Type="close" />
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="ant-drawer-body" style="@BodyStyle">
|
||||||
|
@if (ContentTemplate != null)
|
||||||
{
|
{
|
||||||
<div class="ant-drawer-title">
|
@ContentTemplate
|
||||||
@if (TitleTemplate != null)
|
|
||||||
{
|
|
||||||
@TitleTemplate
|
|
||||||
}
|
|
||||||
@if (!string.IsNullOrEmpty(TitleString))
|
|
||||||
{
|
|
||||||
@((MarkupString)TitleString)
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
@if (Closable)
|
@if (string.IsNullOrEmpty(ContentString))
|
||||||
{
|
{
|
||||||
<button @onclick="_=>CloseClick()" aria-label="Close" class="ant-drawer-close">
|
@((MarkupString)ContentString)
|
||||||
<Icon Type="close" />
|
|
||||||
</button>
|
|
||||||
}
|
}
|
||||||
|
@ChildContent
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
<div class="ant-drawer-body" style="@BodyStyle">
|
|
||||||
@if (ContentTemplate != null)
|
|
||||||
{
|
|
||||||
@ContentTemplate
|
|
||||||
}
|
|
||||||
@if (string.IsNullOrEmpty(ContentString))
|
|
||||||
{
|
|
||||||
@((MarkupString)ContentString)
|
|
||||||
}
|
|
||||||
@ChildContent
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@if (Handler != null)
|
||||||
|
{
|
||||||
|
@Handler
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
@if (Handler != null)
|
|
||||||
{
|
|
||||||
@Handler
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</CascadingValue>
|
@ -389,5 +389,11 @@ namespace AntDesign
|
|||||||
|
|
||||||
_drawerStyle = style;
|
_drawerStyle = style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
_timer?.Dispose();
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
string prefixCls = "ant-btn";
|
string prefixCls = "ant-btn";
|
||||||
ClassMapper.Clear();
|
ClassMapper.Clear();
|
||||||
Placement = PlacementType.BottomRight;
|
Placement = Placement.BottomRight;
|
||||||
base.OnInitialized();
|
base.OnInitialized();
|
||||||
ClassMapper.If($"{prefixCls}-block", () => Block);
|
ClassMapper.If($"{prefixCls}-block", () => Block);
|
||||||
|
|
||||||
@ -208,25 +208,20 @@ namespace AntDesign
|
|||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
Ref = RefBack.Current;
|
Ref = RefBack.Current;
|
||||||
DomEventService.AddEventListener(Ref, "click", OnUnboundClick, true);
|
|
||||||
DomEventService.AddEventListener(Ref, "mouseover", OnUnboundMouseEnter, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "click", OnUnboundClick);
|
||||||
DomEventService.AddEventListener(Ref, "mouseout", OnUnboundMouseLeave, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "mouseover", OnUnboundMouseEnter);
|
||||||
DomEventService.AddEventListener(Ref, "focusin", OnUnboundFocusIn, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "mouseout", OnUnboundMouseLeave);
|
||||||
DomEventService.AddEventListener(Ref, "focusout", OnUnboundFocusOut, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "focusin", OnUnboundFocusIn);
|
||||||
DomEventService.AddEventListener(Ref, "contextmenu", OnContextMenu, true, true);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "focusout", OnUnboundFocusOut);
|
||||||
|
DomEventListener.AddExclusive<JsonElement>(Ref, "contextmenu", OnContextMenu, true);
|
||||||
}
|
}
|
||||||
return base.OnAfterRenderAsync(firstRender);
|
return base.OnAfterRenderAsync(firstRender);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "click", OnUnboundClick);
|
DomEventListener.DisposeExclusive();
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "mouseover", OnUnboundMouseEnter);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "mouseout", OnUnboundMouseLeave);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "focusin", OnUnboundFocusIn);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "focusout", OnUnboundFocusOut);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "contextmenu", OnContextMenu);
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +284,11 @@ namespace AntDesign
|
|||||||
_formItems.Add(formItem);
|
_formItems.Add(formItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IForm.RemoveFormItem(IFormItem formItem)
|
||||||
|
{
|
||||||
|
_formItems.Remove(formItem);
|
||||||
|
}
|
||||||
|
|
||||||
void IForm.AddControl(IControlValueAccessor valueAccessor)
|
void IForm.AddControl(IControlValueAccessor valueAccessor)
|
||||||
{
|
{
|
||||||
this._controls.Add(valueAccessor);
|
this._controls.Add(valueAccessor);
|
||||||
|
@ -270,6 +270,8 @@ namespace AntDesign
|
|||||||
CurrentEditContext.OnValidationStateChanged -= _validationStateChangedHandler;
|
CurrentEditContext.OnValidationStateChanged -= _validationStateChangedHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Form?.RemoveFormItem(this);
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ namespace AntDesign.Internal
|
|||||||
|
|
||||||
internal void AddFormItem(IFormItem formItem);
|
internal void AddFormItem(IFormItem formItem);
|
||||||
|
|
||||||
|
internal void RemoveFormItem(IFormItem formItem);
|
||||||
|
|
||||||
internal void AddControl(IControlValueAccessor valueAccessor);
|
internal void AddControl(IControlValueAccessor valueAccessor);
|
||||||
|
|
||||||
internal void RemoveControl(IControlValueAccessor valueAccessor);
|
internal void RemoveControl(IControlValueAccessor valueAccessor);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AntDesign.JsInterop;
|
using AntDesign.JsInterop;
|
||||||
@ -52,13 +53,13 @@ namespace AntDesign
|
|||||||
/// Used to set gutter during pre-rendering
|
/// Used to set gutter during pre-rendering
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public BreakpointType DefaultBreakpoint { get; set; } = BreakpointType.Xxl;
|
public BreakpointType? DefaultBreakpoint { get; set; } = BreakpointType.Xxl;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
private string _gutterStyle;
|
private string _gutterStyle;
|
||||||
private BreakpointType _currentBreakPoint;
|
private BreakpointType? _currentBreakPoint;
|
||||||
|
|
||||||
private IList<Col> _cols = new List<Col>();
|
private IList<Col> _cols = new List<Col>();
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
if (DefaultBreakpoint != null)
|
if (DefaultBreakpoint != null)
|
||||||
{
|
{
|
||||||
SetGutterStyle(DefaultBreakpoint.Name);
|
SetGutterStyle(DefaultBreakpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
@ -100,8 +101,8 @@ namespace AntDesign
|
|||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
var dimensions = await JsInvokeAsync<Window>(JSInteropConstants.GetWindow);
|
var dimensions = await JsInvokeAsync<Window>(JSInteropConstants.GetWindow);
|
||||||
DomEventService.AddEventListener<Window>("window", "resize", OnResize, false);
|
DomEventListener.AddShared<Window>("window", "resize", OnResize);
|
||||||
OptimizeSize(dimensions.innerWidth);
|
OptimizeSize(dimensions.InnerWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
@ -110,7 +111,7 @@ namespace AntDesign
|
|||||||
internal void AddCol(Col col)
|
internal void AddCol(Col col)
|
||||||
{
|
{
|
||||||
this._cols.Add(col);
|
this._cols.Add(col);
|
||||||
var gutter = this.GetGutter((_currentBreakPoint ?? DefaultBreakpoint).Name);
|
var gutter = this.GetGutter(_currentBreakPoint ?? DefaultBreakpoint);
|
||||||
col.RowGutterChanged(gutter);
|
col.RowGutterChanged(gutter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,9 +120,9 @@ namespace AntDesign
|
|||||||
this._cols.Remove(col);
|
this._cols.Remove(col);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnResize(Window window)
|
private void OnResize(Window window)
|
||||||
{
|
{
|
||||||
OptimizeSize(window.innerWidth);
|
OptimizeSize(window.InnerWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OptimizeSize(decimal windowWidth)
|
private void OptimizeSize(decimal windowWidth)
|
||||||
@ -129,7 +130,7 @@ namespace AntDesign
|
|||||||
BreakpointType actualBreakpoint = _breakpoints[_breakpoints.Length - 1];
|
BreakpointType actualBreakpoint = _breakpoints[_breakpoints.Length - 1];
|
||||||
for (int i = 0; i < _breakpoints.Length; i++)
|
for (int i = 0; i < _breakpoints.Length; i++)
|
||||||
{
|
{
|
||||||
if (windowWidth <= _breakpoints[i].Width && (windowWidth >= (i > 0 ? _breakpoints[i - 1].Width : 0)))
|
if (windowWidth <= (int)_breakpoints[i] && (windowWidth >= (i > 0 ? (int)_breakpoints[i - 1] : 0)))
|
||||||
{
|
{
|
||||||
actualBreakpoint = _breakpoints[i];
|
actualBreakpoint = _breakpoints[i];
|
||||||
}
|
}
|
||||||
@ -137,7 +138,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
this._currentBreakPoint = actualBreakpoint;
|
this._currentBreakPoint = actualBreakpoint;
|
||||||
|
|
||||||
SetGutterStyle(actualBreakpoint.Name);
|
SetGutterStyle(actualBreakpoint);
|
||||||
|
|
||||||
if (OnBreakpoint.HasDelegate)
|
if (OnBreakpoint.HasDelegate)
|
||||||
{
|
{
|
||||||
@ -147,7 +148,7 @@ namespace AntDesign
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetGutterStyle(string breakPoint)
|
private void SetGutterStyle(BreakpointType? breakPoint)
|
||||||
{
|
{
|
||||||
var gutter = this.GetGutter(breakPoint);
|
var gutter = this.GetGutter(breakPoint);
|
||||||
_cols.ForEach(x => x.RowGutterChanged(gutter));
|
_cols.ForEach(x => x.RowGutterChanged(gutter));
|
||||||
@ -162,27 +163,28 @@ namespace AntDesign
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private (int horizontalGutter, int verticalGutter) GetGutter(string breakPoint)
|
private (int horizontalGutter, int verticalGutter) GetGutter(BreakpointType? breakPoint)
|
||||||
{
|
{
|
||||||
GutterType gutter = 0;
|
GutterType gutter = 0;
|
||||||
if (this.Gutter.Value != null)
|
if (this.Gutter.Value != null)
|
||||||
gutter = this.Gutter;
|
gutter = this.Gutter;
|
||||||
|
|
||||||
|
var breakPointName = Enum.GetName(typeof(BreakpointType), breakPoint);
|
||||||
|
|
||||||
return gutter.Match(
|
return gutter.Match(
|
||||||
num => (num, 0),
|
num => (num, 0),
|
||||||
dic => breakPoint != null && dic.ContainsKey(breakPoint) ? (dic[breakPoint], 0) : (0, 0),
|
dic => breakPoint != null && dic.ContainsKey(breakPointName) ? (dic[breakPointName], 0) : (0, 0),
|
||||||
tuple => tuple,
|
tuple => tuple,
|
||||||
tupleDicInt => (tupleDicInt.Item1.ContainsKey(breakPoint) ? tupleDicInt.Item1[breakPoint] : 0, tupleDicInt.Item2),
|
tupleDicInt => (tupleDicInt.Item1.ContainsKey(breakPointName) ? tupleDicInt.Item1[breakPointName] : 0, tupleDicInt.Item2),
|
||||||
tupleIntDic => (tupleIntDic.Item1, tupleIntDic.Item2.ContainsKey(breakPoint) ? tupleIntDic.Item2[breakPoint] : 0),
|
tupleIntDic => (tupleIntDic.Item1, tupleIntDic.Item2.ContainsKey(breakPointName) ? tupleIntDic.Item2[breakPointName] : 0),
|
||||||
tupleDicDic => (tupleDicDic.Item1.ContainsKey(breakPoint) ? tupleDicDic.Item1[breakPoint] : 0, tupleDicDic.Item2.ContainsKey(breakPoint) ? tupleDicDic.Item2[breakPoint] : 0)
|
tupleDicDic => (tupleDicDic.Item1.ContainsKey(breakPointName) ? tupleDicDic.Item1[breakPointName] : 0, tupleDicDic.Item2.ContainsKey(breakPointName) ? tupleDicDic.Item2[breakPointName] : 0)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
DomEventListener.Dispose();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
|
||||||
DomEventService.RemoveEventListerner<Window>("window", "resize", OnResize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="ant-input-number-input-wrap">
|
<div class="ant-input-number-input-wrap">
|
||||||
<input @ref="Ref" role="spinbutton" aria-valuemin="@Min" aria-valuemax="@Max" autocomplete="off" max="@Max" min="@Min" step="@Step"
|
<input @ref="Ref" role="spinbutton" aria-valuemin="@Min" aria-valuemax="@Max" autocomplete="off" max="@Max" min="@Min" step="@Step" inputmode="@_inputNumberMode"
|
||||||
aria-valuenow="@CurrentValue" class="ant-input-number-input" @bind="@CurrentValueAsString" @oninput="OnInput" @onkeydown="OnKeyDown" @onfocus="@OnFocus" @onblur="@OnBlurAsync" disabled="@Disabled" />
|
aria-valuenow="@CurrentValue" class="ant-input-number-input" @bind="@CurrentValueAsString" @oninput="OnInput" @onkeydown="OnKeyDown" @onfocus="@OnFocusAsync" @onblur="@OnBlurAsync" disabled="@Disabled" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -74,6 +74,9 @@ namespace AntDesign
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<TValue> OnChange { get; set; }
|
public EventCallback<TValue> OnChange { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public EventCallback<FocusEventArgs> OnFocus { get; set; }
|
||||||
|
|
||||||
private readonly bool _isNullable;
|
private readonly bool _isNullable;
|
||||||
private bool _hasDefaultValue;
|
private bool _hasDefaultValue;
|
||||||
|
|
||||||
@ -115,40 +118,40 @@ namespace AntDesign
|
|||||||
|
|
||||||
private static readonly Dictionary<Type, object> _defaultMaximum = new Dictionary<Type, object>()
|
private static readonly Dictionary<Type, object> _defaultMaximum = new Dictionary<Type, object>()
|
||||||
{
|
{
|
||||||
{ typeof(sbyte),sbyte.MaxValue },
|
{ typeof(sbyte), sbyte.MaxValue },
|
||||||
{ typeof(byte), byte.MaxValue },
|
{ typeof(byte), byte.MaxValue },
|
||||||
|
|
||||||
{ typeof(short),short.MaxValue },
|
{ typeof(short), short.MaxValue },
|
||||||
{ typeof(ushort),ushort.MaxValue },
|
{ typeof(ushort), ushort.MaxValue },
|
||||||
|
|
||||||
{ typeof(int),int.MaxValue },
|
{ typeof(int), int.MaxValue },
|
||||||
{ typeof(uint),uint.MaxValue },
|
{ typeof(uint), uint.MaxValue },
|
||||||
|
|
||||||
{ typeof(long),long.MaxValue },
|
{ typeof(long), long.MaxValue },
|
||||||
{ typeof(ulong),ulong.MaxValue },
|
{ typeof(ulong), ulong.MaxValue },
|
||||||
|
|
||||||
{ typeof(float),float.PositiveInfinity },
|
{ typeof(float), float.PositiveInfinity },
|
||||||
{ typeof(double),double.PositiveInfinity },
|
{ typeof(double), double.PositiveInfinity },
|
||||||
{ typeof(decimal),decimal.MaxValue },
|
{ typeof(decimal), decimal.MaxValue },
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Dictionary<Type, object> _defaultMinimum = new Dictionary<Type, object>()
|
private static readonly Dictionary<Type, object> _defaultMinimum = new Dictionary<Type, object>()
|
||||||
{
|
{
|
||||||
{ typeof(sbyte),sbyte.MinValue },
|
{ typeof(sbyte), sbyte.MinValue },
|
||||||
{ typeof(byte), byte.MinValue },
|
{ typeof(byte), byte.MinValue },
|
||||||
|
|
||||||
{ typeof(short),short.MinValue },
|
{ typeof(short), short.MinValue },
|
||||||
{ typeof(ushort),ushort.MinValue },
|
{ typeof(ushort), ushort.MinValue },
|
||||||
|
|
||||||
{ typeof(int),int.MinValue },
|
{ typeof(int), int.MinValue },
|
||||||
{ typeof(uint),uint.MinValue },
|
{ typeof(uint), uint.MinValue },
|
||||||
|
|
||||||
{ typeof(long),long.MinValue },
|
{ typeof(long), long.MinValue },
|
||||||
{ typeof(ulong),ulong.MinValue },
|
{ typeof(ulong), ulong.MinValue },
|
||||||
|
|
||||||
{ typeof(float),float.NegativeInfinity},
|
{ typeof(float), float.NegativeInfinity},
|
||||||
{ typeof(double),double.NegativeInfinity },
|
{ typeof(double), double.NegativeInfinity },
|
||||||
{ typeof(decimal),decimal.MinValue },
|
{ typeof(decimal), decimal.MinValue },
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Type[] _floatTypes = new Type[] { typeof(float), typeof(double), typeof(decimal) };
|
private static Type[] _floatTypes = new Type[] { typeof(float), typeof(double), typeof(decimal) };
|
||||||
@ -160,6 +163,8 @@ namespace AntDesign
|
|||||||
private CancellationTokenSource _decreaseTokenSource;
|
private CancellationTokenSource _decreaseTokenSource;
|
||||||
private TValue _defaultValue;
|
private TValue _defaultValue;
|
||||||
|
|
||||||
|
private string _inputNumberMode = "numeric";
|
||||||
|
|
||||||
public InputNumber()
|
public InputNumber()
|
||||||
{
|
{
|
||||||
_isNullable = _surfaceType.IsGenericType && _surfaceType.GetGenericTypeDefinition() == typeof(Nullable<>);
|
_isNullable = _surfaceType.IsGenericType && _surfaceType.GetGenericTypeDefinition() == typeof(Nullable<>);
|
||||||
@ -203,6 +208,7 @@ namespace AntDesign
|
|||||||
MethodCallExpression expRound = Expression.Call(null, typeof(InputNumberMath).GetMethod(nameof(InputNumberMath.Round), new Type[] { _surfaceType, typeof(int) }), num, decimalPlaces);
|
MethodCallExpression expRound = Expression.Call(null, typeof(InputNumberMath).GetMethod(nameof(InputNumberMath.Round), new Type[] { _surfaceType, typeof(int) }), num, decimalPlaces);
|
||||||
var lambdaRound = Expression.Lambda<Func<TValue, int, TValue>>(expRound, num, decimalPlaces);
|
var lambdaRound = Expression.Lambda<Func<TValue, int, TValue>>(expRound, num, decimalPlaces);
|
||||||
_roundFunc = lambdaRound.Compile();
|
_roundFunc = lambdaRound.Compile();
|
||||||
|
_inputNumberMode = "decimal";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_defaultMaximum.ContainsKey(underlyingType)) Max = (TValue)_defaultMaximum[underlyingType];
|
if (_defaultMaximum.ContainsKey(underlyingType)) Max = (TValue)_defaultMaximum[underlyingType];
|
||||||
@ -404,10 +410,15 @@ namespace AntDesign
|
|||||||
_inputString = args.Value?.ToString();
|
_inputString = args.Value?.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFocus()
|
private async Task OnFocusAsync(FocusEventArgs args)
|
||||||
{
|
{
|
||||||
_focused = true;
|
_focused = true;
|
||||||
CurrentValue = Value;
|
CurrentValue = Value;
|
||||||
|
|
||||||
|
if (OnFocus.HasDelegate)
|
||||||
|
{
|
||||||
|
await OnFocus.InvokeAsync(args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnBlurAsync()
|
private async Task OnBlurAsync()
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -32,7 +31,7 @@ namespace AntDesign
|
|||||||
protected virtual bool EnableOnPressEnter => OnPressEnter.HasDelegate;
|
protected virtual bool EnableOnPressEnter => OnPressEnter.HasDelegate;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public DomEventService DomEventService { get; set; }
|
protected IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The label text displayed before (on the left side of) the input field.
|
/// The label text displayed before (on the left side of) the input field.
|
||||||
@ -52,6 +51,13 @@ namespace AntDesign
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool AllowClear { get; set; }
|
public bool AllowClear { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls the autocomplete attribute of the input HTML element.
|
||||||
|
/// Default = true
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public bool AutoComplete { get; set; } = true;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool AutoFocus
|
public bool AutoFocus
|
||||||
{
|
{
|
||||||
@ -168,8 +174,11 @@ namespace AntDesign
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ReadOnly { get; set; }
|
public bool ReadOnly { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls onclick & blur event propagation.
|
||||||
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool AutoComplete { get; set; } = true;
|
public bool StopPropagation { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The suffix icon for the Input.
|
/// The suffix icon for the Input.
|
||||||
@ -451,9 +460,10 @@ namespace AntDesign
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_debounceTimer?.Dispose();
|
|
||||||
if (_debounceTimer != null)
|
if (_debounceTimer != null)
|
||||||
{
|
{
|
||||||
|
await _debounceTimer.DisposeAsync();
|
||||||
|
|
||||||
_debounceTimer = null;
|
_debounceTimer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,23 +487,21 @@ namespace AntDesign
|
|||||||
|
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener(Ref, "compositionstart", OnCompositionStart);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "compositionstart", OnCompositionStart);
|
||||||
DomEventService.AddEventListener(Ref, "compositionend", OnCompositionEnd);
|
DomEventListener.AddExclusive<JsonElement>(Ref, "compositionend", OnCompositionEnd);
|
||||||
if (this.AutoFocus)
|
if (this.AutoFocus)
|
||||||
{
|
{
|
||||||
IsFocused = true;
|
IsFocused = true;
|
||||||
await this.FocusAsync(Ref);
|
await this.FocusAsync(Ref);
|
||||||
}
|
}
|
||||||
DomEventService.AddEventListener(Ref, "focus", OnFocusInternal, true);
|
|
||||||
|
DomEventListener.AddExclusive<JsonElement>(Ref, "focus", OnFocusInternal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "compositionstart", OnCompositionStart);
|
DomEventListener.DisposeExclusive();
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "compositionend", OnCompositionEnd);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(Ref, "focus", OnFocusInternal);
|
|
||||||
|
|
||||||
_debounceTimer?.Dispose();
|
_debounceTimer?.Dispose();
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
@ -641,6 +649,13 @@ namespace AntDesign
|
|||||||
//TODO: Use built in @onfocus once https://github.com/dotnet/aspnetcore/issues/30070 is solved
|
//TODO: Use built in @onfocus once https://github.com/dotnet/aspnetcore/issues/30070 is solved
|
||||||
//builder.AddAttribute(76, "onfocus", CallbackFactory.Create(this, OnFocusAsync));
|
//builder.AddAttribute(76, "onfocus", CallbackFactory.Create(this, OnFocusAsync));
|
||||||
builder.AddAttribute(77, "onmouseup", CallbackFactory.Create(this, OnMouseUpAsync));
|
builder.AddAttribute(77, "onmouseup", CallbackFactory.Create(this, OnMouseUpAsync));
|
||||||
|
|
||||||
|
if (StopPropagation)
|
||||||
|
{
|
||||||
|
builder.AddEventStopPropagationAttribute(78, "onchange", true);
|
||||||
|
builder.AddEventStopPropagationAttribute(79, "onblur", true);
|
||||||
|
}
|
||||||
|
|
||||||
builder.AddElementReferenceCapture(90, r => Ref = r);
|
builder.AddElementReferenceCapture(90, r => Ref = r);
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System.Threading.Tasks;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AntDesign.Core.Extensions;
|
using AntDesign.Core.Extensions;
|
||||||
using AntDesign.JsInterop;
|
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
@namespace AntDesign
|
@namespace AntDesign
|
||||||
@inherits Input<string>
|
@inherits Input<string>
|
||||||
<!--TODO: minheight, maxheight, onResize-->
|
|
||||||
|
|
||||||
@{
|
@{
|
||||||
Dictionary<string, object> attributes =
|
Dictionary<string, object> attributes =
|
||||||
@ -34,13 +33,13 @@
|
|||||||
@if (Suffix != null)
|
@if (Suffix != null)
|
||||||
{
|
{
|
||||||
<span class="@_warpperClassMapper.Class">
|
<span class="@_warpperClassMapper.Class">
|
||||||
<textarea @ref="Ref" @attributes="attributes"/>
|
<textarea @ref="Ref" @attributes="attributes" @onchange:stopPropagation="@StopPropagation" @onblur:stopPropagation="@StopPropagation"/>
|
||||||
@Suffix
|
@Suffix
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<textarea @ref="Ref" @attributes="attributes"/>
|
<textarea @ref="Ref" @attributes="attributes" @onchange:stopPropagation="@StopPropagation" @onblur:stopPropagation="@StopPropagation"/>
|
||||||
}
|
}
|
||||||
<AntDesign.Text Style="float: right; pointer-events: none; white-space: nowrap; color: rgba(0, 0, 0, 0.45)"> @($"/ {MaxLength}")</AntDesign.Text>
|
<AntDesign.Text Style="float: right; pointer-events: none; white-space: nowrap; color: rgba(0, 0, 0, 0.45)"> @($"/ {MaxLength}")</AntDesign.Text>
|
||||||
</div>
|
</div>
|
||||||
@ -50,12 +49,12 @@ else
|
|||||||
@if (Suffix != null)
|
@if (Suffix != null)
|
||||||
{
|
{
|
||||||
<span class="@_warpperClassMapper.Class">
|
<span class="@_warpperClassMapper.Class">
|
||||||
<textarea @ref="Ref" @attributes="attributes"/>
|
<textarea @ref="Ref" @attributes="attributes" @onchange:stopPropagation="@StopPropagation" @onblur:stopPropagation="@StopPropagation"/>
|
||||||
@Suffix
|
@Suffix
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<textarea @ref="Ref" @attributes="attributes"/>
|
<textarea @ref="Ref" @attributes="attributes" @onchange:stopPropagation="@StopPropagation" @onblur:stopPropagation="@StopPropagation"/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using System;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AntDesign.JsInterop;
|
using AntDesign.JsInterop;
|
||||||
@ -28,10 +26,39 @@ namespace AntDesign
|
|||||||
private uint _minRows = DEFAULT_MIN_ROWS;
|
private uint _minRows = DEFAULT_MIN_ROWS;
|
||||||
private uint _maxRows = uint.MaxValue;
|
private uint _maxRows = uint.MaxValue;
|
||||||
private bool _hasMinOrMaxSet;
|
private bool _hasMinOrMaxSet;
|
||||||
|
private bool _hasMinSet;
|
||||||
private DotNetObjectReference<TextArea> _reference;
|
private DotNetObjectReference<TextArea> _reference;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will adjust (grow or shrink) the `TextArea` according to content.
|
||||||
|
/// Can work in connection with `MaxRows` & `MinRows`.
|
||||||
|
/// Sets resize attribute of the textarea HTML element to: none.
|
||||||
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool AutoSize { get; set; }
|
public bool AutoSize
|
||||||
|
{
|
||||||
|
get => _autoSize;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_hasMinOrMaxSet && !value)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("AntBlazor.TextArea: AutoSize cannot be set to false when either MinRows or MaxRows has been set.AutoSize has been switched to true.");
|
||||||
|
_autoSize = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_autoSize = value;
|
||||||
|
}
|
||||||
|
if (_autoSize)
|
||||||
|
{
|
||||||
|
_resizeStyle = "resize: none";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_resizeStyle = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When `false`, value will be set to `null` when content is empty
|
/// When `false`, value will be set to `null` when content is empty
|
||||||
@ -58,12 +85,13 @@ namespace AntDesign
|
|||||||
if (value >= MinRows)
|
if (value >= MinRows)
|
||||||
{
|
{
|
||||||
_maxRows = value;
|
_maxRows = value;
|
||||||
|
Debug.WriteLineIf(!AutoSize, "AntBlazor.TextArea: AutoSize cannot be set to false when either MinRows or MaxRows has been set.AutoSize has been switched to true.");
|
||||||
AutoSize = true;
|
AutoSize = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_maxRows = uint.MaxValue;
|
_maxRows = uint.MaxValue;
|
||||||
Debug.WriteLine($"Value of {nameof(MaxRows)}({MaxRows}) has to be between {nameof(MinRows)}({MinRows}) and {uint.MaxValue}");
|
Debug.WriteLine($"AntBlazor.TextArea: Value of {nameof(MaxRows)}({MaxRows}) has to be between {nameof(MinRows)}({MinRows}) and {uint.MaxValue}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,19 +111,28 @@ namespace AntDesign
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_hasMinOrMaxSet = true;
|
_hasMinOrMaxSet = true;
|
||||||
|
_hasMinSet = true;
|
||||||
if (value >= DEFAULT_MIN_ROWS && value <= MaxRows)
|
if (value >= DEFAULT_MIN_ROWS && value <= MaxRows)
|
||||||
{
|
{
|
||||||
_minRows = value;
|
_minRows = value;
|
||||||
|
Debug.WriteLineIf(!AutoSize, "AntBlazor.TextArea: AutoSize cannot be set to false when either MinRows or MaxRows has been set.AutoSize has been switched to true.");
|
||||||
AutoSize = true;
|
AutoSize = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_minRows = DEFAULT_MIN_ROWS;
|
_minRows = DEFAULT_MIN_ROWS;
|
||||||
Debug.WriteLine($"Value of {nameof(MinRows)}({MinRows}) has to be between {DEFAULT_MIN_ROWS} and {nameof(MaxRows)}({MaxRows})");
|
Debug.WriteLine($"AntBlazor.TextArea: Value of {nameof(MinRows)}({MinRows}) has to be between {DEFAULT_MIN_ROWS} and {nameof(MaxRows)}({MaxRows})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the height of the TextArea expressed in number of rows.
|
||||||
|
/// Default value is 3.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public uint Rows { get; set; } = 3;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback when the size changes
|
/// Callback when the size changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -132,41 +169,25 @@ namespace AntDesign
|
|||||||
|
|
||||||
if (AutoSize)
|
if (AutoSize)
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener("window", "beforeunload", Reloading, false);
|
DomEventListener.AddShared<JsonElement>("window", "beforeunload", Reloading);
|
||||||
|
|
||||||
await CalculateRowHeightAsync();
|
|
||||||
}
|
}
|
||||||
|
await CalculateRowHeightAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
|
protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
|
||||||
{
|
{
|
||||||
|
validationErrorMessage = null;
|
||||||
if (string.IsNullOrWhiteSpace(value))
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
{
|
{
|
||||||
if (DefaultToEmptyString)
|
if (DefaultToEmptyString)
|
||||||
result = string.Empty;
|
result = string.Empty;
|
||||||
else
|
else
|
||||||
result = default;
|
result = default;
|
||||||
validationErrorMessage = null;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
result = value;
|
||||||
|
return true;
|
||||||
|
|
||||||
var success = BindConverter.TryConvertTo<string>(
|
|
||||||
value, CultureInfo.CurrentCulture, out var parsedValue);
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
result = parsedValue;
|
|
||||||
validationErrorMessage = null;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = default;
|
|
||||||
validationErrorMessage = $"{FieldIdentifier.FieldName} field isn't valid.";
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@ -174,7 +195,7 @@ namespace AntDesign
|
|||||||
if (AutoSize && !_isReloading)
|
if (AutoSize && !_isReloading)
|
||||||
{
|
{
|
||||||
_reference?.Dispose();
|
_reference?.Dispose();
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "beforeunload", Reloading);
|
DomEventListener.Dispose();
|
||||||
|
|
||||||
_ = InvokeAsync(async () =>
|
_ = InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
@ -189,6 +210,8 @@ namespace AntDesign
|
|||||||
/// Indicates that a page is being refreshed
|
/// Indicates that a page is being refreshed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool _isReloading;
|
private bool _isReloading;
|
||||||
|
private bool _autoSize;
|
||||||
|
private string _resizeStyle = "";
|
||||||
|
|
||||||
private void Reloading(JsonElement jsonElement) => _isReloading = true;
|
private void Reloading(JsonElement jsonElement) => _isReloading = true;
|
||||||
|
|
||||||
@ -205,33 +228,39 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
_reference = DotNetObjectReference.Create<TextArea>(this);
|
_reference = DotNetObjectReference.Create<TextArea>(this);
|
||||||
}
|
}
|
||||||
var textAreaInfo = await JsInvokeAsync<TextAreaInfo>(JSInteropConstants.RegisterResizeTextArea, Ref, MinRows, MaxRows, _reference);
|
|
||||||
|
|
||||||
// var textAreaInfo = await JsInvokeAsync<TextAreaInfo>(JSInteropConstants.GetTextAreaInfo, Ref);
|
uint rows = Rows;
|
||||||
|
if (_hasMinSet)
|
||||||
|
rows = MinRows;
|
||||||
|
|
||||||
|
TextAreaInfo textAreaInfo;
|
||||||
|
if (AutoSize)
|
||||||
|
{
|
||||||
|
textAreaInfo = await JsInvokeAsync<TextAreaInfo>(
|
||||||
|
JSInteropConstants.InputComponentHelper.RegisterResizeTextArea, Ref, rows, MaxRows, _reference);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textAreaInfo = await JsInvokeAsync<TextAreaInfo>(
|
||||||
|
JSInteropConstants.InputComponentHelper.GetTextAreaInfo, Ref);
|
||||||
|
}
|
||||||
|
|
||||||
_rowHeight = textAreaInfo.LineHeight;
|
_rowHeight = textAreaInfo.LineHeight;
|
||||||
_offsetHeight = textAreaInfo.PaddingTop + textAreaInfo.PaddingBottom
|
_offsetHeight = textAreaInfo.PaddingTop + textAreaInfo.PaddingBottom
|
||||||
+ textAreaInfo.BorderTop + textAreaInfo.BorderBottom;
|
+ textAreaInfo.BorderTop + textAreaInfo.BorderBottom;
|
||||||
|
|
||||||
uint rows = (uint)(textAreaInfo.ScrollHeight / _rowHeight);
|
|
||||||
if (_hasMinOrMaxSet)
|
|
||||||
rows = Math.Max((uint)MinRows, rows);
|
|
||||||
|
|
||||||
double height = 0;
|
|
||||||
if (rows > MaxRows)
|
if (rows > MaxRows)
|
||||||
{
|
{
|
||||||
rows = MaxRows;
|
Style = $"height: {MaxRows * _rowHeight + _offsetHeight}px;{_resizeStyle};overflow-x: hidden";
|
||||||
|
|
||||||
height = rows * _rowHeight + _offsetHeight;
|
|
||||||
Style = $"height: {height}px;";
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
height = rows * _rowHeight + _offsetHeight;
|
string overflow = _autoSize ? "hidden" : "visible";
|
||||||
Style = $"height: {height}px;overflow-y: hidden;";
|
Style = $"height: {rows * _rowHeight + _offsetHeight}px;overflow-y: {overflow};{_resizeStyle};overflow-x: hidden";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TextAreaInfo
|
internal class TextAreaInfo
|
||||||
{
|
{
|
||||||
public double ScrollHeight { get; set; }
|
public double ScrollHeight { get; set; }
|
||||||
public double LineHeight { get; set; }
|
public double LineHeight { get; set; }
|
||||||
|
@ -1,19 +1,12 @@
|
|||||||
namespace AntDesign
|
namespace AntDesign
|
||||||
{
|
{
|
||||||
public sealed class BreakpointType : EnumValue<BreakpointType>
|
public enum BreakpointType
|
||||||
{
|
{
|
||||||
public static readonly BreakpointType Xs = new BreakpointType(nameof(Xs).ToLowerInvariant(), 1, 480);
|
Xs = 480,
|
||||||
public static readonly BreakpointType Sm = new BreakpointType(nameof(Sm).ToLowerInvariant(), 2, 576);
|
Sm = 576,
|
||||||
public static readonly BreakpointType Md = new BreakpointType(nameof(Md).ToLowerInvariant(), 3, 768);
|
Md = 768,
|
||||||
public static readonly BreakpointType Lg = new BreakpointType(nameof(Lg).ToLowerInvariant(), 4, 992);
|
Lg = 992,
|
||||||
public static readonly BreakpointType Xl = new BreakpointType(nameof(Xl).ToLowerInvariant(), 5, 1200);
|
Xl = 1200,
|
||||||
public static readonly BreakpointType Xxl = new BreakpointType(nameof(Xxl).ToLowerInvariant(), 6, 1600);
|
Xxl = 1600,
|
||||||
|
|
||||||
public int Width { get; private set; }
|
|
||||||
|
|
||||||
private BreakpointType(string name, int value, int width) : base(name, value)
|
|
||||||
{
|
|
||||||
Width = width;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
[CascadingParameter] public Layout Parent { get; set; }
|
[CascadingParameter] public Layout Parent { get; set; }
|
||||||
|
|
||||||
[Parameter] public BreakpointType Breakpoint { get; set; }
|
[Parameter] public BreakpointType? Breakpoint { get; set; }
|
||||||
|
|
||||||
[Parameter] public SiderTheme Theme { get; set; } = SiderTheme.Dark;
|
[Parameter] public SiderTheme Theme { get; set; } = SiderTheme.Dark;
|
||||||
|
|
||||||
@ -50,7 +50,8 @@ namespace AntDesign
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<bool> OnBreakpoint { get; set; }
|
public EventCallback<bool> OnBreakpoint { get; set; }
|
||||||
|
|
||||||
[Inject] public DomEventService DomEventService { get; set; }
|
[Inject]
|
||||||
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
private int ComputedWidth => _isCollapsed ? CollapsedWidth : Width;
|
private int ComputedWidth => _isCollapsed ? CollapsedWidth : Width;
|
||||||
|
|
||||||
@ -112,14 +113,14 @@ namespace AntDesign
|
|||||||
if (firstRender && Breakpoint != null)
|
if (firstRender && Breakpoint != null)
|
||||||
{
|
{
|
||||||
var dimensions = await JsInvokeAsync<Window>(JSInteropConstants.GetWindow);
|
var dimensions = await JsInvokeAsync<Window>(JSInteropConstants.GetWindow);
|
||||||
DomEventService.AddEventListener<Window>("window", "resize", OnResize, false);
|
DomEventListener.AddShared<Window>("window", "resize", OnResize);
|
||||||
OptimizeSize(dimensions.innerWidth);
|
OptimizeSize(dimensions.InnerWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnResize(Window window)
|
private void OnResize(Window window)
|
||||||
{
|
{
|
||||||
OptimizeSize(window.innerWidth);
|
OptimizeSize(window.InnerWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleCollapsed()
|
public void ToggleCollapsed()
|
||||||
@ -138,7 +139,7 @@ namespace AntDesign
|
|||||||
var originalCollapsed = _isCollapsed;
|
var originalCollapsed = _isCollapsed;
|
||||||
var originlBrokenPoint = _brokenPoint;
|
var originlBrokenPoint = _brokenPoint;
|
||||||
|
|
||||||
if (windowWidth < Breakpoint?.Width)
|
if (windowWidth < (int)Breakpoint)
|
||||||
{
|
{
|
||||||
_brokenPoint = true;
|
_brokenPoint = true;
|
||||||
_isCollapsed = true;
|
_isCollapsed = true;
|
||||||
@ -171,9 +172,8 @@ namespace AntDesign
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
DomEventListener.Dispose();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
|
||||||
DomEventService.RemoveEventListerner<Window>("window", "resize", OnResize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
@typeparam TItem
|
@typeparam TItem
|
||||||
|
|
||||||
<div class="@ClassMapper.Class" style="@Style" Id="@Id" @ref="Ref">
|
<div class="@ClassMapper.Class" style="@Style" Id="@Id" @ref="Ref">
|
||||||
|
|
||||||
@if (Header != null)
|
@if (Header != null)
|
||||||
{
|
{
|
||||||
<div class="@PrefixName-header">
|
<div class="@PrefixName-header">
|
||||||
@ -11,31 +10,27 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (DataSource != null && DataSource.Any())
|
@if (DataSource?.Any() == true)
|
||||||
{
|
{
|
||||||
<Spin Spinning="Loading">
|
<Spin Spinning="Loading">
|
||||||
@if (Grid != null)
|
@if (Grid != null)
|
||||||
{
|
{
|
||||||
<Row Gutter="Grid.Gutter">
|
<Row Gutter="Grid.Gutter" OnBreakpoint="OnBreakpoint">
|
||||||
@foreach (var item in DataSource)
|
@foreach (var item in DataSource)
|
||||||
{
|
{
|
||||||
<CascadingValue Value="ItemLayout">
|
<CascadingValue Value="this" IsFixed>
|
||||||
<CascadingValue Value="()=>HandleItemClick(item)" TValue="Action" Name="ItemClick">
|
@ChildContent(item)
|
||||||
@ChildContent(item)
|
</CascadingValue>
|
||||||
</CascadingValue>
|
}
|
||||||
</CascadingValue>
|
</Row>
|
||||||
}
|
|
||||||
</Row>
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ul class="ant-list-items">
|
<ul class="ant-list-items">
|
||||||
@foreach (var item in DataSource)
|
@foreach (var item in DataSource)
|
||||||
{
|
{
|
||||||
<CascadingValue Value="ItemLayout">
|
<CascadingValue Value="this" IsFixed>
|
||||||
<CascadingValue Value="()=>HandleItemClick(item)" TValue="Action" Name="ItemClick">
|
@ChildContent(item)
|
||||||
@ChildContent(item)
|
|
||||||
</CascadingValue>
|
|
||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -16,7 +16,7 @@ namespace AntDesign
|
|||||||
public int Xxl { get; set; }
|
public int Xxl { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class AntList<TItem> : AntDomComponentBase
|
public partial class AntList<TItem> : AntDomComponentBase, IAntList
|
||||||
{
|
{
|
||||||
public string PrefixName { get; set; } = "ant-list";
|
public string PrefixName { get; set; } = "ant-list";
|
||||||
|
|
||||||
@ -40,8 +40,6 @@ namespace AntDesign
|
|||||||
|
|
||||||
[Parameter] public bool Split { get; set; } = true;
|
[Parameter] public bool Split { get; set; } = true;
|
||||||
|
|
||||||
[Parameter] public EventCallback<TItem> OnItemClick { get; set; }
|
|
||||||
|
|
||||||
[Parameter] public ListGridType Grid { get; set; }
|
[Parameter] public ListGridType Grid { get; set; }
|
||||||
|
|
||||||
[Parameter] public PaginationOptions Pagination { get; set; }
|
[Parameter] public PaginationOptions Pagination { get; set; }
|
||||||
@ -56,49 +54,63 @@ namespace AntDesign
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string SizeCls => Size switch
|
||||||
|
{
|
||||||
|
"large" => "lg",
|
||||||
|
"small" => "sm",
|
||||||
|
_ => string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
ListGridType IAntList.Grid => Grid;
|
||||||
|
ListItemLayout IAntList.ItemLayout => ItemLayout;
|
||||||
|
double IAntList.ColumnWidth => _columnWidth;
|
||||||
|
|
||||||
|
double _columnWidth;
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
SetClassMap();
|
SetClassMap();
|
||||||
|
|
||||||
|
if (Grid?.Column > 0)
|
||||||
|
{
|
||||||
|
_columnWidth = 100d / Grid.Column;
|
||||||
|
}
|
||||||
|
|
||||||
base.OnInitialized();
|
base.OnInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetClassMap()
|
protected void SetClassMap()
|
||||||
{
|
{
|
||||||
// large => lg
|
|
||||||
// small => sm
|
|
||||||
string sizeCls = string.Empty;
|
|
||||||
switch (Size)
|
|
||||||
{
|
|
||||||
case "large":
|
|
||||||
sizeCls = "lg";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "small":
|
|
||||||
sizeCls = "sm";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassMapper.Clear()
|
ClassMapper.Clear()
|
||||||
.Add(PrefixName)
|
.Add(PrefixName)
|
||||||
.If($"{PrefixName}-split", () => Split)
|
.If($"{PrefixName}-split", () => Split)
|
||||||
.If($"{PrefixName}-rtl", () => RTL)
|
.If($"{PrefixName}-rtl", () => RTL)
|
||||||
.If($"{PrefixName}-bordered", () => Bordered)
|
.If($"{PrefixName}-bordered", () => Bordered)
|
||||||
.GetIf(() => $"{PrefixName}-{sizeCls}", () => !string.IsNullOrEmpty(sizeCls))
|
.GetIf(() => $"{PrefixName}-{SizeCls}", () => !string.IsNullOrEmpty(SizeCls))
|
||||||
.If($"{PrefixName}-vertical", () => ItemLayout == ListItemLayout.Vertical)
|
.If($"{PrefixName}-vertical", () => ItemLayout == ListItemLayout.Vertical)
|
||||||
.If($"{PrefixName}-loading", () => (Loading))
|
.If($"{PrefixName}-loading", () => (Loading))
|
||||||
.If($"{PrefixName}-grid", () => Grid != null)
|
.If($"{PrefixName}-grid", () => Grid != null)
|
||||||
.If($"{PrefixName}-something-after-last-item", () => IsSomethingAfterLastItem);
|
.If($"{PrefixName}-something-after-last-item", () => IsSomethingAfterLastItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleItemClick(TItem item)
|
private void OnBreakpoint(BreakpointType breakPoint)
|
||||||
{
|
{
|
||||||
if (OnItemClick.HasDelegate)
|
var column = breakPoint switch
|
||||||
{
|
{
|
||||||
OnItemClick.InvokeAsync(item);
|
BreakpointType.Xs => Grid.Xs,
|
||||||
|
BreakpointType.Sm => Grid.Sm,
|
||||||
|
BreakpointType.Md => Grid.Md,
|
||||||
|
BreakpointType.Lg => Grid.Lg,
|
||||||
|
BreakpointType.Xl => Grid.Xl,
|
||||||
|
BreakpointType.Xxl => Grid.Xxl,
|
||||||
|
_ => 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (column > 0)
|
||||||
|
{
|
||||||
|
_columnWidth = 100d / column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
components/list/IAntList.cs
Normal file
20
components/list/IAntList.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// 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
|
||||||
|
{
|
||||||
|
internal interface IAntList
|
||||||
|
{
|
||||||
|
internal ListGridType Grid { get; }
|
||||||
|
|
||||||
|
internal ListItemLayout ItemLayout { get; }
|
||||||
|
|
||||||
|
internal double ColumnWidth { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -9,18 +9,20 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<AntDesign.Col Flex="1" Style="@ColStyle">
|
<div style="width: @(AntList.ColumnWidth)%; max-width: @(AntList.ColumnWidth)%;">
|
||||||
<div class="@ClassMapper.Class" style="@Style" Id="@Id" @onclick="HandleClick" @onclick:stopPropagation @ref="Ref">
|
<AntDesign.Col Flex="1" >
|
||||||
@itemChildren(this)
|
<div class="@ClassMapper.Class" style="@Style" Id="@Id" @onclick="HandleClick" @onclick:stopPropagation @ref="Ref">
|
||||||
</div>
|
@itemChildren(this)
|
||||||
</AntDesign.Col>
|
</div>
|
||||||
|
</AntDesign.Col>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
@code{
|
@code{
|
||||||
|
|
||||||
|
|
||||||
RenderFragment<ListItem> itemChildren = content =>
|
RenderFragment<ListItem> itemChildren = content =>
|
||||||
@<Template>
|
@<Template>
|
||||||
@if (content.ItemLayout == ListItemLayout.Vertical && content.Extra != null)
|
@if (content.IsVerticalAndExtra)
|
||||||
{
|
{
|
||||||
<div class="@content.PrefixName-main">
|
<div class="@content.PrefixName-main">
|
||||||
@content.ChildContent
|
@content.ChildContent
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
using System;
|
using System.Threading.Tasks;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AntDesign.JsInterop;
|
using AntDesign.JsInterop;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
@ -19,8 +14,6 @@ namespace AntDesign
|
|||||||
|
|
||||||
[Parameter] public RenderFragment[] Actions { get; set; }
|
[Parameter] public RenderFragment[] Actions { get; set; }
|
||||||
|
|
||||||
[Parameter] public ListGridType Grid { get; set; }
|
|
||||||
|
|
||||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||||
|
|
||||||
[Parameter] public string ColStyle { get; set; }
|
[Parameter] public string ColStyle { get; set; }
|
||||||
@ -31,86 +24,21 @@ namespace AntDesign
|
|||||||
|
|
||||||
[Parameter] public bool NoFlex { get; set; }
|
[Parameter] public bool NoFlex { get; set; }
|
||||||
|
|
||||||
[CascadingParameter] public ListItemLayout ItemLayout { get; set; }
|
[CascadingParameter]
|
||||||
|
private IAntList AntList { get; set; }
|
||||||
[CascadingParameter(Name = "ItemClick")] public Action ItemClick { get; set; }
|
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
public bool IsVerticalAndExtra()
|
public bool IsVerticalAndExtra => AntList?.ItemLayout == ListItemLayout.Vertical && this.Extra != null;
|
||||||
{
|
private ListGridType Grid => AntList.Grid;
|
||||||
return this.ItemLayout == ListItemLayout.Vertical && this.Extra != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
SetClassMap();
|
SetClassMap();
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
||||||
{
|
|
||||||
if (firstRender && Grid != null)
|
|
||||||
{
|
|
||||||
await this.SetGutterStyle();
|
|
||||||
DomEventService.AddEventListener<object>("window", "resize", OnResize, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnResize(object o)
|
|
||||||
{
|
|
||||||
await SetGutterStyle();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Hashtable _gridResponsiveMap = new Hashtable()
|
|
||||||
{
|
|
||||||
[nameof(BreakpointEnum.xs)] = "(max-width: 575px)",
|
|
||||||
[nameof(BreakpointEnum.sm)] = "(max-width: 576px)",
|
|
||||||
[nameof(BreakpointEnum.md)] = "(max-width: 768px)",
|
|
||||||
[nameof(BreakpointEnum.lg)] = "(max-width: 992px)",
|
|
||||||
[nameof(BreakpointEnum.xl)] = "(max-width: 1200px)",
|
|
||||||
[nameof(BreakpointEnum.xxl)] = "(max-width: 1600px)",
|
|
||||||
};
|
|
||||||
|
|
||||||
private async Task SetGutterStyle()
|
|
||||||
{
|
|
||||||
string breakPoint = null;
|
|
||||||
|
|
||||||
await typeof(BreakpointEnum).GetEnumNames().ForEachAsync(async bp =>
|
|
||||||
{
|
|
||||||
if (await JsInvokeAsync<bool>(JSInteropConstants.MatchMedia, _gridResponsiveMap[bp]))
|
|
||||||
{
|
|
||||||
breakPoint = bp;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var column = GetColumn(breakPoint);
|
|
||||||
|
|
||||||
int columnCount = column > 0 ? column : (Grid?.Column ?? 0);
|
|
||||||
if (Grid != null && columnCount > 0)
|
|
||||||
{
|
|
||||||
ColStyle = $"width:{100 / columnCount}%;max-width:{100 / columnCount}%";
|
|
||||||
}
|
|
||||||
|
|
||||||
InvokeStateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int GetColumn(string breakPoint)
|
|
||||||
{
|
|
||||||
var column = 0;
|
|
||||||
if (Grid != null && !string.IsNullOrEmpty(breakPoint))
|
|
||||||
{
|
|
||||||
var value = GetModelValue(breakPoint, Grid);
|
|
||||||
int.TryParse(value, out column);
|
|
||||||
return column;
|
|
||||||
}
|
|
||||||
return column;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void SetClassMap()
|
protected void SetClassMap()
|
||||||
{
|
{
|
||||||
ClassMapper.Clear()
|
ClassMapper.Clear()
|
||||||
@ -118,48 +46,18 @@ namespace AntDesign
|
|||||||
.If($"{PrefixName}-no-flex", () => NoFlex);
|
.If($"{PrefixName}-no-flex", () => NoFlex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsFlexMode()
|
|
||||||
{
|
|
||||||
if (ItemLayout == ListItemLayout.Vertical)
|
|
||||||
{
|
|
||||||
return Extra != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Actions != null || Grid != null) && ItemCount > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetModelValue(string fieldName, object obj)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (obj == null || string.IsNullOrEmpty(fieldName)) return null;
|
|
||||||
var o = obj.GetType().GetProperty(fieldName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance).GetValue(obj, null);
|
|
||||||
var value = o?.ToString() ?? null;
|
|
||||||
if (string.IsNullOrEmpty(value)) return null;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleClick()
|
private void HandleClick()
|
||||||
{
|
{
|
||||||
if (OnClick.HasDelegate)
|
if (OnClick.HasDelegate)
|
||||||
{
|
{
|
||||||
OnClick.InvokeAsync(this);
|
OnClick.InvokeAsync(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemClick?.Invoke();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
DomEventListener.Dispose();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
|
|
||||||
DomEventService.RemoveEventListerner<object>("window", "resize", OnResize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ namespace AntDesign
|
|||||||
|
|
||||||
public Dictionary<string, object> Attributes { get; set; }
|
public Dictionary<string, object> Attributes { get; set; }
|
||||||
|
|
||||||
[Inject] private DomEventService DomEventService { get; set; }
|
|
||||||
internal List<MentionsOption> LstOriginalOptions { get; set; } = new List<MentionsOption>();
|
internal List<MentionsOption> LstOriginalOptions { get; set; } = new List<MentionsOption>();
|
||||||
|
|
||||||
private string DropdownStyle { get; set; }
|
private string DropdownStyle { get; set; }
|
||||||
@ -63,9 +62,6 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
Value = DefaultValue;
|
Value = DefaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//DomEventService.AddEventListener(Ref, "keyup", OnTextAreaKeyup);
|
|
||||||
// DomEventService.AddEventListener(Ref, "onmouseup", OnTextAreaMouseUp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool FirstTime { get; set; } = true;
|
internal bool FirstTime { get; set; } = true;
|
||||||
|
@ -20,6 +20,7 @@ namespace AntDesign
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public MenuTheme Theme { get; set; } = MenuTheme.Light;
|
public MenuTheme Theme { get; set; } = MenuTheme.Light;
|
||||||
|
|
||||||
|
internal MenuMode? InitialMode { get; private set; }
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public MenuMode Mode
|
public MenuMode Mode
|
||||||
{
|
{
|
||||||
@ -110,7 +111,7 @@ namespace AntDesign
|
|||||||
public EventCallback<string[]> SelectedKeysChanged { get; set; }
|
public EventCallback<string[]> SelectedKeysChanged { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public TriggerType TriggerSubMenuAction { get; set; } = TriggerType.Hover;
|
public Trigger TriggerSubMenuAction { get; set; } = Trigger.Hover;
|
||||||
|
|
||||||
internal MenuMode InternalMode { get; private set; }
|
internal MenuMode InternalMode { get; private set; }
|
||||||
|
|
||||||
@ -223,7 +224,7 @@ namespace AntDesign
|
|||||||
throw new ArgumentException($"{nameof(Menu)} in the {Mode} mode cannot be {nameof(InlineCollapsed)}");
|
throw new ArgumentException($"{nameof(Menu)} in the {Mode} mode cannot be {nameof(InlineCollapsed)}");
|
||||||
|
|
||||||
InternalMode = Mode;
|
InternalMode = Mode;
|
||||||
|
InitialMode = Mode;
|
||||||
Parent?.AddMenu(this);
|
Parent?.AddMenu(this);
|
||||||
|
|
||||||
OpenKeys = DefaultOpenKeys?.ToArray() ?? OpenKeys;
|
OpenKeys = DefaultOpenKeys?.ToArray() ?? OpenKeys;
|
||||||
|
@ -2,43 +2,67 @@
|
|||||||
@inherits AntDomComponentBase
|
@inherits AntDomComponentBase
|
||||||
|
|
||||||
<CascadingValue Value="this" IsFixed>
|
<CascadingValue Value="this" IsFixed>
|
||||||
<Tooltip Title="@content(this)" Placement="@PlacementType.Right" Disabled="TooltipDisabled">
|
@* There is no need to render the tooltip if there is no inline mode. Tooltip will be only showing menu content if menu is collapsed to icon version && only for root menu *@
|
||||||
<Unbound>
|
@if (RootMenu.Mode == MenuMode.Inline && ParentMenu is null)
|
||||||
<li class="@ClassMapper.Class" role="menuitem" style=" @(PaddingLeft>0? $"padding-left:{PaddingLeft}px;":"") @Style" @onclick="HandleOnClick" @key="Key" @ref="context.Current">
|
{
|
||||||
|
<Tooltip Title="@content(this)" Placement="@Placement.Right" Disabled="TooltipDisabled">
|
||||||
|
<Unbound Context="tooltip">
|
||||||
|
<li class="@ClassMapper.Class" role="menuitem" style=" @(PaddingLeft>0? $"padding-left:{PaddingLeft}px;":"") @Style" @onclick="HandleOnClick" @key="Key" @ref="tooltip.Current">
|
||||||
|
@if (IconTemplate != null)
|
||||||
|
{
|
||||||
|
@IconTemplate
|
||||||
|
}
|
||||||
|
else if (Icon != null)
|
||||||
|
{
|
||||||
|
<Icon Type="@Icon" />
|
||||||
|
}
|
||||||
|
<span class="ant-menu-title-content">
|
||||||
|
@if (RouterLink == null)
|
||||||
|
{
|
||||||
|
@content(this)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<MenuLink Href="@RouterLink" Match="@RouterMatch">@content(this)</MenuLink>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</Unbound>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<li class="@ClassMapper.Class" role="menuitem" style=" @(PaddingLeft>0? $"padding-left:{PaddingLeft}px;":"") @Style" @onclick="HandleOnClick" @key="Key">
|
||||||
|
@if (Icon != null)
|
||||||
|
{
|
||||||
|
<Icon Type="@Icon" />
|
||||||
|
}
|
||||||
|
|
||||||
@if (IconTemplate != null)
|
<span class="ant-menu-title-content">
|
||||||
{
|
@if (RouterLink == null)
|
||||||
@IconTemplate
|
{
|
||||||
}
|
@content(this)
|
||||||
else if (Icon != null)
|
}
|
||||||
{
|
else
|
||||||
<Icon Type="@Icon" />
|
{
|
||||||
}
|
<MenuLink Href="@RouterLink" Match="@RouterMatch">@content(this)</MenuLink>
|
||||||
|
}
|
||||||
@if (RouterLink == null)
|
</span>
|
||||||
{
|
</li>
|
||||||
@content(this)
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<MenuLink Href="@RouterLink" Match="@RouterMatch">@content(this)</MenuLink>
|
|
||||||
}
|
|
||||||
</li>
|
|
||||||
</Unbound>
|
|
||||||
</Tooltip>
|
|
||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
RenderFragment<MenuItem> content = item =>@<Template>
|
RenderFragment<MenuItem> content = item =>
|
||||||
<span>
|
@<Template>
|
||||||
@if (item.Title != null)
|
@if (item.Title != null)
|
||||||
{
|
{
|
||||||
@item.Title
|
@item.Title
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@item.ChildContent
|
@item.ChildContent
|
||||||
}
|
}
|
||||||
</span>
|
</Template>
|
||||||
</Template>;
|
;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ else
|
|||||||
{
|
{
|
||||||
if (Placement == null)
|
if (Placement == null)
|
||||||
{
|
{
|
||||||
Placement = (RootMenu.Mode == MenuMode.Horizontal && Parent == null) ? PlacementType.BottomLeft : PlacementType.RightTop;
|
Placement = (RootMenu.Mode == MenuMode.Horizontal && Parent == null) ? AntDesign.Placement.BottomLeft : AntDesign.Placement.RightTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
<CascadingValue Value="this" Name="SubMenu" IsFixed="@true">
|
<CascadingValue Value="this" Name="SubMenu" IsFixed="@true">
|
||||||
@ -41,11 +41,11 @@ else
|
|||||||
ComplexAutoCloseAndVisible="true"
|
ComplexAutoCloseAndVisible="true"
|
||||||
BoundaryAdjustMode="@TriggerBoundaryAdjustMode.None"
|
BoundaryAdjustMode="@TriggerBoundaryAdjustMode.None"
|
||||||
Disabled="Disabled"
|
Disabled="Disabled"
|
||||||
Placement="Placement"
|
Placement="Placement.Value"
|
||||||
OnVisibleChange="OnOverlayVisibleChange"
|
OnVisibleChange="OnOverlayVisibleChange"
|
||||||
OnOverlayHiding="OnOverlayHiding"
|
OnOverlayHiding="OnOverlayHiding"
|
||||||
Trigger="new[] { RootMenu?.TriggerSubMenuAction }"
|
Trigger="new Trigger[] { RootMenu?.TriggerSubMenuAction ?? Trigger.Hover }"
|
||||||
PlacementCls="@($"{prefixCls}-placement-{Placement.Name} {prefixCls}-popup")"
|
PlacementCls="@($"{prefixCls}-placement-{_placement.Name} {prefixCls}-popup")"
|
||||||
OverlayEnterCls="@($"{prefixCls}-{RootMenu.Theme} ")"
|
OverlayEnterCls="@($"{prefixCls}-{RootMenu.Theme} ")"
|
||||||
OverlayLeaveCls="@($"{prefixCls}-{RootMenu.Theme} ")"
|
OverlayLeaveCls="@($"{prefixCls}-{RootMenu.Theme} ")"
|
||||||
OverlayHiddenCls="@($"{RootMenu.PrefixCls}-hidden")">
|
OverlayHiddenCls="@($"{RootMenu.PrefixCls}-hidden")">
|
||||||
|
@ -16,7 +16,21 @@ namespace AntDesign
|
|||||||
public SubMenu Parent { get; set; }
|
public SubMenu Parent { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public PlacementType Placement { get; set; }
|
public Placement? Placement
|
||||||
|
{
|
||||||
|
get { return _placement?.Placement; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value is null)
|
||||||
|
{
|
||||||
|
_placement = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_placement = PlacementType.Create(value.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
@ -57,6 +71,7 @@ namespace AntDesign
|
|||||||
private OverlayTrigger _overlayTrigger;
|
private OverlayTrigger _overlayTrigger;
|
||||||
|
|
||||||
internal bool _overlayVisible;
|
internal bool _overlayVisible;
|
||||||
|
private PlacementType? _placement;
|
||||||
|
|
||||||
private void SetClass()
|
private void SetClass()
|
||||||
{
|
{
|
||||||
@ -136,7 +151,16 @@ namespace AntDesign
|
|||||||
base.OnParametersSet();
|
base.OnParametersSet();
|
||||||
|
|
||||||
if (!RootMenu.InlineCollapsed && RootMenu.OpenKeys.Contains(Key))
|
if (!RootMenu.InlineCollapsed && RootMenu.OpenKeys.Contains(Key))
|
||||||
IsOpen = true;
|
{
|
||||||
|
if (RootMenu.InitialMode != RootMenu.Mode)
|
||||||
|
{
|
||||||
|
IsOpen = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IsOpen = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
@ -7,16 +7,18 @@
|
|||||||
{
|
{
|
||||||
<div class=@($"{Config.PrefixCls}-mask {GetMaskClsName()}") style="@Config.MaskStyle"></div>
|
<div class=@($"{Config.PrefixCls}-mask {GetMaskClsName()}") style="@Config.MaskStyle"></div>
|
||||||
}
|
}
|
||||||
<div tabindex="-1" id=@($"{Config.PrefixCls}-wrap_{DialogWrapperId}") class=@($"{Config.PrefixCls}-wrap {Config.GetWrapClassNameExtended()}") role="dialog"
|
<div tabindex="-1" class=@($"{Config.PrefixCls}-wrap {Config.GetWrapClassNameExtended()}") role="dialog"
|
||||||
@onclick="@EventUtil.AsNonRenderingEventHandler(OnMaskClick)"
|
@onclick="@EventUtil.AsNonRenderingEventHandler(OnMaskClick)"
|
||||||
@onmouseup="@EventUtil.AsNonRenderingEventHandler(OnMaskMouseUp)"
|
@onmouseup="@EventUtil.AsNonRenderingEventHandler(OnMaskMouseUp)"
|
||||||
@onkeydown="@OnKeyDown"
|
@onkeydown="@OnKeyDown"
|
||||||
style="@_wrapStyle">
|
style="@_wrapStyle">
|
||||||
<div @ref="@_modal" role="document" class=@($"{Config.PrefixCls} {GetModalClsName()}")
|
<div @ref="@_modal" role="document" class=@($"{Config.PrefixCls} {GetModalClsName()}")
|
||||||
|
@onclick:stopPropagation
|
||||||
@onmousedown="@EventUtil.AsNonRenderingEventHandler(OnDialogMouseDown)"
|
@onmousedown="@EventUtil.AsNonRenderingEventHandler(OnDialogMouseDown)"
|
||||||
style="@GetStyle()">
|
style="@GetStyle()"
|
||||||
|
>
|
||||||
<div id="@_sentinelStart" tabindex="0" aria-hidden="true" style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div>
|
<div id="@_sentinelStart" tabindex="0" aria-hidden="true" style="width: 0px; height: 0px; overflow: hidden; outline: none;"></div>
|
||||||
<div class=@($"{Config.PrefixCls}-content")>
|
<div class=@($"{Config.PrefixCls}-content") id=@($"{Config.PrefixCls}-wrap_{DialogWrapperId}") >
|
||||||
@if (Config.Closable)
|
@if (Config.Closable)
|
||||||
{
|
{
|
||||||
<button type="button" aria-label="Close" class=@($"{Config.PrefixCls}-close") @onclick="@OnCloserClick">
|
<button type="button" aria-label="Close" class=@($"{Config.PrefixCls}-close") @onclick="@OnCloserClick">
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
Size="@(IsSmall ? "small" : "default")"
|
Size="@(IsSmall ? "small" : "default")"
|
||||||
Class="@($"{prefixCls}-size-changer")"
|
Class="@($"{prefixCls}-size-changer")"
|
||||||
DefaultValue="@(PageSize > 0 ? PageSize : pageSizeOptions[0])"
|
DefaultValue="@(PageSize > 0 ? PageSize : pageSizeOptions[0])"
|
||||||
|
BoundaryAdjustMode="@TriggerBoundaryAdjustMode.InView"
|
||||||
OnSelectedItemChanged="@(i => {if (ChangeSize.HasDelegate)ChangeSize.InvokeAsync(i);})">
|
OnSelectedItemChanged="@(i => {if (ChangeSize.HasDelegate)ChangeSize.InvokeAsync(i);})">
|
||||||
<SelectOptions>
|
<SelectOptions>
|
||||||
@foreach(var opt in pageSizeOptions)
|
@foreach(var opt in pageSizeOptions)
|
||||||
|
@ -54,13 +54,13 @@ namespace AntDesign
|
|||||||
public Popconfirm()
|
public Popconfirm()
|
||||||
{
|
{
|
||||||
PrefixCls = "ant-popover";
|
PrefixCls = "ant-popover";
|
||||||
Placement = PlacementType.Top;
|
Placement = Placement.Top;
|
||||||
Trigger = new[] { TriggerType.Click };
|
Trigger = new[] { AntDesign.Trigger.Click };
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override async Task Show(int? overlayLeft = null, int? overlayTop = null)
|
internal override async Task Show(int? overlayLeft = null, int? overlayTop = null)
|
||||||
{
|
{
|
||||||
if (Trigger.Contains(TriggerType.Hover))
|
if (Trigger.Contains(AntDesign.Trigger.Hover))
|
||||||
{
|
{
|
||||||
await Task.Delay((int)(MouseEnterDelay * 1000));
|
await Task.Delay((int)(MouseEnterDelay * 1000));
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
internal override async Task Hide(bool force = false)
|
internal override async Task Hide(bool force = false)
|
||||||
{
|
{
|
||||||
if (Trigger.Contains(TriggerType.Hover))
|
if (Trigger.Contains(AntDesign.Trigger.Hover))
|
||||||
{
|
{
|
||||||
await Task.Delay((int)(MouseLeaveDelay * 1000));
|
await Task.Delay((int)(MouseLeaveDelay * 1000));
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace AntDesign
|
|||||||
public Popover()
|
public Popover()
|
||||||
{
|
{
|
||||||
PrefixCls = "ant-popover";
|
PrefixCls = "ant-popover";
|
||||||
Placement = PlacementType.Top;
|
Placement = Placement.Top;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override string GetOverlayEnterClass()
|
internal override string GetOverlayEnterClass()
|
||||||
@ -47,7 +47,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
internal override async Task Show(int? overlayLeft = null, int? overlayTop = null)
|
internal override async Task Show(int? overlayLeft = null, int? overlayTop = null)
|
||||||
{
|
{
|
||||||
if (Trigger.Contains(TriggerType.Hover))
|
if (Trigger.Contains(AntDesign.Trigger.Hover))
|
||||||
{
|
{
|
||||||
await Task.Delay((int)(MouseEnterDelay * 1000));
|
await Task.Delay((int)(MouseEnterDelay * 1000));
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
internal override async Task Hide(bool force = false)
|
internal override async Task Hide(bool force = false)
|
||||||
{
|
{
|
||||||
if (Trigger.Contains(TriggerType.Hover))
|
if (Trigger.Contains(AntDesign.Trigger.Hover))
|
||||||
{
|
{
|
||||||
await Task.Delay((int)(MouseLeaveDelay * 1000));
|
await Task.Delay((int)(MouseLeaveDelay * 1000));
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,9 @@
|
|||||||
<OverlayTrigger @ref="@_dropDown"
|
<OverlayTrigger @ref="@_dropDown"
|
||||||
Visible="Open"
|
Visible="Open"
|
||||||
Disabled="Disabled"
|
Disabled="Disabled"
|
||||||
Trigger="new[] { TriggerType.Click }"
|
Trigger="new[] { Trigger.Click }"
|
||||||
HiddenMode
|
HiddenMode
|
||||||
|
BoundaryAdjustMode="@BoundaryAdjustMode"
|
||||||
OnMouseEnter="@(() => { OnMouseEnter?.Invoke(); })"
|
OnMouseEnter="@(() => { OnMouseEnter?.Invoke(); })"
|
||||||
OnMouseLeave="@(() => { OnMouseLeave?.Invoke(); })"
|
OnMouseLeave="@(() => { OnMouseLeave?.Invoke(); })"
|
||||||
OnVisibleChange="@OnOverlayVisibleChangeAsync"
|
OnVisibleChange="@OnOverlayVisibleChangeAsync"
|
||||||
@ -23,7 +24,7 @@
|
|||||||
<div style="@_dropdownStyle">
|
<div style="@_dropdownStyle">
|
||||||
@if (SelectOptions != null)
|
@if (SelectOptions != null)
|
||||||
{
|
{
|
||||||
<div class="" style="max-height: @PopupContainerMaxHeight; overflow-y: auto;">
|
<div class="" style="max-height: @PopupContainerMaxHeight; overflow-y: auto;" @ref="_scrollableSelectDiv">
|
||||||
<div>
|
<div>
|
||||||
<div class="" role="listbox" style="display: flex; flex-direction: column;">
|
<div class="" role="listbox" style="display: flex; flex-direction: column;">
|
||||||
@if (CustomTagSelectOptionItem != null)
|
@if (CustomTagSelectOptionItem != null)
|
||||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AntDesign.Core.Helpers.MemberPath;
|
using AntDesign.Core.Helpers.MemberPath;
|
||||||
@ -21,83 +22,69 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
#region Parameters
|
#region Parameters
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overlay adjustment strategy (when for example browser resize is happening)
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public TriggerBoundaryAdjustMode BoundaryAdjustMode { get; set; } = TriggerBoundaryAdjustMode.None;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Toggle the border style.
|
/// Toggle the border style.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter] public bool Bordered { get; set; } = true;
|
[Parameter] public bool Bordered { get; set; } = true;
|
||||||
|
|
||||||
|
|
||||||
|
bool _dataSourceHasChanged = false;
|
||||||
|
IEnumerable<TItem> _dataSourceCopy;
|
||||||
|
IEnumerable<TItem> _dataSourceShallowCopy;
|
||||||
|
//private bool? _isTItemPrimitive;
|
||||||
|
//private bool IsTItemPrimitive
|
||||||
|
//{
|
||||||
|
// get
|
||||||
|
// {
|
||||||
|
// if (_isTItemPrimitive is null)
|
||||||
|
// {
|
||||||
|
// _isTItemPrimitive = IsSimpleType(typeof(TItem));
|
||||||
|
// }
|
||||||
|
// return _isTItemPrimitive!.Value;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MethodInfo will contain attached MemberwiseClone protected
|
||||||
|
/// method. Due to its protection level, it has to be accessed
|
||||||
|
/// using reflection. It will be used during generation of
|
||||||
|
/// the DataSource shallow copy (which is a new list of DataSource
|
||||||
|
/// items with shallow copy of each item).
|
||||||
|
/// </summary>
|
||||||
|
private MethodInfo _dataSourceItemShallowCopyMehtod;
|
||||||
|
private MethodInfo GetDataSourceItemCloneMethod()
|
||||||
|
{
|
||||||
|
if (_dataSourceItemShallowCopyMehtod is null)
|
||||||
|
{
|
||||||
|
_dataSourceItemShallowCopyMehtod = this.GetType().GetGenericArguments()[1]
|
||||||
|
.GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
if (DataSourceEqualityComparer is null)
|
||||||
|
{
|
||||||
|
DataSourceEqualityComparer = new DataSourceEqualityComparer<TItemValue, TItem>(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _dataSourceItemShallowCopyMehtod;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The datasource for this component.
|
/// The datasource for this component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public IEnumerable<TItem> DataSource
|
public IEnumerable<TItem> DataSource { get; set; }
|
||||||
{
|
|
||||||
get => _datasource;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == null && _datasource == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value == null && _datasource != null)
|
/// <summary>
|
||||||
{
|
/// EqualityComparer that will be used during DataSource change
|
||||||
if (!_isInitialized)
|
/// detection. If no comparer set, default .Net is going to be
|
||||||
{
|
/// used.
|
||||||
_selectedValue = default;
|
/// </summary>
|
||||||
}
|
[Parameter]
|
||||||
else
|
public IEqualityComparer<TItem> DataSourceEqualityComparer { get; set; }
|
||||||
{
|
|
||||||
SelectOptionItems.Clear();
|
|
||||||
SelectedOptionItems.Clear();
|
|
||||||
Value = default;
|
|
||||||
|
|
||||||
_datasource = null;
|
|
||||||
|
|
||||||
OnDataSourceChanged?.Invoke();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value != null && !value.Any() && SelectOptionItems.Any())
|
|
||||||
{
|
|
||||||
SelectOptionItems.Clear();
|
|
||||||
SelectedOptionItems.Clear();
|
|
||||||
|
|
||||||
Value = default;
|
|
||||||
var sameObject = object.ReferenceEquals(_datasource, value);
|
|
||||||
|
|
||||||
_datasource = value;
|
|
||||||
|
|
||||||
if (!sameObject)
|
|
||||||
OnDataSourceChanged?.Invoke();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
bool hasChanged;
|
|
||||||
|
|
||||||
if (_datasource == null)
|
|
||||||
{
|
|
||||||
hasChanged = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hasChanged = !value.SequenceEqual(_datasource);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasChanged)
|
|
||||||
{
|
|
||||||
OnDataSourceChanged?.Invoke();
|
|
||||||
|
|
||||||
_datasource = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Activates the first item that is not deactivated.
|
/// Activates the first item that is not deactivated.
|
||||||
@ -315,6 +302,7 @@ namespace AntDesign
|
|||||||
if (_valueHasChanged)
|
if (_valueHasChanged)
|
||||||
{
|
{
|
||||||
_selectedValue = value;
|
_selectedValue = value;
|
||||||
|
_valueHasChanged = _isInitialized;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -339,13 +327,9 @@ namespace AntDesign
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion Parameters
|
#endregion Parameters
|
||||||
|
|
||||||
[Inject] private DomEventService DomEventService { get; set; }
|
[Inject] private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
|
|
||||||
@ -359,12 +343,14 @@ namespace AntDesign
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal ElementReference DropDownRef => _dropDown.GetOverlayComponent().Ref;
|
internal ElementReference DropDownRef => _dropDown.GetOverlayComponent().Ref;
|
||||||
|
private ElementReference _scrollableSelectDiv;
|
||||||
|
|
||||||
private string _dropdownStyle = string.Empty;
|
private string _dropdownStyle = string.Empty;
|
||||||
private TItemValue _selectedValue;
|
private TItemValue _selectedValue;
|
||||||
private TItemValue _defaultValue;
|
private TItemValue _defaultValue;
|
||||||
private bool _defaultValueIsNotNull;
|
private bool _defaultValueIsNotNull;
|
||||||
private IEnumerable<TItem> _datasource;
|
private IEnumerable<TItem> _datasource;
|
||||||
|
private bool _afterFirstRender;
|
||||||
private bool _optionsHasInitialized;
|
private bool _optionsHasInitialized;
|
||||||
private bool _defaultValueApplied;
|
private bool _defaultValueApplied;
|
||||||
private bool _defaultActiveFirstOptionApplied;
|
private bool _defaultActiveFirstOptionApplied;
|
||||||
@ -376,7 +362,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
private string _labelName;
|
private string _labelName;
|
||||||
|
|
||||||
private Func<TItem, string> _getLabel;
|
internal Func<TItem, string> _getLabel;
|
||||||
|
|
||||||
|
|
||||||
private string _groupName = string.Empty;
|
private string _groupName = string.Empty;
|
||||||
@ -389,7 +375,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
private string _valueName;
|
private string _valueName;
|
||||||
|
|
||||||
private Func<TItem, TItemValue> _getValue;
|
internal Func<TItem, TItemValue> _getValue;
|
||||||
|
|
||||||
private bool _disableSubmitFormOnEnter;
|
private bool _disableSubmitFormOnEnter;
|
||||||
private bool _showArrowIcon = true;
|
private bool _showArrowIcon = true;
|
||||||
@ -441,10 +427,15 @@ namespace AntDesign
|
|||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
|
EvaluateDataSourceChange();
|
||||||
if (SelectOptions == null)
|
if (SelectOptions == null)
|
||||||
{
|
{
|
||||||
CreateDeleteSelectOptions();
|
if (!_optionsHasInitialized || _dataSourceHasChanged)
|
||||||
_optionsHasInitialized = true;
|
{
|
||||||
|
CreateDeleteSelectOptions();
|
||||||
|
_optionsHasInitialized = true;
|
||||||
|
_dataSourceHasChanged = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_valueHasChanged && _optionsHasInitialized)
|
if (_valueHasChanged && _optionsHasInitialized)
|
||||||
@ -456,10 +447,116 @@ namespace AntDesign
|
|||||||
EditContext?.NotifyFieldChanged(FieldIdentifier);
|
EditContext?.NotifyFieldChanged(FieldIdentifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnParametersSet();
|
base.OnParametersSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EvaluateDataSourceChange()
|
||||||
|
{
|
||||||
|
if (DataSource == null && _datasource == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DataSource == null && _datasource != null)
|
||||||
|
{
|
||||||
|
SelectOptionItems.Clear();
|
||||||
|
SelectedOptionItems.Clear();
|
||||||
|
Value = default;
|
||||||
|
|
||||||
|
_datasource = null;
|
||||||
|
_dataSourceCopy = null;
|
||||||
|
_dataSourceShallowCopy = null;
|
||||||
|
|
||||||
|
OnDataSourceChanged?.Invoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DataSource != null && !DataSource.Any() && SelectOptionItems.Any())
|
||||||
|
{
|
||||||
|
SelectOptionItems.Clear();
|
||||||
|
SelectedOptionItems.Clear();
|
||||||
|
|
||||||
|
Value = default;
|
||||||
|
|
||||||
|
_datasource = DataSource;
|
||||||
|
_dataSourceShallowCopy = new List<TItem>();
|
||||||
|
_dataSourceCopy = new List<TItem>();
|
||||||
|
|
||||||
|
OnDataSourceChanged?.Invoke();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DataSource != null)
|
||||||
|
{
|
||||||
|
if (_datasource == null)
|
||||||
|
{
|
||||||
|
_dataSourceHasChanged = true;
|
||||||
|
}
|
||||||
|
else if (_isPrimitive)
|
||||||
|
{
|
||||||
|
_dataSourceHasChanged = !DataSource.SequenceEqual(_dataSourceCopy);
|
||||||
|
}
|
||||||
|
else if (_getValue is null)
|
||||||
|
{
|
||||||
|
_dataSourceHasChanged = !DataSource.SequenceEqual(_dataSourceCopy) ||
|
||||||
|
!DataSource.SequenceEqual(_dataSourceShallowCopy, DataSourceEqualityComparer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dataSourceHasChanged = !DataSource.SequenceEqual(_dataSourceShallowCopy, DataSourceEqualityComparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dataSourceHasChanged)
|
||||||
|
{
|
||||||
|
OnDataSourceChanged?.Invoke();
|
||||||
|
_datasource = DataSource;
|
||||||
|
if (_isPrimitive)
|
||||||
|
{
|
||||||
|
_dataSourceCopy = _datasource.ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_getValue is null)
|
||||||
|
{
|
||||||
|
_dataSourceCopy = _datasource.ToList();
|
||||||
|
}
|
||||||
|
var cloneMethod = GetDataSourceItemCloneMethod();
|
||||||
|
_dataSourceShallowCopy = _datasource.Select(x => (TItem)cloneMethod.Invoke(x, null)).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used only when ChildElement SelectOptions is used.
|
||||||
|
/// Will run this process if after initalization an item
|
||||||
|
/// is added that is also marked as selected.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
internal async Task ProcessSelectedSelectOptions()
|
||||||
|
{
|
||||||
|
if (_isInitialized && _afterFirstRender)
|
||||||
|
{
|
||||||
|
if (Mode == "default")
|
||||||
|
{
|
||||||
|
if (LastValueBeforeReset is not null)
|
||||||
|
{
|
||||||
|
OnValueChange(LastValueBeforeReset);
|
||||||
|
LastValueBeforeReset = default;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OnValueChange(Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await OnValuesChangeAsync(Values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (SelectOptions != null)
|
if (SelectOptions != null)
|
||||||
@ -471,7 +568,7 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
await SetInitialValuesAsync();
|
await SetInitialValuesAsync();
|
||||||
|
|
||||||
DomEventService.AddEventListener("window", "resize", OnWindowResize, false);
|
DomEventListener.AddShared<JsonElement>("window", "resize", OnWindowResize);
|
||||||
await SetDropdownStyleAsync();
|
await SetDropdownStyleAsync();
|
||||||
|
|
||||||
_defaultValueApplied = !(_defaultValueIsNotNull || _defaultValuesHasItems);
|
_defaultValueApplied = !(_defaultValueIsNotNull || _defaultValuesHasItems);
|
||||||
@ -511,11 +608,12 @@ namespace AntDesign
|
|||||||
}
|
}
|
||||||
|
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
_afterFirstRender = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "resize", OnWindowResize);
|
DomEventListener.Dispose();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,7 +665,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
foreach (var item in _datasource)
|
foreach (var item in _datasource)
|
||||||
{
|
{
|
||||||
TItemValue value = _getValue == null ? THelper.ChangeType<TItemValue>(item) : _getValue(item);
|
TItemValue value = _getValue == null ? (TItemValue)(object)item : _getValue(item);
|
||||||
|
|
||||||
var exists = false;
|
var exists = false;
|
||||||
SelectOptionItem<TItemValue, TItem> selectOption;
|
SelectOptionItem<TItemValue, TItem> selectOption;
|
||||||
@ -725,7 +823,7 @@ namespace AntDesign
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task ElementScrollIntoViewAsync(ElementReference element)
|
private async Task ElementScrollIntoViewAsync(ElementReference element)
|
||||||
{
|
{
|
||||||
await JsInvokeAsync(JSInteropConstants.ScrollTo, element);
|
await JsInvokeAsync(JSInteropConstants.ScrollTo, element, _scrollableSelectDiv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -960,14 +1058,20 @@ namespace AntDesign
|
|||||||
return newItem;
|
return newItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected virtual string GetLabel(TItem item)
|
protected virtual string GetLabel(TItem item)
|
||||||
{
|
{
|
||||||
return item.ToString();
|
return item.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
|
/// <summary>
|
||||||
|
/// When newly set Value is not found in SelectOptionItems, it is reset to
|
||||||
|
/// default. This property holds the value before reset. It may be needed
|
||||||
|
/// to be reaplied (for example when new Value is set at the same time
|
||||||
|
/// as new SelectOption is added, but Value in the component is set
|
||||||
|
/// before new SelectOptionItem has been created).
|
||||||
|
/// </summary>
|
||||||
|
internal TItemValue LastValueBeforeReset { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Method is called every time if the value of the @bind-Value was changed by the two-way binding.
|
/// The Method is called every time if the value of the @bind-Value was changed by the two-way binding.
|
||||||
@ -987,6 +1091,11 @@ namespace AntDesign
|
|||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
|
if (SelectOptions is not null)
|
||||||
|
{
|
||||||
|
LastValueBeforeReset = value;
|
||||||
|
}
|
||||||
|
|
||||||
if (!AllowClear)
|
if (!AllowClear)
|
||||||
_ = TrySetDefaultValueAsync();
|
_ = TrySetDefaultValueAsync();
|
||||||
else
|
else
|
||||||
@ -1399,9 +1508,6 @@ namespace AntDesign
|
|||||||
currentSelected.IsActive = true;
|
currentSelected.IsActive = true;
|
||||||
ActiveOption = currentSelected;
|
ActiveOption = currentSelected;
|
||||||
|
|
||||||
// ToDo: Sometime the element does not scroll, you have to call the function twice
|
|
||||||
await ElementScrollIntoViewAsync(currentSelected.Ref);
|
|
||||||
await Task.Delay(1);
|
|
||||||
await ElementScrollIntoViewAsync(currentSelected.Ref);
|
await ElementScrollIntoViewAsync(currentSelected.Ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1504,9 +1610,6 @@ namespace AntDesign
|
|||||||
currentSelected.IsActive = true;
|
currentSelected.IsActive = true;
|
||||||
ActiveOption = currentSelected;
|
ActiveOption = currentSelected;
|
||||||
|
|
||||||
// ToDo: Sometime the element does not scroll, you have to call the function twice
|
|
||||||
await ElementScrollIntoViewAsync(currentSelected.Ref);
|
|
||||||
await Task.Delay(1);
|
|
||||||
await ElementScrollIntoViewAsync(currentSelected.Ref);
|
await ElementScrollIntoViewAsync(currentSelected.Ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1703,9 +1806,6 @@ namespace AntDesign
|
|||||||
|
|
||||||
currentSelected.IsActive = true;
|
currentSelected.IsActive = true;
|
||||||
ActiveOption = currentSelected;
|
ActiveOption = currentSelected;
|
||||||
// ToDo: Sometime the element does not scroll, you have to call the function twice
|
|
||||||
await ElementScrollIntoViewAsync(currentSelected.Ref);
|
|
||||||
await Task.Delay(1);
|
|
||||||
await ElementScrollIntoViewAsync(currentSelected.Ref);
|
await ElementScrollIntoViewAsync(currentSelected.Ref);
|
||||||
}
|
}
|
||||||
else if (ActiveOption == null)//position on first element in the list
|
else if (ActiveOption == null)//position on first element in the list
|
||||||
|
@ -161,6 +161,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
bool isAlreadySelected = false;
|
||||||
if (SelectParent.SelectOptions == null)
|
if (SelectParent.SelectOptions == null)
|
||||||
{
|
{
|
||||||
// The SelectOptionItem was already created, now only the SelectOption has to be
|
// The SelectOptionItem was already created, now only the SelectOption has to be
|
||||||
@ -176,6 +177,7 @@ namespace AntDesign
|
|||||||
GroupName = Model.GroupName;
|
GroupName = Model.GroupName;
|
||||||
Value = Model.Value;
|
Value = Model.Value;
|
||||||
Model.ChildComponent = this;
|
Model.ChildComponent = this;
|
||||||
|
isAlreadySelected = IsAlreadySelected(Model);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -194,11 +196,27 @@ namespace AntDesign
|
|||||||
};
|
};
|
||||||
|
|
||||||
SelectParent.SelectOptionItems.Add(newSelectOptionItem);
|
SelectParent.SelectOptionItems.Add(newSelectOptionItem);
|
||||||
|
isAlreadySelected = IsAlreadySelected(newSelectOptionItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetClassMap();
|
SetClassMap();
|
||||||
|
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
if (isAlreadySelected)
|
||||||
|
{
|
||||||
|
await SelectParent.ProcessSelectedSelectOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsAlreadySelected(SelectOptionItem<TItemValue, TItem> selectOption)
|
||||||
|
{
|
||||||
|
if (SelectParent.Mode == "default")
|
||||||
|
{
|
||||||
|
return selectOption.Value.Equals(SelectParent.Value) || selectOption.Value.Equals(SelectParent.LastValueBeforeReset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return SelectParent.Values is null || SelectParent.Values.Contains(selectOption.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SetClassMap()
|
protected void SetClassMap()
|
||||||
|
38
components/select/internal/DataSourceEqualityComparer.cs
Normal file
38
components/select/internal/DataSourceEqualityComparer.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AntDesign
|
||||||
|
{
|
||||||
|
internal class DataSourceEqualityComparer<TItemValue, TItem> : IEqualityComparer<TItem>
|
||||||
|
{
|
||||||
|
private Select<TItemValue, TItem> SelectParent { get; }
|
||||||
|
|
||||||
|
public DataSourceEqualityComparer(Select<TItemValue, TItem> selectParent)
|
||||||
|
{
|
||||||
|
SelectParent = selectParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(TItem x, TItem y)
|
||||||
|
{
|
||||||
|
if (SelectParent._getLabel is null)
|
||||||
|
{
|
||||||
|
if (SelectParent._getValue is null)
|
||||||
|
{
|
||||||
|
return x.ToString().Equals(y.ToString());
|
||||||
|
}
|
||||||
|
return x.ToString().Equals(y.ToString())
|
||||||
|
&& SelectParent._getValue(x).Equals(SelectParent._getValue(y));
|
||||||
|
}
|
||||||
|
if (SelectParent._getValue is null)
|
||||||
|
{
|
||||||
|
return SelectParent._getLabel(x).Equals(SelectParent._getLabel(y));
|
||||||
|
}
|
||||||
|
return SelectParent._getLabel(x).Equals(SelectParent._getLabel(y))
|
||||||
|
&& SelectParent._getValue(x).Equals(SelectParent._getValue(y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(TItem obj)
|
||||||
|
{
|
||||||
|
return obj.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,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> : IDisposable
|
||||||
{
|
{
|
||||||
[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; }
|
||||||
@ -57,7 +57,7 @@ namespace AntDesign.Select.Internal
|
|||||||
[Parameter] public string SearchValue { get; set; }
|
[Parameter] public string SearchValue { get; set; }
|
||||||
[Parameter] public ForwardRef RefBack { get; set; } = new ForwardRef();
|
[Parameter] public ForwardRef RefBack { get; set; } = new ForwardRef();
|
||||||
[Inject] protected IJSRuntime Js { get; set; }
|
[Inject] protected IJSRuntime Js { get; set; }
|
||||||
[Inject] private DomEventService DomEventService { get; set; }
|
[Inject] private IDomEventListener DomEventListener { get; set; }
|
||||||
protected ElementReference Ref
|
protected ElementReference Ref
|
||||||
{
|
{
|
||||||
get { return _ref; }
|
get { return _ref; }
|
||||||
@ -108,7 +108,7 @@ namespace AntDesign.Select.Internal
|
|||||||
{
|
{
|
||||||
if (ParentSelect.EnableSearch)
|
if (ParentSelect.EnableSearch)
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener("window", "beforeunload", Reloading, false);
|
DomEventListener.AddShared<JsonElement>("window", "beforeunload", Reloading);
|
||||||
await Js.InvokeVoidAsync(JSInteropConstants.AddPreventKeys, ParentSelect._inputRef, new[] { "ArrowUp", "ArrowDown" });
|
await Js.InvokeVoidAsync(JSInteropConstants.AddPreventKeys, ParentSelect._inputRef, new[] { "ArrowUp", "ArrowDown" });
|
||||||
await Js.InvokeVoidAsync(JSInteropConstants.AddPreventEnterOnOverlayVisible, ParentSelect._inputRef, ParentSelect._dropDownRef);
|
await Js.InvokeVoidAsync(JSInteropConstants.AddPreventEnterOnOverlayVisible, ParentSelect._inputRef, ParentSelect._dropDownRef);
|
||||||
}
|
}
|
||||||
@ -135,11 +135,11 @@ namespace AntDesign.Select.Internal
|
|||||||
_suffixElement = await Js.InvokeAsync<DomRect>(JSInteropConstants.GetBoundingClientRect, _suffixRef);
|
_suffixElement = await Js.InvokeAsync<DomRect>(JSInteropConstants.GetBoundingClientRect, _suffixRef);
|
||||||
_suffixElement.Width += 7;
|
_suffixElement.Width += 7;
|
||||||
}
|
}
|
||||||
await DomEventService.AddResizeObserver(_overflow, OnOveralyResize);
|
await DomEventListener.AddResizeObserver(_overflow, OnOveralyResize);
|
||||||
await CalculateResponsiveTags();
|
await CalculateResponsiveTags();
|
||||||
}
|
}
|
||||||
DomEventService.AddEventListener(ParentSelect._inputRef, "focusout", OnBlurInternal, true);
|
DomEventListener.AddExclusive<JsonElement>(ParentSelect._inputRef, "focusout", OnBlurInternal);
|
||||||
DomEventService.AddEventListener(ParentSelect._inputRef, "focus", OnFocusInternal, true);
|
DomEventListener.AddExclusive<JsonElement>(ParentSelect._inputRef, "focus", OnFocusInternal);
|
||||||
}
|
}
|
||||||
else if (_currentItemCount != ParentSelect.SelectedOptionItems.Count)
|
else if (_currentItemCount != ParentSelect.SelectedOptionItems.Count)
|
||||||
{
|
{
|
||||||
@ -418,14 +418,12 @@ namespace AntDesign.Select.Internal
|
|||||||
{
|
{
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
if (ParentSelect.IsResponsive)
|
if (ParentSelect.IsResponsive)
|
||||||
await DomEventService.DisposeResizeObserver(_overflow);
|
await DomEventListener.DisposeResizeObserver(_overflow);
|
||||||
await Js.InvokeVoidAsync(JSInteropConstants.RemovePreventKeys, ParentSelect._inputRef);
|
await Js.InvokeVoidAsync(JSInteropConstants.RemovePreventKeys, ParentSelect._inputRef);
|
||||||
await Js.InvokeVoidAsync(JSInteropConstants.RemovePreventEnterOnOverlayVisible, ParentSelect._inputRef);
|
await Js.InvokeVoidAsync(JSInteropConstants.RemovePreventEnterOnOverlayVisible, ParentSelect._inputRef);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(ParentSelect._inputRef, "focus", OnFocusInternal);
|
DomEventListener.Dispose();
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(ParentSelect._inputRef, "focusout", OnBlurInternal);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "beforeunload", Reloading);
|
|
||||||
|
|
||||||
if (IsDisposed) return;
|
if (IsDisposed) return;
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ namespace AntDesign
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
#region Parameters
|
#region Parameters
|
||||||
|
|
||||||
@ -261,8 +261,6 @@ namespace AntDesign
|
|||||||
(double, double) typedValue = DataConvertionExtensions.Convert<TValue, (double, double)>(CurrentValue);
|
(double, double) typedValue = DataConvertionExtensions.Convert<TValue, (double, double)>(CurrentValue);
|
||||||
if (value != typedValue.Item1)
|
if (value != typedValue.Item1)
|
||||||
CurrentValue = DataConvertionExtensions.Convert<(double, double), TValue>((_leftValue, RightValue));
|
CurrentValue = DataConvertionExtensions.Convert<(double, double), TValue>((_leftValue, RightValue));
|
||||||
if (_toolTipLeft != null)
|
|
||||||
_toolTipLeft.ChildElementMoved();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,8 +301,6 @@ namespace AntDesign
|
|||||||
//CurrentValue = DoubleToGeneric(_rightValue);
|
//CurrentValue = DoubleToGeneric(_rightValue);
|
||||||
CurrentValue = DataConvertionExtensions.Convert<double, TValue>(_rightValue);
|
CurrentValue = DataConvertionExtensions.Convert<double, TValue>(_rightValue);
|
||||||
}
|
}
|
||||||
if (_toolTipRight != null)
|
|
||||||
_toolTipRight.ChildElementMoved();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -366,7 +362,7 @@ namespace AntDesign
|
|||||||
/// Set Tooltip display position. Ref Tooltip
|
/// Set Tooltip display position. Ref Tooltip
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public PlacementType TooltipPlacement { get; set; }
|
public Placement TooltipPlacement { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If true, Tooltip will show always, or it will not show anyway, even if dragging or hovering.
|
/// If true, Tooltip will show always, or it will not show anyway, even if dragging or hovering.
|
||||||
@ -404,11 +400,6 @@ namespace AntDesign
|
|||||||
|
|
||||||
#endregion Parameters
|
#endregion Parameters
|
||||||
|
|
||||||
protected override void OnInitialized()
|
|
||||||
{
|
|
||||||
base.OnInitialized();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async override Task SetParametersAsync(ParameterView parameters)
|
public async override Task SetParametersAsync(ParameterView parameters)
|
||||||
{
|
{
|
||||||
await base.SetParametersAsync(parameters);
|
await base.SetParametersAsync(parameters);
|
||||||
@ -460,9 +451,9 @@ namespace AntDesign
|
|||||||
if (!dict.ContainsKey(nameof(TooltipPlacement)))
|
if (!dict.ContainsKey(nameof(TooltipPlacement)))
|
||||||
{
|
{
|
||||||
if (Vertical)
|
if (Vertical)
|
||||||
TooltipPlacement = PlacementType.Right;
|
TooltipPlacement = Placement.Right;
|
||||||
else
|
else
|
||||||
TooltipPlacement = PlacementType.Top;
|
TooltipPlacement = Placement.Top;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,8 +478,8 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener("window", "mousemove", OnMouseMove, false);
|
DomEventListener.AddShared<JsonElement>("window", "mousemove", OnMouseMove);
|
||||||
DomEventService.AddEventListener("window", "mouseup", OnMouseUp, false);
|
DomEventListener.AddShared<JsonElement>("window", "mouseup", OnMouseUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnAfterRender(firstRender);
|
base.OnAfterRender(firstRender);
|
||||||
@ -496,9 +487,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "mousemove", OnMouseMove);
|
DomEventListener.Dispose();
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "mouseup", OnMouseUp);
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,11 +498,9 @@ namespace AntDesign
|
|||||||
if (_toolTipRight != null && HasTooltip)
|
if (_toolTipRight != null && HasTooltip)
|
||||||
{
|
{
|
||||||
_rightHandle = _toolTipRight.Ref;
|
_rightHandle = _toolTipRight.Ref;
|
||||||
await _toolTipRight.ChildElementMoved();
|
|
||||||
if (_toolTipLeft != null)
|
if (_toolTipLeft != null)
|
||||||
{
|
{
|
||||||
_leftHandle = _toolTipLeft.Ref;
|
_leftHandle = _toolTipLeft.Ref;
|
||||||
await _toolTipLeft.ChildElementMoved();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,5 +106,11 @@ namespace AntDesign
|
|||||||
_isLoading = Spinning;
|
_isLoading = Spinning;
|
||||||
InvokeAsync(StateHasChanged);
|
InvokeAsync(StateHasChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
_delayTimer?.Dispose();
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,72 +1,89 @@
|
|||||||
@namespace AntDesign
|
@namespace AntDesign
|
||||||
|
@using AntDesign.TableModels
|
||||||
@inherits ColumnBase
|
@inherits ColumnBase
|
||||||
|
|
||||||
@if (IsInitialize)
|
@if (IsInitialize)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (IsPlaceholder)
|
else if (IsPlaceholder)
|
||||||
{
|
{
|
||||||
<td style="padding: 0px; border: 0px; height: 0px;"></td>
|
<td style="padding: 0px; border: 0px; height: 0px;"></td>
|
||||||
}
|
}
|
||||||
else if (IsMeasure)
|
else if (IsMeasure)
|
||||||
{
|
{
|
||||||
<td style="padding: 0px; border: 0px; height: 0px;"><div style="height: 0px; overflow: hidden;"> </div></td>
|
<td style="padding: 0px; border: 0px; height: 0px;"><div style="height: 0px; overflow: hidden;"> </div></td>
|
||||||
}
|
}
|
||||||
else if (IsColGroup)
|
else if (IsColGroup)
|
||||||
{
|
{
|
||||||
@if (AppendExpandColumn)
|
@if (AppendExpandColumn)
|
||||||
{
|
{
|
||||||
<col class="ant-table-expand-icon-col">
|
<col class="ant-table-expand-icon-col">
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Width != null)
|
if (Width != null)
|
||||||
{
|
{
|
||||||
<col style="width: @((CssSizeLength)Width); min-width: @((CssSizeLength)Width);">
|
<col style="width: @((CssSizeLength)Width); min-width: @((CssSizeLength)Width);">
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<col />
|
<col />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsHeader && HeaderColSpan != 0)
|
else if (IsHeader && HeaderColSpan != 0)
|
||||||
{
|
{
|
||||||
@if (AppendExpandColumn)
|
@if (AppendExpandColumn)
|
||||||
{
|
{
|
||||||
<th class="ant-table-cell ant-table-row-expand-icon-cell"></th>
|
<th class="ant-table-cell ant-table-row-expand-icon-cell"></th>
|
||||||
}
|
}
|
||||||
|
|
||||||
<th class="@ClassMapper.Class" style="@FixedStyle @HeaderStyle" colspan="@HeaderColSpan">
|
<th class="@ClassMapper.Class" style="@FixedStyle @HeaderStyle" colspan="@HeaderColSpan">
|
||||||
@if (TitleTemplate != null)@TitleTemplate else @Title
|
@if (TitleTemplate != null)
|
||||||
</th>
|
{
|
||||||
|
@TitleTemplate
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@Title
|
||||||
|
}
|
||||||
|
</th>
|
||||||
}
|
}
|
||||||
else if (!IsHeader && RowSpan != 0 && ColSpan != 0)
|
else if (!IsHeader && RowSpan != 0 && ColSpan != 0)
|
||||||
{
|
{
|
||||||
@if (AppendExpandColumn)
|
@if (AppendExpandColumn)
|
||||||
{
|
{
|
||||||
<td class="ant-table-cell ant-table-row-expand-icon-cell">
|
<td class="ant-table-cell ant-table-row-expand-icon-cell">
|
||||||
@if (Table.RowExpandable(RowData) && (!Table.TreeMode || !RowData.HasChildren))
|
@if (Table.RowExpandable(RowData) && (!Table.TreeMode || !RowData.HasChildren))
|
||||||
{
|
{
|
||||||
<button type="button" @onclick="ToggleTreeNode"
|
<button type="button" @onclick="ToggleTreeNode"
|
||||||
class="ant-table-row-expand-icon @(RowData.Expanded?"ant-table-row-expand-icon-expanded":"ant-table-row-expand-icon-collapsed")"
|
class="ant-table-row-expand-icon @(RowData.Expanded?"ant-table-row-expand-icon-expanded":"ant-table-row-expand-icon-collapsed")"
|
||||||
aria-label="@(RowData.Expanded?Table.Locale.Collapse:Table.Locale.Expand)"></button>
|
aria-label="@(RowData.Expanded?Table.Locale.Collapse:Table.Locale.Expand)"></button>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
|
|
||||||
<td class="@ClassMapper.Class" style="@FixedStyle @Style" rowspan="@RowSpan" colspan="@ColSpan" data-label="@Context.HeaderColumns[ColIndex].Title">
|
<td class="@ClassMapper.Class" style="@FixedStyle @Style" rowspan="@RowSpan" colspan="@ColSpan" data-label="@Context.HeaderColumns[ColIndex].Title">
|
||||||
@if (ColIndex == Table.TreeExpandIconColumnIndex && Table.TreeMode)
|
@if (ColIndex == Table.TreeExpandIconColumnIndex && Table.TreeMode)
|
||||||
{
|
{
|
||||||
<span class="ant-table-row-indent indent-level-@RowData.Level" style="padding-left: @((CssSizeLength)(RowData.Level * Table.IndentSize));"></span>
|
<span class="ant-table-row-indent indent-level-@RowData.Level" style="padding-left: @((CssSizeLength)(RowData.Level * Table.IndentSize));"></span>
|
||||||
@if (RowData.HasChildren)
|
@if (RowData.HasChildren)
|
||||||
{
|
{
|
||||||
<button type="button" @onclick="ToggleTreeNode" class="ant-table-row-expand-icon @(RowData?.Expanded==true?"ant-table-row-expand-icon-expanded":"ant-table-row-expand-icon-collapsed")" aria-label="@(RowData?.Expanded==true?Table.Locale.Collapse:Table.Locale.Expand)"></button>
|
<button type="button" @onclick="ToggleTreeNode" class="ant-table-row-expand-icon @(RowData?.Expanded==true?"ant-table-row-expand-icon-expanded":"ant-table-row-expand-icon-collapsed")" aria-label="@(RowData?.Expanded==true?Table.Locale.Collapse:Table.Locale.Expand)"></button>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<button type="button" class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced" aria-label="@Table.Locale.Expand"></button>
|
<button type="button" class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced" aria-label="@Table.Locale.Expand"></button>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ChildContent
|
|
||||||
</td>
|
@if (CellRender != null)
|
||||||
|
{
|
||||||
|
var cellData = new CellData(RowData);
|
||||||
|
@CellRender(cellData)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@ChildContent
|
||||||
|
}
|
||||||
|
</td>
|
||||||
}
|
}
|
@ -8,386 +8,404 @@
|
|||||||
|
|
||||||
@if (IsInitialize)
|
@if (IsInitialize)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (Hidden)
|
else if (Hidden)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (IsPlaceholder)
|
else if (IsPlaceholder)
|
||||||
{
|
{
|
||||||
<td style="padding: 0px; border: 0px; height: 0px;"></td>
|
<td style="padding: 0px; border: 0px; height: 0px;"></td>
|
||||||
}
|
}
|
||||||
else if (IsMeasure)
|
else if (IsMeasure)
|
||||||
{
|
{
|
||||||
<td style="padding: 0px; border: 0px; height: 0px;"><div style="height: 0px; overflow: hidden;"> </div></td>
|
<td style="padding: 0px; border: 0px; height: 0px;"><div style="height: 0px; overflow: hidden;"> </div></td>
|
||||||
}
|
}
|
||||||
else if (IsColGroup)
|
else if (IsColGroup)
|
||||||
{
|
{
|
||||||
@if (AppendExpandColumn)
|
@if (AppendExpandColumn)
|
||||||
{
|
{
|
||||||
<col class="ant-table-expand-icon-col">
|
<col class="ant-table-expand-icon-col">
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Width != null)
|
if (Width != null)
|
||||||
{
|
{
|
||||||
<col style="width: @((CssSizeLength)Width); min-width: @((CssSizeLength)Width);">
|
<col style="width: @((CssSizeLength)Width); min-width: @((CssSizeLength)Width);">
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<col />
|
<col />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsHeader && HeaderColSpan != 0)
|
else if (IsHeader && HeaderColSpan != 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
@if (AppendExpandColumn)
|
@if (AppendExpandColumn)
|
||||||
{
|
{
|
||||||
<th class="ant-table-cell ant-table-row-expand-icon-cell"></th>
|
<th class="ant-table-cell ant-table-row-expand-icon-cell"></th>
|
||||||
}
|
}
|
||||||
|
|
||||||
var headerCellAttributes = OnHeaderCell?.Invoke();
|
var headerCellAttributes = OnHeaderCell?.Invoke();
|
||||||
<CascadingValue Name="IsHeader" Value="false" IsFixed>
|
<CascadingValue Name="IsHeader" Value="false" IsFixed>
|
||||||
<th class="@ClassMapper.Class" style="@FixedStyle @HeaderStyle" colspan="@(HeaderColSpan > 1 ? HeaderColSpan : false)" title="@(Ellipsis ? Title : false)" @attributes="headerCellAttributes">
|
<th class="@ClassMapper.Class" style="@FixedStyle @HeaderStyle" colspan="@(HeaderColSpan > 1 ? HeaderColSpan : false)" title="@(Ellipsis ? HeaderTitle : false)" @attributes="headerCellAttributes">
|
||||||
@if (Sortable || (_filterable && _filters?.Any() == true))
|
@if (Sortable || (_filterable && _filters?.Any() == true))
|
||||||
{
|
{
|
||||||
@FilterToolTipSorter
|
@FilterToolTipSorter
|
||||||
}
|
}
|
||||||
else if (TitleTemplate != null)
|
else if (TitleTemplate != null)
|
||||||
{
|
{
|
||||||
@TitleTemplate
|
@TitleTemplate
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@Title
|
@HeaderTitle
|
||||||
}
|
}
|
||||||
</th>
|
</th>
|
||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
}
|
}
|
||||||
else if (IsBody && RowSpan != 0 && ColSpan != 0)
|
else if (IsBody && RowSpan != 0 && ColSpan != 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
var fieldText = !string.IsNullOrWhiteSpace(Format) ? Formatter<TData>.Format(Field, Format) : Field?.ToString();
|
var fieldText = !string.IsNullOrWhiteSpace(Format) ? Formatter<TData>.Format(Field, Format) : Field?.ToString();
|
||||||
|
|
||||||
@if (AppendExpandColumn)
|
@if (AppendExpandColumn)
|
||||||
{
|
{
|
||||||
<td class="ant-table-cell ant-table-row-expand-icon-cell">
|
<td class="ant-table-cell ant-table-row-expand-icon-cell">
|
||||||
@if (Table.RowExpandable(RowData) && (!Table.TreeMode || !RowData.HasChildren))
|
@if (Table.RowExpandable(RowData) && (!Table.TreeMode || !RowData.HasChildren))
|
||||||
{
|
{
|
||||||
<button type="button" @onclick="ToggleTreeNode" @onclick:stopPropagation
|
<button type="button" @onclick="ToggleTreeNode" @onclick:stopPropagation
|
||||||
class="ant-table-row-expand-icon @(RowData.Expanded ? "ant-table-row-expand-icon-expanded" : "ant-table-row-expand-icon-collapsed")"
|
class="ant-table-row-expand-icon @(RowData.Expanded ? "ant-table-row-expand-icon-expanded" : "ant-table-row-expand-icon-collapsed")"
|
||||||
aria-label="@(RowData.Expanded ? Table.Locale.Collapse : Table.Locale.Expand)"></button>
|
aria-label="@(RowData.Expanded ? Table.Locale.Collapse : Table.Locale.Expand)"></button>
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
|
var cellData = new CellData(RowData);
|
||||||
|
var cellAttributes = OnCell?.Invoke(cellData);
|
||||||
|
<CascadingValue Name="IsBody" Value="false" IsFixed>
|
||||||
|
<td class="@ClassMapper.Class" style="@FixedStyle @Style" rowspan="@RowSpan" colspan="@ColSpan" title="@(Ellipsis ? fieldText : false)" @attributes="cellAttributes">
|
||||||
|
@if (ColIndex == Table.TreeExpandIconColumnIndex && Table.TreeMode)
|
||||||
|
{
|
||||||
|
<span class="ant-table-row-indent indent-level-@RowData.Level" style="padding-left: @((CssSizeLength)(RowData.Level * Table.IndentSize));"></span>
|
||||||
|
@if (RowData.HasChildren)
|
||||||
|
{
|
||||||
|
<button type="button" @onclick="ToggleTreeNode" @onclick:stopPropagation class="ant-table-row-expand-icon @(RowData?.Expanded == true ? "ant-table-row-expand-icon-expanded" : "ant-table-row-expand-icon-collapsed")" aria-label="@(RowData?.Expanded == true ? Table.Locale.Collapse : Table.Locale.Expand)"></button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="button" class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced" aria-label="@Table.Locale.Expand"></button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var cellAttributes = OnCell?.Invoke(RowData);
|
@if (CellRender != null)
|
||||||
<CascadingValue Name="IsBody" Value="false" IsFixed>
|
{
|
||||||
<td class="@ClassMapper.Class" style="@FixedStyle @Style" rowspan="@RowSpan" colspan="@ColSpan" title="@(Ellipsis ? fieldText : false)" @attributes="cellAttributes">
|
@CellRender(cellData)
|
||||||
@if (ColIndex == Table.TreeExpandIconColumnIndex && Table.TreeMode)
|
}
|
||||||
{
|
else if (ChildContent != null)
|
||||||
<span class="ant-table-row-indent indent-level-@RowData.Level" style="padding-left: @((CssSizeLength)(RowData.Level * Table.IndentSize));"></span>
|
{
|
||||||
@if (RowData.HasChildren)
|
@ChildContent
|
||||||
{
|
}
|
||||||
<button type="button" @onclick="ToggleTreeNode" @onclick:stopPropagation class="ant-table-row-expand-icon @(RowData?.Expanded == true ? "ant-table-row-expand-icon-expanded" : "ant-table-row-expand-icon-collapsed")" aria-label="@(RowData?.Expanded == true ? Table.Locale.Collapse : Table.Locale.Expand)"></button>
|
else
|
||||||
}
|
{
|
||||||
else
|
if (!string.IsNullOrWhiteSpace(Format))
|
||||||
{
|
{
|
||||||
<button type="button" class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced" aria-label="@Table.Locale.Expand"></button>
|
@(Formatter<TData>.Format(Field, Format))
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
@if (CellRender != null)
|
@Field
|
||||||
{
|
}
|
||||||
@CellRender(Field)
|
}
|
||||||
}
|
</td>
|
||||||
else if (ChildContent != null)
|
</CascadingValue>
|
||||||
{
|
|
||||||
@ChildContent
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(Format))
|
|
||||||
{
|
|
||||||
@(Formatter<TData>.Format(Field, Format))
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@Field
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</CascadingValue>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
|
string HeaderTitle => Title ?? DisplayName ?? FieldName;
|
||||||
|
|
||||||
RenderFragment SortHeader =>
|
RenderFragment SortHeader =>
|
||||||
@<Template>
|
@<Template>
|
||||||
<span>
|
<span>
|
||||||
@if (TitleTemplate != null) @TitleTemplate else @Title
|
@if (TitleTemplate != null)
|
||||||
</span>
|
{
|
||||||
@{
|
@TitleTemplate
|
||||||
bool hasDescendingSorter = SortDirection.Descending.IsIn(SortDirections);
|
}
|
||||||
bool hasAscendingSorter = SortDirection.Ascending.IsIn(SortDirections);
|
else
|
||||||
}
|
{
|
||||||
<span class="ant-table-column-sorter@(hasDescendingSorter && hasAscendingSorter ? " ant-table-column-sorter-full" : "")">
|
@HeaderTitle
|
||||||
<span class="ant-table-column-sorter-inner">
|
}
|
||||||
@if (hasAscendingSorter)
|
</span>
|
||||||
{
|
@{
|
||||||
<Icon Type="caret-up" Class=@($"ant-table-column-sorter-up{(_sortDirection == SortDirection.Ascending ? " active" : "")}") />
|
bool hasDescendingSorter = SortDirection.Descending.IsIn(SortDirections);
|
||||||
}
|
bool hasAscendingSorter = SortDirection.Ascending.IsIn(SortDirections);
|
||||||
@if (hasDescendingSorter)
|
}
|
||||||
{
|
<span class="ant-table-column-sorter@(hasDescendingSorter && hasAscendingSorter ? " ant-table-column-sorter-full" : "")">
|
||||||
<Icon Type="caret-down" Class=@($"ant-table-column-sorter-down{(_sortDirection == SortDirection.Descending ? " active" : "")}") />
|
<span class="ant-table-column-sorter-inner">
|
||||||
}
|
@if (hasAscendingSorter)
|
||||||
</span>
|
{
|
||||||
</span>
|
<Icon Type="caret-up" Class=@($"ant-table-column-sorter-up{(_sortDirection == SortDirection.Ascending ? " active" : "")}") />
|
||||||
</Template>;
|
}
|
||||||
|
@if (hasDescendingSorter)
|
||||||
|
{
|
||||||
|
<Icon Type="caret-down" Class=@($"ant-table-column-sorter-down{(_sortDirection == SortDirection.Descending ? " active" : "")}") />
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</Template>
|
||||||
|
;
|
||||||
|
|
||||||
RenderFragment ToolTipSorter =>
|
RenderFragment ToolTipSorter =>
|
||||||
@<Template>
|
@<Template>
|
||||||
@if (ShowSorterTooltip)
|
@if (ShowSorterTooltip)
|
||||||
{
|
{
|
||||||
<Tooltip Title="@SorterTooltip">
|
<Tooltip Title="@SorterTooltip">
|
||||||
<Unbound>
|
<Unbound>
|
||||||
<div class="ant-table-column-sorters" @ref="context.Current" @onclick="HandleSort">
|
<div class="ant-table-column-sorters" @ref="context.Current" @onclick="HandleSort">
|
||||||
@SortHeader
|
@SortHeader
|
||||||
</div>
|
</div>
|
||||||
</Unbound>
|
</Unbound>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="ant-table-column-sorters" @onclick="HandleSort">
|
<div class="ant-table-column-sorters" @onclick="HandleSort">
|
||||||
@SortHeader
|
@SortHeader
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</Template>;
|
</Template>
|
||||||
|
;
|
||||||
|
|
||||||
RenderFragment FilterToolTipSorter =>
|
RenderFragment FilterToolTipSorter =>
|
||||||
@<Template>
|
@<Template>
|
||||||
@if (_filterable && _filters?.Any() == true)
|
@if (_filterable && _filters?.Any() == true)
|
||||||
{
|
{
|
||||||
<div class="ant-table-filter-column">
|
<div class="ant-table-filter-column">
|
||||||
@if (Sortable)
|
@if (Sortable)
|
||||||
{
|
{
|
||||||
@ToolTipSorter
|
@ToolTipSorter
|
||||||
}
|
}
|
||||||
else if (TitleTemplate != null)
|
else if (TitleTemplate != null)
|
||||||
{
|
{
|
||||||
@TitleTemplate
|
@TitleTemplate
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@Title
|
@HeaderTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
<Dropdown Trigger="new[] { TriggerType.Click }" Visible="_filterOpened" Placement="PlacementType.BottomRight" OnMaskClick="() => { if (_filterOpened) FilterConfirm(); }">
|
<Dropdown Trigger="new[] { Trigger.Click }" Visible="_filterOpened" Placement="Placement.BottomRight" OnMaskClick="() => { if (_filterOpened) FilterConfirm(); }">
|
||||||
<Unbound>
|
<Unbound>
|
||||||
<span @ref="context.Current" role="button" tabindex="-1" class="ant-dropdown-trigger ant-table-filter-trigger@((_filterOpened ? " ant-dropdown-open" : "") + (_hasFilterSelected ? " active" : ""))"
|
<span @ref="context.Current" role="button" tabindex="-1" class="ant-dropdown-trigger ant-table-filter-trigger@((_filterOpened ? " ant-dropdown-open" : "") + (_hasFilterSelected ? " active" : ""))"
|
||||||
@onclick="() => { if (_filterOpened) FilterConfirm(); else _filterOpened = true; }">
|
@onclick="() => { if (_filterOpened) FilterConfirm(); else _filterOpened = true; }">
|
||||||
<Icon Type="filter" Theme="fill" />
|
<Icon Type="filter" Theme="fill" />
|
||||||
</span>
|
</span>
|
||||||
</Unbound>
|
</Unbound>
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<div class="ant-table-filter-dropdown">
|
<div class="ant-table-filter-dropdown">
|
||||||
@if (_filters?.Any() == true && _columnFilterType == TableFilterType.List)
|
@if (_filters?.Any() == true && _columnFilterType == TableFilterType.List)
|
||||||
{
|
{
|
||||||
<Menu AutoCloseDropdown="false" SelectedKeys="_selectedFilterValues">
|
<Menu AutoCloseDropdown="false" SelectedKeys="_selectedFilterValues">
|
||||||
@foreach (var filter in _filters)
|
@foreach (var filter in _filters)
|
||||||
{
|
{
|
||||||
<MenuItem Key="@filter.Value?.ToString()" OnClick="() => FilterSelected(filter)">
|
<MenuItem Key="@filter.Value?.ToString()" OnClick="() => FilterSelected(filter)">
|
||||||
@if (FilterMultiple)
|
@if (FilterMultiple)
|
||||||
{
|
{
|
||||||
<Checkbox Value="filter.Selected" ValueChanged="value => FilterSelected(filter)">@filter.Text</Checkbox>
|
<Checkbox Value="filter.Selected" ValueChanged="value => FilterSelected(filter)">@filter.Text</Checkbox>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<Radio TValue="bool" Checked="filter.Selected" CheckedChanged="value => FilterSelected(filter)">@filter.Text</Radio>
|
<Radio TValue="bool" Checked="filter.Selected" CheckedChanged="value => FilterSelected(filter)">@filter.Text</Radio>
|
||||||
}
|
}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
}
|
}
|
||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div id="@("popup-container-for-" + Id)" style="position:relative!important"></div>
|
<div id="@("popup-container-for-" + Id)" style="position:relative!important"></div>
|
||||||
int filterCount = _filters.Count();
|
int filterCount = _filters.Count();
|
||||||
@for (int index = 0; index < filterCount; index++)
|
@for (int index = 0; index < filterCount; index++)
|
||||||
{
|
{
|
||||||
var filter = _filters.ElementAt(index);
|
var filter = _filters.ElementAt(index);
|
||||||
var noInput = filter.FilterCompareOperator == TableFilterCompareOperator.IsNull || filter.FilterCompareOperator == TableFilterCompareOperator.IsNotNull;
|
var noInput = filter.FilterCompareOperator == TableFilterCompareOperator.IsNull || filter.FilterCompareOperator == TableFilterCompareOperator.IsNotNull;
|
||||||
<div @key="filter" style="padding:10px;min-width:150px;@(index > 0 ? "border-top:1px solid #f0f0f0" : "")">
|
<div @key="filter" style="padding:10px;min-width:150px;@(index > 0 ? "border-top:1px solid #f0f0f0" : "")">
|
||||||
@if (index > 0)
|
@if (index > 0)
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
<Space Style="margin-bottom:10px">
|
<Space Style="margin-bottom:10px">
|
||||||
<SpaceItem>
|
<SpaceItem>
|
||||||
<Select Value="filter.FilterCondition" TItemValue="TableFilterCondition" TItem="TableFilterCondition" ValueChanged="value => SetFilterCondition(filter,value)" PopupContainerSelector="@("#popup-container-for-" + Id)">
|
<Select Value="filter.FilterCondition" TItemValue="TableFilterCondition" TItem="TableFilterCondition" ValueChanged="value => SetFilterCondition(filter,value)" PopupContainerSelector="@("#popup-container-for-" + Id)" BoundaryAdjustMode="@TriggerBoundaryAdjustMode.None">
|
||||||
<SelectOptions>
|
<SelectOptions>
|
||||||
<SelectOption TItem="TableFilterCondition" TItemValue="TableFilterCondition" Value="@TableFilterCondition.And" Label="@Table?.Locale.FilterOptions.And"></SelectOption>
|
<SelectOption TItem="TableFilterCondition" TItemValue="TableFilterCondition" Value="@TableFilterCondition.And" Label="@Table?.Locale.FilterOptions.And"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCondition" TItemValue="TableFilterCondition" Value="@TableFilterCondition.Or" Label="@Table?.Locale.FilterOptions.Or"></SelectOption>
|
<SelectOption TItem="TableFilterCondition" TItemValue="TableFilterCondition" Value="@TableFilterCondition.Or" Label="@Table?.Locale.FilterOptions.Or"></SelectOption>
|
||||||
</SelectOptions>
|
</SelectOptions>
|
||||||
</Select>
|
</Select>
|
||||||
</SpaceItem>
|
</SpaceItem>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<Space Style="width:100%;">
|
<Space Style="width:100%;">
|
||||||
<SpaceItem Style="flex:auto">
|
<SpaceItem Style="flex:auto">
|
||||||
<Select Value="filter.FilterCompareOperator" TItemValue="TableFilterCompareOperator" TItem="TableFilterCompareOperator" Style="width: 100%; overflow: visible" ValueChanged="value => SetFilterCompareOperator(filter,value)" PopupContainerSelector="@("#popup-container-for-" + Id)" DropdownMatchSelectWidth="false">
|
<Select Value="filter.FilterCompareOperator" TItemValue="TableFilterCompareOperator" TItem="TableFilterCompareOperator" Style="width: 100%; overflow: visible" ValueChanged="value => SetFilterCompareOperator(filter,value)" PopupContainerSelector="@("#popup-container-for-" + Id)" BoundaryAdjustMode="@TriggerBoundaryAdjustMode.None" DropdownMatchSelectWidth="false">
|
||||||
<SelectOptions>
|
<SelectOptions>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.Equals" Label="@Table?.Locale.FilterOptions.Equals"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.Equals" Label="@Table?.Locale.FilterOptions.Equals"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.NotEquals" Label="@Table?.Locale.FilterOptions.NotEquals"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.NotEquals" Label="@Table?.Locale.FilterOptions.NotEquals"></SelectOption>
|
||||||
@if (_columnDataType == typeof(string))
|
@if (_columnDataType == typeof(string))
|
||||||
{
|
{
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.Contains" Label="@Table?.Locale.FilterOptions.Contains"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.Contains" Label="@Table?.Locale.FilterOptions.Contains"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.StartsWith" Label="@Table?.Locale.FilterOptions.StartsWith"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.StartsWith" Label="@Table?.Locale.FilterOptions.StartsWith"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.EndsWith" Label="@Table?.Locale.FilterOptions.EndsWith"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.EndsWith" Label="@Table?.Locale.FilterOptions.EndsWith"></SelectOption>
|
||||||
}
|
}
|
||||||
else if (_columnDataType.IsEnum)
|
else if (_columnDataType.IsEnum)
|
||||||
{
|
{
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.Contains" Label="@Table?.Locale.FilterOptions.Contains"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.Contains" Label="@Table?.Locale.FilterOptions.Contains"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.NotContains" Label="@Table?.Locale.FilterOptions.NotContains"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.NotContains" Label="@Table?.Locale.FilterOptions.NotContains"></SelectOption>
|
||||||
}
|
}
|
||||||
else if (_columnDataType == typeof(DateTime))
|
else if (_columnDataType == typeof(DateTime))
|
||||||
{
|
{
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.GreaterThan" Label="@Table?.Locale.FilterOptions.GreaterThan"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.GreaterThan" Label="@Table?.Locale.FilterOptions.GreaterThan"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.LessThan" Label="@Table?.Locale.FilterOptions.LessThan"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.LessThan" Label="@Table?.Locale.FilterOptions.LessThan"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.GreaterThanOrEquals" Label="@Table?.Locale.FilterOptions.GreaterThanOrEquals"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.GreaterThanOrEquals" Label="@Table?.Locale.FilterOptions.GreaterThanOrEquals"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.LessThanOrEquals" Label="@Table?.Locale.FilterOptions.LessThanOrEquals"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.LessThanOrEquals" Label="@Table?.Locale.FilterOptions.LessThanOrEquals"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.TheSameDateWith" Label="@Table?.Locale.FilterOptions.TheSameDateWith"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.TheSameDateWith" Label="@Table?.Locale.FilterOptions.TheSameDateWith"></SelectOption>
|
||||||
}
|
}
|
||||||
else if (_columnDataType == typeof(Guid)) { }
|
else if (_columnDataType == typeof(Guid)) { }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.GreaterThan" Label="@Table?.Locale.FilterOptions.GreaterThan"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.GreaterThan" Label="@Table?.Locale.FilterOptions.GreaterThan"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.LessThan" Label="@Table?.Locale.FilterOptions.LessThan"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.LessThan" Label="@Table?.Locale.FilterOptions.LessThan"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.GreaterThanOrEquals" Label="@Table?.Locale.FilterOptions.GreaterThanOrEquals"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.GreaterThanOrEquals" Label="@Table?.Locale.FilterOptions.GreaterThanOrEquals"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.LessThanOrEquals" Label="@Table?.Locale.FilterOptions.LessThanOrEquals"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.LessThanOrEquals" Label="@Table?.Locale.FilterOptions.LessThanOrEquals"></SelectOption>
|
||||||
}
|
}
|
||||||
@if (THelper.IsTypeNullable<TData>() || _columnDataType == typeof(string))
|
@if (THelper.IsTypeNullable<TData>() || _columnDataType == typeof(string))
|
||||||
{
|
{
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.IsNull" Label="@Table?.Locale.FilterOptions.IsNull"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.IsNull" Label="@Table?.Locale.FilterOptions.IsNull"></SelectOption>
|
||||||
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.IsNotNull" Label="@Table?.Locale.FilterOptions.IsNotNull"></SelectOption>
|
<SelectOption TItem="TableFilterCompareOperator" TItemValue="TableFilterCompareOperator" Value="@TableFilterCompareOperator.IsNotNull" Label="@Table?.Locale.FilterOptions.IsNotNull"></SelectOption>
|
||||||
}
|
}
|
||||||
</SelectOptions>
|
</SelectOptions>
|
||||||
</Select>
|
</Select>
|
||||||
</SpaceItem>
|
</SpaceItem>
|
||||||
@if (!noInput)
|
@if (!noInput)
|
||||||
{
|
{
|
||||||
<SpaceItem>
|
<SpaceItem>
|
||||||
@FilterInput(filter)
|
@FilterInput(filter)
|
||||||
</SpaceItem>
|
</SpaceItem>
|
||||||
}
|
}
|
||||||
@if (filterCount > 1)
|
@if (filterCount > 1)
|
||||||
{
|
{
|
||||||
<SpaceItem>
|
<SpaceItem>
|
||||||
<Button Size="small" Icon="close" Type="primary" OnClick="()=> RemoveFilter(filter)">
|
<Button Size="small" Icon="close" Type="primary" OnClick="()=> RemoveFilter(filter)">
|
||||||
</Button>
|
</Button>
|
||||||
</SpaceItem>
|
</SpaceItem>
|
||||||
}
|
}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<div class="ant-table-filter-dropdown-btns">
|
<div class="ant-table-filter-dropdown-btns">
|
||||||
<Button Size="small" Type="link" OnClick="ResetFilters">
|
<Button Size="small" Type="link" OnClick="ResetFilters">
|
||||||
@Table?.Locale.FilterReset
|
@Table?.Locale.FilterReset
|
||||||
</Button>
|
</Button>
|
||||||
@if (_columnFilterType == TableFilterType.FieldType)
|
@if (_columnFilterType == TableFilterType.FieldType)
|
||||||
{
|
{
|
||||||
<Button Size="small" Icon="plus" Type="primary" OnClick="AddFilter">
|
<Button Size="small" Icon="plus" Type="primary" OnClick="AddFilter">
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
<Button Size="small" Type="primary" OnClick="() => FilterConfirm()">
|
<Button Size="small" Type="primary" OnClick="() => FilterConfirm()">
|
||||||
@Table?.Locale.FilterConfirm
|
@Table?.Locale.FilterConfirm
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ToolTipSorter
|
@ToolTipSorter
|
||||||
}
|
}
|
||||||
</Template>;
|
</Template>
|
||||||
|
;
|
||||||
|
|
||||||
RenderFragment<TableFilter> FilterInput => filter =>
|
RenderFragment<TableFilter> FilterInput => filter =>
|
||||||
@<Template>
|
@<Template>
|
||||||
@if (_columnDataType == typeof(DateTime))
|
@if (_columnDataType == typeof(DateTime))
|
||||||
{
|
{
|
||||||
if (filter.FilterCompareOperator != TableFilterCompareOperator.TheSameDateWith)
|
if (filter.FilterCompareOperator != TableFilterCompareOperator.TheSameDateWith)
|
||||||
{
|
{
|
||||||
<DatePicker Value="(DateTime?)filter.Value" ShowTime="@true"
|
<DatePicker Value="(DateTime?)filter.Value" ShowTime="@true"
|
||||||
TValue="DateTime?" ValueChanged="value => SetFilterValue(filter, value?.AddMilliseconds(-value.Value.Millisecond))" PopupContainerSelector="@("#popup-container-for-" + Id)"></DatePicker>
|
TValue="DateTime?" ValueChanged="value => SetFilterValue(filter, value?.AddMilliseconds(-value.Value.Millisecond))"
|
||||||
}
|
PopupContainerSelector="@("#popup-container-for-" + Id)"
|
||||||
else
|
BoundaryAdjustMode="@TriggerBoundaryAdjustMode.None"/>
|
||||||
{
|
}
|
||||||
<DatePicker Value="(DateTime?)filter.Value" TValue="DateTime?" ValueChanged="value => SetFilterValue(filter, value)" PopupContainerSelector="@("#popup-container-for-" + Id)"></DatePicker>
|
else
|
||||||
}
|
{
|
||||||
}
|
<DatePicker Value="(DateTime?)filter.Value" TValue="DateTime?" ValueChanged="value => SetFilterValue(filter, value)"
|
||||||
else if (_columnDataType.IsEnum)
|
PopupContainerSelector="@("#popup-container-for-" + Id)"
|
||||||
{
|
BoundaryAdjustMode="@TriggerBoundaryAdjustMode.None"/>
|
||||||
<EnumSelect TEnum="TData" Mode="multiple" Values="EnumHelper<TData>.Split(filter.Value)" PopupContainerSelector="@("#popup-container-for-" + Id)"
|
}
|
||||||
Style="width:180px;" ValuesChanged="value => SetFilterValue(filter, EnumHelper<TData>.Combine(value))">
|
}
|
||||||
</EnumSelect>
|
else if (_columnDataType.IsEnum)
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(byte))
|
<EnumSelect TEnum="TData" Mode="multiple" Values="EnumHelper<TData>.Split(filter.Value)"
|
||||||
{
|
PopupContainerSelector="@("#popup-container-for-" + Id)"
|
||||||
<InputNumber Value="(byte?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="byte?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
Style="width:180px;"
|
||||||
}
|
ValuesChanged="value => SetFilterValue(filter, EnumHelper<TData>.Combine(value))"
|
||||||
else if (_columnDataType == typeof(decimal))
|
BoundaryAdjustMode="@TriggerBoundaryAdjustMode.None"/>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(decimal?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="decimal?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(byte))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(double))
|
<InputNumber Value="(byte?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="byte?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(double?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="double?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(decimal))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(short))
|
<InputNumber Value="(decimal?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="decimal?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(short?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="short?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(double))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(int))
|
<InputNumber Value="(double?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="double?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(int?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="int?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(short))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(long))
|
<InputNumber Value="(short?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="short?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(long?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="long?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(int))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(sbyte))
|
<InputNumber Value="(int?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="int?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(sbyte?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="sbyte?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(long))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(float))
|
<InputNumber Value="(long?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="long?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(float?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="float?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(sbyte))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(ushort))
|
<InputNumber Value="(sbyte?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="sbyte?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(ushort?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="ushort?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(float))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(uint))
|
<InputNumber Value="(float?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="float?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(uint?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="uint?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(ushort))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(ulong))
|
<InputNumber Value="(ushort?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="ushort?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<InputNumber Value="(ulong?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="ulong?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
else if (_columnDataType == typeof(uint))
|
||||||
}
|
{
|
||||||
else if (_columnDataType == typeof(Guid))
|
<InputNumber Value="(uint?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="uint?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<Input Value="(Guid?)filter.Value" TValue="Guid?" ValueChanged="value => SetFilterValue(filter, value)" />
|
else if (_columnDataType == typeof(ulong))
|
||||||
}
|
{
|
||||||
else
|
<InputNumber Value="(ulong?)filter.Value" Formatter="number => NumberFormatter(number)" TValue="ulong?" ValueChanged="value => SetFilterValue(filter, value)"></InputNumber>
|
||||||
{
|
}
|
||||||
<Input TValue="TData" Value="(TData)filter.Value" ValueChanged="value => SetFilterValue(filter, value)" />
|
else if (_columnDataType == typeof(Guid))
|
||||||
}
|
{
|
||||||
</Template>;
|
<Input Value="(Guid?)filter.Value" TValue="Guid?" ValueChanged="value => SetFilterValue(filter, value)" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<Input TValue="TData" Value="(TData)filter.Value" ValueChanged="value => SetFilterValue(filter, value)" />
|
||||||
|
}
|
||||||
|
</Template>
|
||||||
|
;
|
||||||
}
|
}
|
@ -22,8 +22,6 @@ namespace AntDesign
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public Expression<Func<TData>> FieldExpression { get; set; }
|
public Expression<Func<TData>> FieldExpression { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public RenderFragment<TData> CellRender { get; set; }
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public TData Field
|
public TData Field
|
||||||
@ -70,7 +68,7 @@ namespace AntDesign
|
|||||||
public SortDirection DefaultSortOrder { get; set; }
|
public SortDirection DefaultSortOrder { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Func<RowData, Dictionary<string, object>> OnCell { get; set; }
|
public Func<CellData, Dictionary<string, object>> OnCell { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Func<Dictionary<string, object>> OnHeaderCell { get; set; }
|
public Func<Dictionary<string, object>> OnHeaderCell { get; set; }
|
||||||
|
@ -70,6 +70,9 @@ namespace AntDesign
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Hidden { get; set; }
|
public bool Hidden { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public virtual RenderFragment<CellData> CellRender { get; set; }
|
||||||
|
|
||||||
public int ColIndex { get; set; }
|
public int ColIndex { get; set; }
|
||||||
|
|
||||||
protected bool AppendExpandColumn => Table.HasExpandTemplate && ColIndex == (Table.TreeMode ? Table.TreeExpandIconColumnIndex : Table.ExpandIconColumnIndex);
|
protected bool AppendExpandColumn => Table.HasExpandTemplate && ColIndex == (Table.TreeMode ? Table.TreeExpandIconColumnIndex : Table.ExpandIconColumnIndex);
|
||||||
|
@ -1,48 +1,62 @@
|
|||||||
@namespace AntDesign
|
@namespace AntDesign
|
||||||
|
@using AntDesign.TableModels
|
||||||
@inherits ColumnBase
|
@inherits ColumnBase
|
||||||
|
|
||||||
@if (IsInitialize)
|
@if (IsInitialize)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (IsPlaceholder)
|
else if (IsPlaceholder)
|
||||||
{
|
{
|
||||||
<td style="padding: 0px; border: 0px; height: 0px;"></td>
|
<td style="padding: 0px; border: 0px; height: 0px;"></td>
|
||||||
}
|
}
|
||||||
else if (IsMeasure)
|
else if (IsMeasure)
|
||||||
{
|
{
|
||||||
<td style="padding: 0px; border: 0px; height: 0px;"><div style="height: 0px; overflow: hidden;"> </div></td>
|
<td style="padding: 0px; border: 0px; height: 0px;"><div style="height: 0px; overflow: hidden;"> </div></td>
|
||||||
}
|
}
|
||||||
else if (IsColGroup)
|
else if (IsColGroup)
|
||||||
{
|
{
|
||||||
if (Width != null)
|
if (Width != null)
|
||||||
{
|
{
|
||||||
<col class="ant-table-selection-col" style="width: @((CssSizeLength)Width); min-width: @((CssSizeLength)Width);">
|
<col class="ant-table-selection-col" style="width: @((CssSizeLength)Width); min-width: @((CssSizeLength)Width);">
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<col class="ant-table-selection-col">
|
<col class="ant-table-selection-col">
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsHeader && HeaderColSpan != 0)
|
else if (IsHeader && HeaderColSpan != 0)
|
||||||
{
|
{
|
||||||
<th class="@ClassMapper.Class ant-table-selection-column" style="@FixedStyle @HeaderStyle" @key="@Key" colspan="@HeaderColSpan">
|
<th class="@ClassMapper.Class ant-table-selection-column" style="@FixedStyle @HeaderStyle" @key="@Key" colspan="@HeaderColSpan">
|
||||||
@if (Type == "checkbox")
|
@if (Type == "checkbox")
|
||||||
{
|
{
|
||||||
<Checkbox Checked="_checked" CheckedChange="HandleCheckedChange" Indeterminate="Indeterminate" />
|
<Checkbox Checked="_checked" CheckedChange="HandleCheckedChange" Indeterminate="Indeterminate" />
|
||||||
}
|
}
|
||||||
</th>
|
</th>
|
||||||
}
|
}
|
||||||
else if (!IsHeader && RowSpan != 0 && ColSpan != 0)
|
else if (!IsHeader && RowSpan != 0 && ColSpan != 0)
|
||||||
{
|
{
|
||||||
<td class="@ClassMapper.Class ant-table-selection-column" style="@FixedStyle @Style" @key="@Key" rowspan="@RowSpan" colspan="@ColSpan">
|
<td class="@ClassMapper.Class ant-table-selection-column" style="@FixedStyle @Style" @key="@Key" rowspan="@RowSpan" colspan="@ColSpan">
|
||||||
@if (Type == "checkbox")
|
|
||||||
{
|
@if (CellRender != null)
|
||||||
<Checkbox Checked="_checked" Disabled="Disabled" CheckedChange="HandleCheckedChange" />
|
{
|
||||||
}
|
var cellData = new CellData(RowData);
|
||||||
else if (Type == "radio")
|
@CellRender(cellData)
|
||||||
{
|
}
|
||||||
<Radio Checked="_checked" Disabled="Disabled" CheckedChange="HandleCheckedChange" TValue="bool" />
|
else if (ChildContent != null)
|
||||||
}
|
{
|
||||||
</td>
|
@ChildContent
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@if (Type == "checkbox")
|
||||||
|
{
|
||||||
|
<Checkbox Checked="_checked" Disabled="Disabled" CheckedChange="HandleCheckedChange" />
|
||||||
|
}
|
||||||
|
else if (Type == "radio")
|
||||||
|
{
|
||||||
|
<Radio Checked="_checked" Disabled="Disabled" CheckedChange="HandleCheckedChange" TValue="bool" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</td>
|
||||||
}
|
}
|
@ -1,5 +1,15 @@
|
|||||||
@namespace AntDesign
|
@namespace AntDesign
|
||||||
|
@using AntDesign.TableModels
|
||||||
@inherits ColumnBase
|
@inherits ColumnBase
|
||||||
|
|
||||||
<td class="@ClassMapper.Class" style="@FixedStyle @Style" colspan="@ColSpan">@ChildContent</td>
|
<td class="@ClassMapper.Class" style="@FixedStyle @Style" colspan="@ColSpan">
|
||||||
|
@if (CellRender != null)
|
||||||
|
{
|
||||||
|
var cellData = new CellData(RowData);
|
||||||
|
@CellRender(cellData)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@ChildContent
|
||||||
|
}
|
||||||
|
</td>
|
@ -27,7 +27,7 @@
|
|||||||
<CascadingValue Name="IsInitialize" Value="true" IsFixed>
|
<CascadingValue Name="IsInitialize" Value="true" IsFixed>
|
||||||
@ChildContent(_fieldModel)
|
@ChildContent(_fieldModel)
|
||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
<div class="@ClassMapper.Class">
|
<div class="@ClassMapper.Class" @ref="_tableRef">
|
||||||
@if (TitleTemplate != null || Title != null)
|
@if (TitleTemplate != null || Title != null)
|
||||||
{
|
{
|
||||||
<div class="ant-table-title">
|
<div class="ant-table-title">
|
||||||
|
@ -136,7 +136,7 @@ namespace AntDesign
|
|||||||
public bool Responsive { get; set; } = true;
|
public bool Responsive { get; set; } = true;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
public ColumnContext ColumnContext { get; set; }
|
public ColumnContext ColumnContext { get; set; }
|
||||||
|
|
||||||
@ -146,20 +146,20 @@ namespace AntDesign
|
|||||||
|
|
||||||
private IList<SummaryRow> _summaryRows;
|
private IList<SummaryRow> _summaryRows;
|
||||||
|
|
||||||
|
private bool _hasFirstLoad;
|
||||||
private bool _waitingReload;
|
private bool _waitingReload;
|
||||||
private bool _waitingReloadAndInvokeChange;
|
private bool _waitingReloadAndInvokeChange;
|
||||||
private bool _treeMode;
|
private bool _treeMode;
|
||||||
|
|
||||||
private bool _hasFixLeft;
|
private bool _hasFixLeft;
|
||||||
private bool _hasFixRight;
|
private bool _hasFixRight;
|
||||||
private bool _pingRight;
|
|
||||||
private bool _pingLeft;
|
|
||||||
private int _treeExpandIconColumnIndex;
|
private int _treeExpandIconColumnIndex;
|
||||||
private readonly ClassMapper _wrapperClassMapper = new ClassMapper();
|
private readonly ClassMapper _wrapperClassMapper = new ClassMapper();
|
||||||
private string TableLayoutStyle => TableLayout == null ? "" : $"table-layout: {TableLayout};";
|
private string TableLayoutStyle => TableLayout == null ? "" : $"table-layout: {TableLayout};";
|
||||||
|
|
||||||
private ElementReference _tableHeaderRef;
|
private ElementReference _tableHeaderRef;
|
||||||
private ElementReference _tableBodyRef;
|
private ElementReference _tableBodyRef;
|
||||||
|
private ElementReference _tableRef;
|
||||||
|
|
||||||
private bool ServerSide => _hasRemoteDataSourceAttribute ? RemoteDataSource : Total > _dataSourceCount;
|
private bool ServerSide => _hasRemoteDataSourceAttribute ? RemoteDataSource : Total > _dataSourceCount;
|
||||||
|
|
||||||
@ -325,8 +325,8 @@ namespace AntDesign
|
|||||||
.If($"{prefixCls}-fixed-column {prefixCls}-scroll-horizontal", () => ScrollX != null)
|
.If($"{prefixCls}-fixed-column {prefixCls}-scroll-horizontal", () => ScrollX != null)
|
||||||
.If($"{prefixCls}-has-fix-left", () => _hasFixLeft)
|
.If($"{prefixCls}-has-fix-left", () => _hasFixLeft)
|
||||||
.If($"{prefixCls}-has-fix-right", () => _hasFixRight)
|
.If($"{prefixCls}-has-fix-right", () => _hasFixRight)
|
||||||
.If($"{prefixCls}-ping-left", () => _pingLeft)
|
//.If($"{prefixCls}-ping-left", () => _pingLeft)
|
||||||
.If($"{prefixCls}-ping-right", () => _pingRight)
|
//.If($"{prefixCls}-ping-right", () => _pingRight)
|
||||||
.If($"{prefixCls}-rtl", () => RTL)
|
.If($"{prefixCls}-rtl", () => RTL)
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -359,9 +359,21 @@ namespace AntDesign
|
|||||||
FlushCache();
|
FlushCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAfterRender(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
base.OnAfterRender(firstRender);
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
DomEventListener.AddShared<JsonElement>("window", "beforeunload", Reloading);
|
||||||
|
|
||||||
|
if (ScrollY != null || ScrollX != null)
|
||||||
|
{
|
||||||
|
await JsInvokeAsync(JSInteropConstants.BindTableScroll, _tableBodyRef, _tableRef, _tableHeaderRef, ScrollX != null, ScrollY != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
_hasFirstLoad = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!firstRender)
|
if (!firstRender)
|
||||||
{
|
{
|
||||||
@ -371,28 +383,6 @@ namespace AntDesign
|
|||||||
_shouldRender = false;
|
_shouldRender = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
||||||
{
|
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
|
||||||
|
|
||||||
if (firstRender)
|
|
||||||
{
|
|
||||||
DomEventService.AddEventListener("window", "beforeunload", Reloading, false);
|
|
||||||
if (ScrollX != null)
|
|
||||||
{
|
|
||||||
await SetScrollPositionClassName();
|
|
||||||
|
|
||||||
DomEventService.AddEventListener("window", "resize", OnResize, false);
|
|
||||||
DomEventService.AddEventListener(_tableBodyRef, "scroll", OnScroll);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ScrollY != null && ScrollX != null)
|
|
||||||
{
|
|
||||||
await JsInvokeAsync(JSInteropConstants.BindTableHeaderAndBodyScroll, _tableBodyRef, _tableHeaderRef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
base.OnParametersSet();
|
base.OnParametersSet();
|
||||||
@ -402,12 +392,19 @@ namespace AntDesign
|
|||||||
_waitingReloadAndInvokeChange = false;
|
_waitingReloadAndInvokeChange = false;
|
||||||
_waitingReload = false;
|
_waitingReload = false;
|
||||||
|
|
||||||
ReloadAndInvokeChange();
|
if (_hasFirstLoad)
|
||||||
|
{
|
||||||
|
ReloadAndInvokeChange();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (_waitingReload)
|
else if (_waitingReload)
|
||||||
{
|
{
|
||||||
_waitingReload = false;
|
_waitingReload = false;
|
||||||
InternalReload();
|
|
||||||
|
if (_hasFirstLoad)
|
||||||
|
{
|
||||||
|
InternalReload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.RenderMode == RenderMode.ParametersHashCodeChanged)
|
if (this.RenderMode == RenderMode.ParametersHashCodeChanged)
|
||||||
@ -437,61 +434,9 @@ namespace AntDesign
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnResize(JsonElement _) => await SetScrollPositionClassName();
|
|
||||||
|
|
||||||
private async void OnScroll(JsonElement _) => await SetScrollPositionClassName();
|
|
||||||
|
|
||||||
private async Task SetScrollPositionClassName(bool clear = false)
|
|
||||||
{
|
|
||||||
if (_isReloading)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var element = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, _tableBodyRef);
|
|
||||||
var scrollWidth = element.ScrollWidth;
|
|
||||||
var scrollLeft = element.ScrollLeft;
|
|
||||||
var clientWidth = element.ClientWidth;
|
|
||||||
|
|
||||||
var beforePingLeft = _pingLeft;
|
|
||||||
var beforePingRight = _pingRight;
|
|
||||||
|
|
||||||
if ((scrollWidth == clientWidth && scrollWidth != 0) || clear)
|
|
||||||
{
|
|
||||||
_pingLeft = false;
|
|
||||||
_pingRight = false;
|
|
||||||
}
|
|
||||||
else if (scrollLeft == 0)
|
|
||||||
{
|
|
||||||
_pingLeft = false;
|
|
||||||
_pingRight = true;
|
|
||||||
}
|
|
||||||
// allow the gap between 1 px, it's magic ✨
|
|
||||||
else if (Math.Abs(scrollWidth - (scrollLeft + clientWidth)) < 1)
|
|
||||||
{
|
|
||||||
_pingRight = false;
|
|
||||||
_pingLeft = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_pingLeft = true;
|
|
||||||
_pingRight = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (beforePingLeft != _pingLeft || beforePingRight != _pingRight)
|
|
||||||
{
|
|
||||||
_shouldRender = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!clear)
|
|
||||||
{
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "resize", OnResize);
|
DomEventListener.Dispose();
|
||||||
DomEventService.RemoveEventListerner<JsonElement>(_tableBodyRef, "scroll", OnScroll);
|
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "beforeunload", Reloading);
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,12 +444,12 @@ namespace AntDesign
|
|||||||
{
|
{
|
||||||
if (!_isReloading)
|
if (!_isReloading)
|
||||||
{
|
{
|
||||||
if (ScrollY != null && ScrollX != null)
|
if (ScrollY != null || ScrollX != null)
|
||||||
{
|
{
|
||||||
await JsInvokeAsync(JSInteropConstants.UnbindTableHeaderAndBodyScroll, _tableBodyRef);
|
await JsInvokeAsync(JSInteropConstants.UnbindTableScroll, _tableBodyRef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DomEventService.RemoveEventListerner<JsonElement>("window", "beforeunload", Reloading);
|
DomEventListener.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ITable.RowExpandable(RowData rowData)
|
bool ITable.RowExpandable(RowData rowData)
|
||||||
|
20
components/table/TableModels/CellData.cs
Normal file
20
components/table/TableModels/CellData.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// 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.TableModels
|
||||||
|
{
|
||||||
|
public class CellData
|
||||||
|
{
|
||||||
|
public RowData RowData { get; }
|
||||||
|
|
||||||
|
public CellData(RowData rowData)
|
||||||
|
{
|
||||||
|
RowData = rowData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,4 @@
|
|||||||
// Licensed to the .NET Foundation under one or more agreements.
|
using System;
|
||||||
// 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.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@ -54,7 +50,7 @@ namespace AntDesign
|
|||||||
internal List<TabPane> _panes = new List<TabPane>();
|
internal List<TabPane> _panes = new List<TabPane>();
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public DomEventService DomEventService { get; set; }
|
private IDomEventListener DomEventListener { get; set; }
|
||||||
|
|
||||||
#region Parameters
|
#region Parameters
|
||||||
|
|
||||||
@ -394,13 +390,13 @@ namespace AntDesign
|
|||||||
|
|
||||||
if (IsHorizontal && !_wheelDisabled)
|
if (IsHorizontal && !_wheelDisabled)
|
||||||
{
|
{
|
||||||
DomEventService.AddEventListener<string>(_scrollTabBar, "wheel", OnWheel, true, true);
|
DomEventListener.AddExclusive<string>(_scrollTabBar, "wheel", OnWheel, true);
|
||||||
_wheelDisabled = true;
|
_wheelDisabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsHorizontal && _wheelDisabled)
|
if (!IsHorizontal && _wheelDisabled)
|
||||||
{
|
{
|
||||||
DomEventService.RemoveEventListerner<string>(_scrollTabBar, "wheel", OnWheel);
|
DomEventListener.RemoveExclusive(_scrollTabBar, "wheel");
|
||||||
_wheelDisabled = false;
|
_wheelDisabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,5 +564,11 @@ namespace AntDesign
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion DRAG & DROP
|
#endregion DRAG & DROP
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
DomEventListener.DisposeExclusive();
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ namespace AntDesign
|
|||||||
public Tooltip()
|
public Tooltip()
|
||||||
{
|
{
|
||||||
PrefixCls = "ant-tooltip";
|
PrefixCls = "ant-tooltip";
|
||||||
Placement = PlacementType.Top;
|
Placement = Placement.Top;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override string GetOverlayEnterClass()
|
internal override string GetOverlayEnterClass()
|
||||||
@ -38,7 +38,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
internal override async Task Show(int? overlayLeft = null, int? overlayTop = null)
|
internal override async Task Show(int? overlayLeft = null, int? overlayTop = null)
|
||||||
{
|
{
|
||||||
if (Trigger.Contains(TriggerType.Hover))
|
if (Trigger.Contains(AntDesign.Trigger.Hover))
|
||||||
{
|
{
|
||||||
await Task.Delay((int)(MouseEnterDelay * 1000));
|
await Task.Delay((int)(MouseEnterDelay * 1000));
|
||||||
}
|
}
|
||||||
@ -48,7 +48,7 @@ namespace AntDesign
|
|||||||
|
|
||||||
internal override async Task Hide(bool force = false)
|
internal override async Task Hide(bool force = false)
|
||||||
{
|
{
|
||||||
if (Trigger.Contains(TriggerType.Hover))
|
if (Trigger.Contains(AntDesign.Trigger.Hover))
|
||||||
{
|
{
|
||||||
await Task.Delay((int)(MouseLeaveDelay * 1000));
|
await Task.Delay((int)(MouseLeaveDelay * 1000));
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ namespace AntDesign
|
|||||||
await base.Hide(force);
|
await base.Hide(force);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task ChildElementMoved() =>await GetOverlayComponent().UpdatePosition();
|
//internal async Task ChildElementMoved() =>await GetOverlayComponent().UpdatePosition();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<OverlayTrigger @ref="@_dropDown"
|
<OverlayTrigger @ref="@_dropDown"
|
||||||
Visible="Open"
|
Visible="Open"
|
||||||
Disabled="Disabled"
|
Disabled="Disabled"
|
||||||
Trigger="new[] { TriggerType.Click }"
|
Trigger="new[] { Trigger.Click }"
|
||||||
HiddenMode
|
HiddenMode
|
||||||
OnMouseEnter="@(() => { OnMouseEnter?.Invoke(); })"
|
OnMouseEnter="@(() => { OnMouseEnter?.Invoke(); })"
|
||||||
OnMouseLeave="@(() => { OnMouseLeave?.Invoke(); })"
|
OnMouseLeave="@(() => { OnMouseLeave?.Invoke(); })"
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
<div style="padding: 100px; height: 1000px; background: #eee; position: relative " id="area">
|
<div style="padding: 100px; height: 1000px; background: #eee; position: relative " id="area">
|
||||||
<AutoComplete PopupContainerSelector="#area"
|
<AutoComplete PopupContainerSelector="#area"
|
||||||
@bind-Value="@value"
|
@bind-Value="@value"
|
||||||
Options="@options" />
|
Options="@options"
|
||||||
|
BoundaryAdjustMode="@TriggerBoundaryAdjustMode.InScroll"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ When there is a need for autocomplete functionality.
|
|||||||
| Property | Description | Type | Default |
|
| Property | Description | Type | Default |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Backfill | backfill selected item the input when using keyboard | bool | false |
|
| Backfill | backfill selected item the input when using keyboard | bool | false |
|
||||||
|
| BoundaryAdjustMode | `Dropdown` adjustment strategy (when for example browser resize is happening) | TriggerBoundaryAdjustMode | TriggerBoundaryAdjustMode.InView |
|
||||||
| Options | Data source for autocomplete | AutocompleteDataSource | - |
|
| Options | Data source for autocomplete | AutocompleteDataSource | - |
|
||||||
| Disabled | Set disabled | bool | - |
|
| Disabled | Set disabled | bool | - |
|
||||||
| Placeholder | Placeholder text | string | - |
|
| Placeholder | Placeholder text | string | - |
|
||||||
|
@ -19,6 +19,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/qtJm4yt45/AutoComplete.svg
|
|||||||
| 参数 | 说明 | 类型 | 默认值 |
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false |
|
| Backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false |
|
||||||
|
| BoundaryAdjustMode | `Dropdown` adjustment strategy (when for example browser resize is happening) | TriggerBoundaryAdjustMode | TriggerBoundaryAdjustMode.InView |
|
||||||
| Options | 自动完成的数据源 | AutocompleteDataSource | - |
|
| Options | 自动完成的数据源 | AutocompleteDataSource | - |
|
||||||
| Disabled | 是否禁用 | bool | - |
|
| Disabled | 是否禁用 | bool | - |
|
||||||
| Placeholder | 占位符文本 | string | - |
|
| Placeholder | 占位符文本 | string | - |
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<AvatarGroup>
|
<AvatarGroup>
|
||||||
<Avatar Src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
<Avatar Src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
||||||
<Avatar Style="background-color: #f56a00">K</Avatar>
|
<Avatar Style="background-color: #f56a00">K</Avatar>
|
||||||
<Tooltip Title=@("Ant User") Placement="PlacementType.Top">
|
<Tooltip Title=@("Ant User") Placement="Placement.Top">
|
||||||
<Unbound>
|
<Unbound>
|
||||||
<Avatar Style="background-color: #87d068;" Icon="user" RefBack="@context"/>
|
<Avatar Style="background-color: #87d068;" Icon="user" RefBack="@context"/>
|
||||||
</Unbound>
|
</Unbound>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<AvatarGroup MaxCount="2" MaxStyle="color: #f56a00; background-color:#fde3cf;">
|
<AvatarGroup MaxCount="2" MaxStyle="color: #f56a00; background-color:#fde3cf;">
|
||||||
<Avatar Src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
<Avatar Src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
|
||||||
<Avatar Style="background-color: #f56a00">K</Avatar>
|
<Avatar Style="background-color: #f56a00">K</Avatar>
|
||||||
<Tooltip Title=@("Ant User") Placement="PlacementType.Top" >
|
<Tooltip Title=@("Ant User") Placement="Placement.Top" >
|
||||||
<Unbound>
|
<Unbound>
|
||||||
<Avatar Style="background-color: #87d068;" Icon="user" RefBack="@context"/>
|
<Avatar Style="background-color: #87d068;" Icon="user" RefBack="@context"/>
|
||||||
</Unbound>
|
</Unbound>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user