Skip to content

Commit 81aa14d

Browse files
authored
[Toolbar] Allow arrow keys to move cursor inside input fields (#3200)
* [FluentToolbar] Add EnableArrowKeyTextNavigation * Update tests to include LibraryConfiguration registration --------- Co-authored-by: rpodevns <rpodevns@users.noreply.github.com>
1 parent 4c6ec97 commit 81aa14d

File tree

4 files changed

+113
-1
lines changed

4 files changed

+113
-1
lines changed

examples/Demo/Shared/Microsoft.FluentUI.AspNetCore.Components.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9813,6 +9813,15 @@
98139813
Removes all queued toasts with toast intent Custom
98149814
</summary>
98159815
</member>
9816+
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentToolbar.LibraryConfiguration">
9817+
<summary />
9818+
</member>
9819+
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentToolbar.JSRuntime">
9820+
<summary />
9821+
</member>
9822+
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentToolbar.Module">
9823+
<summary />
9824+
</member>
98169825
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentToolbar.Orientation">
98179826
<summary>
98189827
Gets or sets the toolbar's orentation. See <see cref="P:Microsoft.FluentUI.AspNetCore.Components.FluentToolbar.Orientation"/>
@@ -9823,6 +9832,11 @@
98239832
Gets or sets the content to be rendered inside the component.
98249833
</summary>
98259834
</member>
9835+
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentToolbar.EnableArrowKeyTextNavigation">
9836+
<summary>
9837+
Gets or sets a value indicating whether arrow key navigation within text input fields is enabled. Default is false.
9838+
</summary>
9839+
</member>
98269840
<member name="P:Microsoft.FluentUI.AspNetCore.Components.FluentTooltip.ServiceProvider">
98279841
<summary>
98289842
Gets or sets a reference to the list of registered services.

src/Core/Components/Toolbar/FluentToolbar.razor.cs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
using Microsoft.AspNetCore.Components;
2+
using Microsoft.FluentUI.AspNetCore.Components.Extensions;
3+
using Microsoft.JSInterop;
24

35
namespace Microsoft.FluentUI.AspNetCore.Components;
46

5-
public partial class FluentToolbar : FluentComponentBase
7+
public partial class FluentToolbar : FluentComponentBase, IAsyncDisposable
68
{
9+
private const string JAVASCRIPT_FILE = "./_content/Microsoft.FluentUI.AspNetCore.Components/Components/Toolbar/FluentToolbar.razor.js";
10+
11+
/// <summary />
12+
[Inject]
13+
private LibraryConfiguration LibraryConfiguration { get; set; } = default!;
14+
15+
/// <summary />
16+
[Inject]
17+
private IJSRuntime JSRuntime { get; set; } = default!;
18+
19+
/// <summary />
20+
private IJSObjectReference Module { get; set; } = default!;
21+
722
/// <summary>
823
/// Gets or sets the toolbar's orentation. See <see cref="Orientation"/>
924
/// </summary>
@@ -15,4 +30,37 @@ public partial class FluentToolbar : FluentComponentBase
1530
/// </summary>
1631
[Parameter]
1732
public RenderFragment? ChildContent { get; set; }
33+
34+
/// <summary>
35+
/// Gets or sets a value indicating whether arrow key navigation within text input fields is enabled. Default is false.
36+
/// </summary>
37+
[Parameter]
38+
public bool? EnableArrowKeyTextNavigation { get; set; } = false;
39+
40+
public FluentToolbar()
41+
{
42+
Id = Identifier.NewId();
43+
}
44+
45+
protected override async Task OnAfterRenderAsync(bool firstRender)
46+
{
47+
if (firstRender)
48+
{
49+
Module ??= await JSRuntime.InvokeAsync<IJSObjectReference>("import", JAVASCRIPT_FILE.FormatCollocatedUrl(LibraryConfiguration));
50+
51+
if (EnableArrowKeyTextNavigation ?? false)
52+
{
53+
await Module.InvokeVoidAsync("preventArrowKeyNavigation", Id);
54+
}
55+
}
56+
}
57+
58+
public async ValueTask DisposeAsync()
59+
{
60+
if (Module is not null && !string.IsNullOrEmpty(Id))
61+
{
62+
await Module.InvokeVoidAsync("removePreventArrowKeyNavigation", Id);
63+
await Module.DisposeAsync();
64+
}
65+
}
1866
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Prevent fluent-toolbar from overriding arrow key functionality in input fields
2+
const handlers = new Map();
3+
4+
export function preventArrowKeyNavigation(id) {
5+
const toolbar = document.querySelector("#" + id);
6+
if (!toolbar) return;
7+
8+
const arrowKeyListener = (event) => {
9+
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
10+
const activeElement = document.activeElement;
11+
if (activeElement && (activeElement.tagName === 'FLUENT-SEARCH'
12+
|| activeElement.tagName === 'FLUENT-TEXT-FIELD'
13+
|| activeElement.tagName === 'FLUENT-NUMBER-FIELD'
14+
|| activeElement.tagName === 'FLUENT-TEXT-AREA')) {
15+
16+
const textLength = activeElement.value?.length || 0;
17+
if (textLength > 0) {
18+
event.stopPropagation();
19+
}
20+
}
21+
}
22+
};
23+
24+
toolbar.addEventListener('keydown', arrowKeyListener, true);
25+
handlers.set(id, { toolbar, arrowKeyListener });
26+
}
27+
28+
export function removePreventArrowKeyNavigation(id) {
29+
const handler = handlers.get(id);
30+
if (handler) {
31+
const { toolbar, arrowKeyListener } = handler;
32+
33+
if (toolbar) {
34+
toolbar.removeEventListener('keydown', arrowKeyListener, true);
35+
}
36+
37+
handlers.delete(id);
38+
}
39+
}

tests/Core/_ToDo/Toolbar/FluentToolbarTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
using Bunit;
2+
using Microsoft.AspNetCore.Components;
3+
using Microsoft.Extensions.DependencyInjection;
24
using Xunit;
35

46
namespace Microsoft.FluentUI.AspNetCore.Components.Tests.Toolbar;
57
public class FluentToolbarTests : TestBase
68
{
9+
[Inject]
10+
private LibraryConfiguration LibraryConfiguration { get; set; } = new LibraryConfiguration();
11+
12+
public FluentToolbarTests()
13+
{
14+
TestContext.JSInterop.Mode = JSRuntimeMode.Loose;
15+
TestContext.Services.AddSingleton(LibraryConfiguration);
16+
}
17+
718
[Fact]
819
public void FluentToolbar_Default()
920
{

0 commit comments

Comments
 (0)