mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-27 12:17:42 +08:00
214 lines
6.0 KiB
C#
214 lines
6.0 KiB
C#
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Headless;
|
|
using Avalonia.Input;
|
|
using Avalonia.Threading;
|
|
using Avalonia.VisualTree;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using AvaloniaWindow = Avalonia.Controls.Window;
|
|
using AtomButton = AtomUI.Desktop.Controls.Button;
|
|
using AtomWindow = AtomUI.Desktop.Controls.Window;
|
|
|
|
namespace AtomUI.Desktop.Controls.Tests.Buttons;
|
|
|
|
public class ButtonKeyboardNavigationTests
|
|
{
|
|
static ButtonKeyboardNavigationTests()
|
|
{
|
|
AvaloniaTestApp.EnsureInitialized();
|
|
}
|
|
|
|
[Fact]
|
|
public void Tab_Should_Move_Focus_To_AtomButton()
|
|
{
|
|
TabShouldMoveFocusToAtomButton(new AvaloniaWindow());
|
|
}
|
|
|
|
[Fact]
|
|
public void Tab_Should_Move_Focus_To_AtomButton_In_AtomWindow()
|
|
{
|
|
TabShouldMoveFocusToAtomButton(new AtomWindow());
|
|
}
|
|
|
|
[Fact]
|
|
public void Fresh_AtomWindow_Tab_From_No_Focus_Should_Reach_Button()
|
|
{
|
|
var button1 = new AtomButton { Content = "One", Width = 80 };
|
|
var panel = new StackPanel();
|
|
panel.Children.Add(button1);
|
|
|
|
var window = new AtomWindow
|
|
{
|
|
Width = 360,
|
|
Height = 220,
|
|
Content = panel
|
|
};
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
var focusManager = TopLevel.GetTopLevel(panel)!.FocusManager;
|
|
focusManager.GetFocusedElement().ShouldNotBeSameAs(button1);
|
|
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
PressTab(window);
|
|
if (ReferenceEquals(focusManager.GetFocusedElement(), button1))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
focusManager.GetFocusedElement().ShouldBeSameAs(button1);
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
}
|
|
}
|
|
|
|
private static void TabShouldMoveFocusToAtomButton(AvaloniaWindow window)
|
|
{
|
|
var textBox = new TextBox { Width = 120 };
|
|
var button1 = new AtomButton { Content = "One", Width = 80 };
|
|
var button2 = new AtomButton { Content = "Two", Width = 80 };
|
|
|
|
var panel = new StackPanel();
|
|
panel.Children.Add(textBox);
|
|
panel.Children.Add(button1);
|
|
panel.Children.Add(button2);
|
|
|
|
window.Width = 360;
|
|
window.Height = 220;
|
|
window.Content = panel;
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
var focusManager = TopLevel.GetTopLevel(panel)!.FocusManager;
|
|
|
|
// 起点:焦点在 TextBox
|
|
textBox.Focus().ShouldBeTrue();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
PressTab(window);
|
|
focusManager.GetFocusedElement().ShouldBeSameAs(button1);
|
|
|
|
PressTab(window);
|
|
focusManager.GetFocusedElement().ShouldBeSameAs(button2);
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Focused_AtomButton_Enter_Should_Click()
|
|
{
|
|
var clicked = 0;
|
|
var button = new AtomButton { Content = "Go", Width = 80 };
|
|
button.Click += (_, _) => clicked++;
|
|
|
|
var window = new AvaloniaWindow
|
|
{
|
|
Width = 360,
|
|
Height = 220,
|
|
Content = button
|
|
};
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
button.Focus().ShouldBeTrue();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
window.KeyPress(Key.Enter, RawInputModifiers.None, PhysicalKey.Enter, null);
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
clicked.ShouldBe(1);
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Tab_Focused_Button_Should_Show_FocusVisual()
|
|
{
|
|
AssertFocusVisualVisible(new AtomButton { Content = "Go", Width = 80 },
|
|
"ButtonTheme.axaml");
|
|
}
|
|
|
|
[Fact]
|
|
public void Tab_Focused_Dashed_Button_Should_Show_FocusVisual()
|
|
{
|
|
AssertFocusVisualVisible(new AtomButton { Content = "Go", Width = 80, ButtonType = ButtonType.Dashed },
|
|
"ButtonTheme.axaml");
|
|
}
|
|
|
|
[Fact]
|
|
public void Tab_Focused_Dashed_Variant_Button_Should_Show_FocusVisual()
|
|
{
|
|
AssertFocusVisualVisible(new AtomButton { Content = "Go", Width = 80, Variant = ButtonVariant.Dashed },
|
|
"ButtonTheme.axaml");
|
|
}
|
|
|
|
[Fact]
|
|
public void Tab_Focused_DropdownButton_Should_Show_FocusVisual()
|
|
{
|
|
AssertFocusVisualVisible(new DropdownButton { Content = "Go", Width = 120 },
|
|
"DropdownButtonTheme.axaml / DropdownButtonBaseTheme.axaml");
|
|
}
|
|
|
|
private static void AssertFocusVisualVisible(Control button, string themeFile)
|
|
{
|
|
var window = new AtomWindow
|
|
{
|
|
Width = 360,
|
|
Height = 220,
|
|
Content = button
|
|
};
|
|
|
|
try
|
|
{
|
|
window.Show();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
button.Focus(NavigationMethod.Tab).ShouldBeTrue();
|
|
Dispatcher.UIThread.RunJobs();
|
|
|
|
// :focus-visible 伪类应在键盘导航后置位
|
|
button.Classes.Contains(":focus-visible").ShouldBeTrue();
|
|
|
|
// 主题声明了 ^:focus-visible /template/ Border#FocusVisual 样式,
|
|
// 模板必须存在该元素且在键盘焦点下可见,锁定 #487 的回归形态
|
|
var focusVisual = button.GetVisualDescendants()
|
|
.OfType<Border>()
|
|
.FirstOrDefault(c => c.Name == "FocusVisual");
|
|
focusVisual.ShouldNotBeNull($"{themeFile} :focus-visible 样式指向 Border#FocusVisual,模板必须包含该元素");
|
|
focusVisual.IsVisible.ShouldBeTrue();
|
|
focusVisual.BorderThickness.ShouldNotBe(new Thickness(0));
|
|
focusVisual.BorderBrush.ShouldNotBeNull("ColorFocusBorder 令牌应解析出焦点环画刷");
|
|
}
|
|
finally
|
|
{
|
|
window.Close();
|
|
}
|
|
}
|
|
|
|
private static void PressTab(AvaloniaWindow window)
|
|
{
|
|
window.KeyPress(Key.Tab, RawInputModifiers.None, PhysicalKey.Tab, null);
|
|
Dispatcher.UIThread.RunJobs();
|
|
}
|
|
}
|