Skip to content

Commit 9938de3

Browse files
authored
feat(TreeView): support toggle node by ArrowLeft/Right (#4351)
* feat: 增加左右按键支持 * test: 增加单元测试 * refactor: 更改参数名称 * refactor: 更新参数名称 * feat: 支持空格 * doc: 更新注释 * doc: 更新示例本地化 * test: 移除不需要的单元测试 * chore: bump version 8.9.4-beta03
1 parent a88946d commit 9938de3

File tree

8 files changed

+57
-13
lines changed

8 files changed

+57
-13
lines changed

src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@
194194
Introduction="@Localizer["TreeViewEnableKeyboardArrowUpDownIntro"]"
195195
Name="Normal">
196196
<section ignore>@_selectedValue</section>
197-
<TreeView TItem="TreeFoo" Items="@KeyboardItems" OnTreeItemClick="@OnTreeItemKeyboardClick" EnableKeyboardArrowUpDown="true" />
197+
<TreeView TItem="TreeFoo" Items="@KeyboardItems" OnTreeItemClick="@OnTreeItemKeyboardClick" EnableKeyboard="true" />
198198
</DemoBlock>
199199

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

src/BootstrapBlazor.Server/Locales/en-US.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@
709709
"TreeViewMaxSelectedCountIntro": "Control the maximum number of selectable items by setting the <code>MaxSelectedCount</code> property, and handle the logic through the <code>OnMaxSelectedCountExceed</code> callback",
710710
"TreeViewMaxSelectedCountDesc": "When more than 2 nodes are selected, a <code>Toast</code> prompt bar will pop up",
711711
"TreeViewEnableKeyboardArrowUpDownTitle": "Keyboard",
712-
"TreeViewEnableKeyboardArrowUpDownIntro": "Support keyboard up and down arrow operations by setting <code>EnableKeyboardArrowUpDown=\"true\"</code>"
712+
"TreeViewEnableKeyboardArrowUpDownIntro": "Support keyboard up and down arrow operations by setting <code>EnableKeyboardArrowUpDown=\"true\"</code>. <kbd>ArrowLeft</kbd> collapse the node, <kbd>ArrowRight</kbd> expand the node, <kbd>ArrowUp</kbd> move the node up, <kbd>ArrowDown</kbd> move the node down, <kbd>Space</kbd> select the node,"
713713
},
714714
"BootstrapBlazor.Server.Components.Samples.Trees": {
715715
"TreeIntro": "<p>Obsolete,The <a href=\"treeviews\" alt=\"treeview\">TreeView</a> provides more functions",

src/BootstrapBlazor.Server/Locales/zh-CN.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@
709709
"TreeViewMaxSelectedCountIntro": "通过设置 <code>MaxSelectedCount</code> 属性控制最大可选数量,通过 <code>OnMaxSelectedCountExceed</code> 回调处理逻辑",
710710
"TreeViewMaxSelectedCountDesc": "选中节点超过 2 个时,弹出 <code>Toast</code> 提示栏",
711711
"TreeViewEnableKeyboardArrowUpDownTitle": "键盘支持",
712-
"TreeViewEnableKeyboardArrowUpDownIntro": "通过设置 <code>EnableKeyboardArrowUpDown=\"true\"</code> 支持键盘上下箭头操作"
712+
"TreeViewEnableKeyboardArrowUpDownIntro": "通过设置 <code>EnableKeyboardArrowUpDown=\"true\"</code> 支持键盘上下箭头操作。<kbd>左箭头</kbd> 收起节点,<kbd>右箭头</kbd> 展开节点,<kbd>上箭头</kbd> 向上移动节点,<kbd>下箭头</kbd> 向下移动节点,<kbd>空格</kbd> 选中节点"
713713
},
714714
"BootstrapBlazor.Server.Components.Samples.Trees": {
715715
"TreeIntro": "<p>本组件已弃用,请使用新组件 <a href=\"treeviews\" alt=\"treeview\">TreeView</a> 提供更多功能",

src/BootstrapBlazor/BootstrapBlazor.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>8.9.4-beta02</Version>
4+
<Version>8.9.4-beta03</Version>
55
</PropertyGroup>
66

77
<ItemGroup Condition="'$(TargetFramework)' == 'net5.0'">

src/BootstrapBlazor/Components/TreeView/TreeView.razor

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
}
1919
else
2020
{
21-
<div @attributes="AdditionalAttributes" id="@Id" tabindex="0" class="@ClassString" data-bb-keyboard-arrow-up-down="@EnableKeyboardArrowUpDownString">
21+
<div @attributes="AdditionalAttributes" id="@Id" tabindex="0" class="@ClassString" data-bb-keyboard="@EnableKeyboardString">
2222
@if (ShowSearch)
2323
{
2424
@if (SearchTemplate == null)

src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs

+17-5
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,15 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
246246
public string? ExpandNodeIcon { get; set; }
247247

248248
/// <summary>
249-
/// 获得/设置 是否开启键盘上下键操作 默认 false
249+
/// 获得/设置 是否开启键盘上下左右按键操作 默认 false
250+
/// <para>ArrowLeft 收起节点</para>
251+
/// <para>ArrowRight 展开节点</para>
252+
/// <para>ArrowUp 向上移动节点</para>
253+
/// <para>ArrowDown 向下移动节点</para>
254+
/// <para>Space 选中当前节点</para>
250255
/// </summary>
251256
[Parameter]
252-
public bool EnableKeyboardArrowUpDown { get; set; }
257+
public bool EnableKeyboard { get; set; }
253258

254259
/// <summary>
255260
/// 获得/设置 是否键盘上下键操作当前选中节点与视窗关系配置 默认 null 使用 { behavior: "smooth", block: "center", inline: "nearest" }
@@ -295,7 +300,7 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
295300

296301
private string? _searchText;
297302

298-
private string? EnableKeyboardArrowUpDownString => EnableKeyboardArrowUpDown ? "true" : null;
303+
private string? EnableKeyboardString => EnableKeyboard ? "true" : null;
299304

300305
/// <summary>
301306
/// <inheritdoc/>
@@ -396,8 +401,15 @@ public async ValueTask TriggerKeyDown(string key)
396401
// 如果兄弟节点没有时,找到父亲节点
397402
if (ActiveItem != null)
398403
{
399-
_keyboardArrowUpDownTrigger = true;
400-
await ActiveTreeViewItem(key, ActiveItem);
404+
if (key == "ArrowUp" || key == "ArrowDown")
405+
{
406+
_keyboardArrowUpDownTrigger = true;
407+
await ActiveTreeViewItem(key, ActiveItem);
408+
}
409+
else if (key == "ArrowLeft" || key == "ArrowRight")
410+
{
411+
await OnToggleNodeAsync(ActiveItem, true);
412+
}
401413
}
402414
}
403415

src/BootstrapBlazor/Components/TreeView/TreeView.razor.js

+11-2
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,23 @@ export function init(id, invoke, method) {
3030
})
3131

3232
EventHandler.on(el, 'keydown', '.tree-root', e => {
33-
if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Enter') {
34-
const v = el.getAttribute('data-bb-keyboard-arrow-up-down');
33+
if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
34+
const v = el.getAttribute('data-bb-keyboard');
3535
if (v === "true") {
3636
e.preventDefault();
3737

3838
invoke.invokeMethodAsync(method, e.key);
3939
}
4040
}
41+
else if (e.keyCode === 32) {
42+
const v = el.getAttribute('data-bb-keyboard');
43+
if (v === "true") {
44+
const checkbox = el.querySelector(".active > .tree-content > .form-check > .form-check-input");
45+
if (checkbox) {
46+
checkbox.click();
47+
}
48+
}
49+
}
4150
});
4251
}
4352

test/UnitTest/Components/TreeViewTest.cs

+24-1
Original file line numberDiff line numberDiff line change
@@ -901,7 +901,7 @@ public async Task KeyBoard_Ok()
901901
var activeItemText = "1010";
902902
var cut = Context.RenderComponent<TreeView<TreeFoo>>(pb =>
903903
{
904-
pb.Add(a => a.EnableKeyboardArrowUpDown, true);
904+
pb.Add(a => a.EnableKeyboard, true);
905905
pb.Add(a => a.Items, items);
906906
pb.Add(a => a.OnTreeItemClick, new Func<TreeViewItem<TreeFoo>, Task>(treeViewItem =>
907907
{
@@ -942,6 +942,29 @@ public async Task KeyBoard_Ok()
942942
Assert.Equal("1010", activeItemText);
943943
}
944944

945+
[Fact]
946+
public async Task ToggleExpand_Ok()
947+
{
948+
List<TreeFoo> data =
949+
[
950+
new() { Text = "1010", Id = "1010" },
951+
new() { Text = "1010-01", Id = "1010-01", ParentId = "1010" },
952+
];
953+
954+
var items = TreeFoo.CascadingTree(data);
955+
items[0].IsActive = true;
956+
var cut = Context.RenderComponent<TreeView<TreeFoo>>(pb =>
957+
{
958+
pb.Add(a => a.EnableKeyboard, true);
959+
pb.Add(a => a.Items, items);
960+
});
961+
await cut.InvokeAsync(() => cut.Instance.TriggerKeyDown("ArrowRight"));
962+
cut.Contains("node-icon visible fa-solid fa-caret-right fa-rotate-90");
963+
964+
await cut.InvokeAsync(() => cut.Instance.TriggerKeyDown("ArrowLeft"));
965+
cut.Contains("node-icon visible fa-solid fa-caret-right");
966+
}
967+
945968
class MockTree<TItem> : TreeView<TItem> where TItem : class
946969
{
947970
public bool TestComparerItem(TItem? a, TItem? b) => base.Equals(a, b);

0 commit comments

Comments
 (0)