mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-07-08 18:16:08 +00:00
Merge pull request #2599 from radzenhq/accessibility-fixes
Accessibility fixes
This commit is contained in:
@@ -374,6 +374,85 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.False(input.HasAttribute("aria-activedescendant"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AutoComplete_AriaExpanded_TracksPopupState()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
var data = new List<string> { "Apple", "Banana", "Cherry" };
|
||||
|
||||
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
|
||||
{
|
||||
parameters
|
||||
.Add(p => p.Data, data)
|
||||
.Add(p => p.OpenOnFocus, true);
|
||||
});
|
||||
|
||||
var input = component.Find("input[role=\"combobox\"]");
|
||||
|
||||
Assert.Equal("false", input.GetAttribute("aria-expanded"));
|
||||
|
||||
await component.InvokeAsync(() => component.Instance.OnPopupOpen());
|
||||
|
||||
input = component.Find("input[role=\"combobox\"]");
|
||||
Assert.Equal("true", input.GetAttribute("aria-expanded"));
|
||||
|
||||
await component.InvokeAsync(() => component.Instance.OnPopupClose());
|
||||
|
||||
input = component.Find("input[role=\"combobox\"]");
|
||||
Assert.Equal("false", input.GetAttribute("aria-expanded"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AutoComplete_AriaExpanded_IsFalse_AfterEscape()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
var data = new List<string> { "Apple", "Banana", "Cherry" };
|
||||
|
||||
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
|
||||
{
|
||||
parameters
|
||||
.Add(p => p.Data, data)
|
||||
.Add(p => p.OpenOnFocus, true);
|
||||
});
|
||||
|
||||
await component.InvokeAsync(() => component.Instance.OnPopupOpen());
|
||||
|
||||
var input = component.Find("input[role=\"combobox\"]");
|
||||
Assert.Equal("true", input.GetAttribute("aria-expanded"));
|
||||
|
||||
input.KeyDown(new Microsoft.AspNetCore.Components.Web.KeyboardEventArgs { Code = "Escape" });
|
||||
|
||||
input = component.Find("input[role=\"combobox\"]");
|
||||
Assert.Equal("false", input.GetAttribute("aria-expanded"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AutoComplete_Sets_AriaSelected_OnHighlightedOption()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
ctx.JSInterop.Setup<int>("Radzen.focusListItem", _ => true).SetResult(1);
|
||||
var data = new List<string> { "Apple", "Banana", "Cherry" };
|
||||
|
||||
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
|
||||
{
|
||||
parameters
|
||||
.Add(p => p.Data, data)
|
||||
.Add(p => p.OpenOnFocus, true);
|
||||
});
|
||||
|
||||
var input = component.Find("input[role=\"combobox\"]");
|
||||
input.KeyDown(new Microsoft.AspNetCore.Components.Web.KeyboardEventArgs { Code = "ArrowDown" });
|
||||
|
||||
var options = component.FindAll("li[role=\"option\"]");
|
||||
|
||||
Assert.Equal("false", options[0].GetAttribute("aria-selected"));
|
||||
Assert.Equal("true", options[1].GetAttribute("aria-selected"));
|
||||
Assert.Equal("false", options[2].GetAttribute("aria-selected"));
|
||||
}
|
||||
|
||||
private sealed class AutoCompleteWithAccessibleView : RadzenAutoComplete
|
||||
{
|
||||
public IEnumerable CurrentView => View;
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace Radzen.Blazor.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BreadCrumb_Item_WithPath_DoesNotRender_AriaCurrentPage()
|
||||
public void BreadCrumb_NonLastItem_WithPath_DoesNotRender_AriaCurrentPage()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
@@ -205,10 +205,69 @@ namespace Radzen.Blazor.Tests
|
||||
builder.AddAttribute(1, nameof(RadzenBreadCrumbItem.Text), "Home");
|
||||
builder.AddAttribute(2, nameof(RadzenBreadCrumbItem.Path), "/");
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.OpenComponent<RadzenBreadCrumbItem>(3);
|
||||
builder.AddAttribute(4, nameof(RadzenBreadCrumbItem.Text), "Products");
|
||||
builder.AddAttribute(5, nameof(RadzenBreadCrumbItem.Path), "/products");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
Assert.DoesNotContain("aria-current", component.Markup);
|
||||
var items = component.FindAll("li.rz-breadcrumb-item");
|
||||
|
||||
Assert.Equal(2, items.Count);
|
||||
Assert.Null(items[0].GetAttribute("aria-current"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BreadCrumb_LastItem_WithPath_Renders_AriaCurrentPage()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenBreadCrumb>(parameters =>
|
||||
{
|
||||
parameters.Add(c => c.ChildContent, builder =>
|
||||
{
|
||||
builder.OpenComponent<RadzenBreadCrumbItem>(0);
|
||||
builder.AddAttribute(1, nameof(RadzenBreadCrumbItem.Text), "Home");
|
||||
builder.AddAttribute(2, nameof(RadzenBreadCrumbItem.Path), "/");
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.OpenComponent<RadzenBreadCrumbItem>(3);
|
||||
builder.AddAttribute(4, nameof(RadzenBreadCrumbItem.Text), "Products");
|
||||
builder.AddAttribute(5, nameof(RadzenBreadCrumbItem.Path), "/products");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
var items = component.FindAll("li.rz-breadcrumb-item");
|
||||
|
||||
Assert.Equal("page", items[1].GetAttribute("aria-current"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BreadCrumb_Renders_OrderedList_WithListItems()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
|
||||
var component = ctx.RenderComponent<RadzenBreadCrumb>(parameters =>
|
||||
{
|
||||
parameters.Add(c => c.ChildContent, builder =>
|
||||
{
|
||||
builder.OpenComponent<RadzenBreadCrumbItem>(0);
|
||||
builder.AddAttribute(1, nameof(RadzenBreadCrumbItem.Text), "Home");
|
||||
builder.AddAttribute(2, nameof(RadzenBreadCrumbItem.Path), "/");
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.OpenComponent<RadzenBreadCrumbItem>(3);
|
||||
builder.AddAttribute(4, nameof(RadzenBreadCrumbItem.Text), "Products");
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
var list = component.Find("nav > ol.rz-breadcrumb-list");
|
||||
|
||||
Assert.Equal(2, list.QuerySelectorAll("li.rz-breadcrumb-item").Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Bunit;
|
||||
using Bunit;
|
||||
using Xunit;
|
||||
|
||||
namespace Radzen.Blazor.Tests
|
||||
@@ -30,7 +30,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Icon, icon));
|
||||
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"" aria-hidden=""true"">{icon}</i>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -48,7 +48,7 @@ namespace Radzen.Blazor.Tests
|
||||
);
|
||||
|
||||
// does not render the actual icon when busy
|
||||
Assert.DoesNotContain(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.DoesNotContain(@$"<i class=""notranslate rz-button-icon-left rzi"" aria-hidden=""true"">{icon}</i>", component.Markup);
|
||||
|
||||
// renders the icon with busy spin animation
|
||||
Assert.Contains(@"<i style=""animation: rotation", component.Markup);
|
||||
@@ -71,7 +71,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.Icon, icon);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"" aria-hidden=""true"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<span class=""rz-button-text"">{text}</span>", component.Markup);
|
||||
}
|
||||
|
||||
|
||||
@@ -3444,7 +3444,7 @@ namespace Radzen.Blazor.Tests
|
||||
var wrapper = component.Find("div.rz-data-grid");
|
||||
Assert.Equal("grid", wrapper.GetAttribute("role"));
|
||||
Assert.Equal("0", wrapper.GetAttribute("tabindex"));
|
||||
Assert.False(string.IsNullOrEmpty(wrapper.GetAttribute("aria-activedescendant")));
|
||||
Assert.True(string.IsNullOrEmpty(wrapper.GetAttribute("aria-activedescendant")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -3467,7 +3467,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
var instance = component.Instance;
|
||||
|
||||
Assert.False(string.IsNullOrEmpty(instance.GetActiveDescendantId()));
|
||||
Assert.Null(instance.GetActiveDescendantId());
|
||||
|
||||
instance.HasActiveDescendant = () => false;
|
||||
Assert.Null(instance.GetActiveDescendantId());
|
||||
@@ -4083,7 +4083,7 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.DoesNotContain("2 columns showing", label.TextContent);
|
||||
Assert.Equal("Name", label.TextContent.Trim());
|
||||
|
||||
Assert.Equal("none", component.Find(".rz-column-picker th.rz-sortable-column").GetAttribute("aria-sort"));
|
||||
Assert.Null(component.Find(".rz-column-picker th.rz-sortable-column").GetAttribute("aria-sort"));
|
||||
component.Find(".rz-column-picker th.rz-sortable-column > div").Click();
|
||||
Assert.Equal("ascending", component.Find(".rz-column-picker th.rz-sortable-column").GetAttribute("aria-sort"));
|
||||
}
|
||||
|
||||
@@ -119,9 +119,11 @@ namespace Radzen.Blazor.Tests
|
||||
});
|
||||
|
||||
var searchInput = component.Find("input.rz-lookup-search-input");
|
||||
var grid = component.Find("div[role='grid']");
|
||||
|
||||
Assert.Equal("combobox", searchInput.GetAttribute("role"));
|
||||
Assert.NotNull(searchInput.GetAttribute("aria-controls"));
|
||||
Assert.Equal(grid.Id, searchInput.GetAttribute("aria-controls"));
|
||||
Assert.Equal("grid", searchInput.GetAttribute("aria-haspopup"));
|
||||
Assert.Equal("list", searchInput.GetAttribute("aria-autocomplete"));
|
||||
Assert.NotNull(searchInput.GetAttribute("aria-expanded"));
|
||||
}
|
||||
|
||||
@@ -974,6 +974,106 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.Equal("Filter by status", combobox.GetAttribute("aria-label"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_Multiple_AriaLabel_ReflectsSelectedItems()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var data = new[]
|
||||
{
|
||||
new DataItem { Text = "Item 1", Id = 1 },
|
||||
new DataItem { Text = "Item 2", Id = 2 },
|
||||
new DataItem { Text = "Item 3", Id = 3 },
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDropDown<IEnumerable<int>>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Data, data);
|
||||
parameters.Add(p => p.TextProperty, nameof(DataItem.Text));
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Id));
|
||||
parameters.Add(p => p.Multiple, true);
|
||||
parameters.Add(p => p.Value, new List<int> { 1, 3 });
|
||||
});
|
||||
|
||||
var combobox = component.Find("div[role='combobox']");
|
||||
|
||||
Assert.Equal("Item 1,Item 3", combobox.GetAttribute("aria-label"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_Multiple_AriaLabel_ShowsCount_WhenAboveMaxSelectedLabels()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var data = new[]
|
||||
{
|
||||
new DataItem { Text = "Item 1", Id = 1 },
|
||||
new DataItem { Text = "Item 2", Id = 2 },
|
||||
new DataItem { Text = "Item 3", Id = 3 },
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDropDown<IEnumerable<int>>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Data, data);
|
||||
parameters.Add(p => p.TextProperty, nameof(DataItem.Text));
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Id));
|
||||
parameters.Add(p => p.Multiple, true);
|
||||
parameters.Add(p => p.MaxSelectedLabels, 2);
|
||||
parameters.Add(p => p.Value, new List<int> { 1, 2, 3 });
|
||||
});
|
||||
|
||||
var combobox = component.Find("div[role='combobox']");
|
||||
|
||||
Assert.Equal($"3 {component.Instance.SelectedItemsText}", combobox.GetAttribute("aria-label"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_Chips_RemoveButtons_AreNotTabbable()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var data = new[]
|
||||
{
|
||||
new DataItem { Text = "Item 1", Id = 1 },
|
||||
new DataItem { Text = "Item 2", Id = 2 },
|
||||
};
|
||||
|
||||
var component = ctx.RenderComponent<RadzenDropDown<IEnumerable<int>>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Data, data);
|
||||
parameters.Add(p => p.TextProperty, nameof(DataItem.Text));
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Id));
|
||||
parameters.Add(p => p.Multiple, true);
|
||||
parameters.Add(p => p.Chips, true);
|
||||
parameters.Add(p => p.Value, new List<int> { 1, 2 });
|
||||
});
|
||||
|
||||
var buttons = component.FindAll(".rz-chip button");
|
||||
|
||||
Assert.NotEmpty(buttons);
|
||||
Assert.All(buttons, b => Assert.Equal("-1", b.GetAttribute("tabindex")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_HiddenHelperInput_IsHiddenFromAccessibilityTree()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = DropDown<int>(ctx, parameters =>
|
||||
{
|
||||
parameters.Add(p => p.ValueProperty, nameof(DataItem.Id));
|
||||
});
|
||||
|
||||
var hiddenInput = component.Find(".rz-helper-hidden-accessible input");
|
||||
|
||||
Assert.Equal("true", hiddenInput.GetAttribute("aria-hidden"));
|
||||
Assert.Equal("-1", hiddenInput.GetAttribute("tabindex"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DropDown_WithoutConsumerAriaLabel_FallsBackToComputedAriaLabel()
|
||||
{
|
||||
|
||||
@@ -271,7 +271,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.Data, new List<string> { "Apple", "Banana" });
|
||||
});
|
||||
|
||||
var listbox = component.Find("div[role=\"listbox\"]");
|
||||
var listbox = component.Find("ul[role=\"listbox\"]");
|
||||
|
||||
Assert.NotNull(listbox.GetAttribute("tabindex"));
|
||||
Assert.Equal("false", listbox.GetAttribute("aria-multiselectable"));
|
||||
@@ -289,7 +289,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.EmptyAriaLabel, "Fruits");
|
||||
});
|
||||
|
||||
var listbox = component.Find("div[role=\"listbox\"]");
|
||||
var listbox = component.Find("ul[role=\"listbox\"]");
|
||||
|
||||
Assert.Equal("Fruits", listbox.GetAttribute("aria-label"));
|
||||
}
|
||||
@@ -306,7 +306,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.Data, new List<string> { "Apple", "Banana" });
|
||||
});
|
||||
|
||||
var listbox = component.Find("div[role=\"listbox\"]");
|
||||
var listbox = component.Find("ul[role=\"listbox\"]");
|
||||
|
||||
Assert.Equal("true", listbox.GetAttribute("aria-multiselectable"));
|
||||
}
|
||||
@@ -366,13 +366,13 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.Data, new List<string> { "Apple", "Banana", "Cherry" });
|
||||
});
|
||||
|
||||
var listbox = component.Find("div[role=\"listbox\"]");
|
||||
var listbox = component.Find("ul[role=\"listbox\"]");
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(listbox.GetAttribute("aria-activedescendant")));
|
||||
|
||||
listbox.KeyDown(new KeyboardEventArgs { Key = "ArrowDown" });
|
||||
|
||||
listbox = component.Find("div[role=\"listbox\"]");
|
||||
listbox = component.Find("ul[role=\"listbox\"]");
|
||||
var active = listbox.GetAttribute("aria-activedescendant");
|
||||
|
||||
Assert.False(string.IsNullOrEmpty(active));
|
||||
|
||||
@@ -330,7 +330,7 @@ namespace Radzen.Blazor.Tests
|
||||
var toggle = component.Find("div.rz-navigation-item-wrapper[role=button]");
|
||||
toggle.KeyDown(new KeyboardEventArgs { Code = "ArrowDown" });
|
||||
|
||||
var activeId = component.Find("div.rz-navigation-item-wrapper[role=button]").GetAttribute("aria-activedescendant");
|
||||
var activeId = component.Find("ul.rz-navigation-menu").GetAttribute("aria-activedescendant");
|
||||
|
||||
Assert.False(string.IsNullOrEmpty(activeId));
|
||||
|
||||
@@ -364,7 +364,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.All(component.FindAll("li[role=menuitem]"), item => Assert.Equal("-1", item.GetAttribute("tabindex")));
|
||||
|
||||
var activeId = toggle.GetAttribute("aria-activedescendant");
|
||||
var activeId = component.Find("ul.rz-navigation-menu").GetAttribute("aria-activedescendant");
|
||||
Assert.False(string.IsNullOrEmpty(activeId));
|
||||
|
||||
var focusedItems = component.FindAll("li[role=menuitem].rz-state-focused");
|
||||
@@ -395,7 +395,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Equal(1, component.Instance.focusedIndex);
|
||||
|
||||
var activeId = component.Find("div.rz-navigation-item-wrapper[role=button]").GetAttribute("aria-activedescendant");
|
||||
var activeId = component.Find("ul.rz-navigation-menu").GetAttribute("aria-activedescendant");
|
||||
var lastItem = component.FindAll("li[role=menuitem]")[1];
|
||||
|
||||
Assert.Equal(lastItem.Id, activeId);
|
||||
@@ -449,7 +449,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Equal(-1, component.Instance.focusedIndex);
|
||||
|
||||
Assert.True(string.IsNullOrEmpty(component.Find("div.rz-navigation-item-wrapper[role=button]").GetAttribute("aria-activedescendant")));
|
||||
Assert.True(string.IsNullOrEmpty(component.Find("ul.rz-navigation-menu").GetAttribute("aria-activedescendant")));
|
||||
|
||||
var menu = component.Find("ul.rz-navigation-menu");
|
||||
Assert.Equal("true", menu.GetAttribute("aria-hidden"));
|
||||
|
||||
@@ -193,6 +193,68 @@ namespace Radzen.Blazor.Tests
|
||||
Assert.DoesNotContain("role=\"radiogroup\"", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectBar_SingleSelect_ArrowKeys_SelectFocusedItem_AndWrap()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenSelectBar<int>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Value, 1);
|
||||
parameters.Add(p => p.Items, builder =>
|
||||
{
|
||||
builder.OpenComponent<RadzenSelectBarItem>(0);
|
||||
builder.AddAttribute(1, "Text", "First");
|
||||
builder.AddAttribute(2, "Value", 1);
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.OpenComponent<RadzenSelectBarItem>(3);
|
||||
builder.AddAttribute(4, "Text", "Second");
|
||||
builder.AddAttribute(5, "Value", 2);
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
var radiogroup = component.Find("div[role=\"radiogroup\"]");
|
||||
|
||||
radiogroup.KeyDown(new Microsoft.AspNetCore.Components.Web.KeyboardEventArgs { Code = "ArrowRight" });
|
||||
|
||||
Assert.Equal(2, component.Instance.Value);
|
||||
|
||||
radiogroup = component.Find("div[role=\"radiogroup\"]");
|
||||
radiogroup.KeyDown(new Microsoft.AspNetCore.Components.Web.KeyboardEventArgs { Code = "ArrowRight" });
|
||||
|
||||
Assert.Equal(1, component.Instance.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectBar_Multiple_ArrowKeys_DoNotToggleSelection()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenSelectBar<System.Collections.Generic.IEnumerable<int>>>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Multiple, true);
|
||||
parameters.Add(p => p.Value, new System.Collections.Generic.List<int> { 1 });
|
||||
parameters.Add(p => p.Items, builder =>
|
||||
{
|
||||
builder.OpenComponent<RadzenSelectBarItem>(0);
|
||||
builder.AddAttribute(1, "Text", "First");
|
||||
builder.AddAttribute(2, "Value", 1);
|
||||
builder.CloseComponent();
|
||||
|
||||
builder.OpenComponent<RadzenSelectBarItem>(3);
|
||||
builder.AddAttribute(4, "Text", "Second");
|
||||
builder.AddAttribute(5, "Value", 2);
|
||||
builder.CloseComponent();
|
||||
});
|
||||
});
|
||||
|
||||
var toolbar = component.Find("div[role=\"toolbar\"]");
|
||||
|
||||
toolbar.KeyDown(new Microsoft.AspNetCore.Components.Web.KeyboardEventArgs { Code = "ArrowRight" });
|
||||
|
||||
Assert.Equal(new[] { 1 }, System.Linq.Enumerable.ToArray(component.Instance.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectBar_Renders_AriaLabelledBy()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Bunit;
|
||||
using Bunit;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Xunit;
|
||||
@@ -32,34 +32,34 @@ namespace Radzen.Blazor.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitButton_Renders_Wrapper_AriaHasPopupAndExpanded()
|
||||
public void SplitButton_Renders_ToggleButton_AriaHasPopupAndExpanded()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = RenderWithItems(ctx);
|
||||
|
||||
var wrapper = component.Find("div.rz-splitbutton");
|
||||
var toggle = component.Find("button.rz-splitbutton-menubutton");
|
||||
|
||||
Assert.Equal("menu", wrapper.GetAttribute("aria-haspopup"));
|
||||
Assert.Equal("false", wrapper.GetAttribute("aria-expanded"));
|
||||
Assert.Equal("menu", toggle.GetAttribute("aria-haspopup"));
|
||||
Assert.Equal("false", toggle.GetAttribute("aria-expanded"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitButton_AltArrowDown_OpensMenu_SetsAriaExpandedAndActiveDescendant()
|
||||
public void SplitButton_ArrowDown_OpensMenu_SetsAriaExpandedAndActiveDescendant()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = RenderWithItems(ctx);
|
||||
|
||||
component.Find("div.rz-splitbutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown", AltKey = true });
|
||||
component.Find("button.rz-splitbutton-menubutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown" });
|
||||
|
||||
var wrapper = component.Find("div.rz-splitbutton");
|
||||
var toggle = component.Find("button.rz-splitbutton-menubutton");
|
||||
|
||||
Assert.Equal("true", wrapper.GetAttribute("aria-expanded"));
|
||||
Assert.Equal("true", toggle.GetAttribute("aria-expanded"));
|
||||
|
||||
var activeDescendant = wrapper.GetAttribute("aria-activedescendant");
|
||||
var activeDescendant = component.Find(@"ul[role=""menu""]").GetAttribute("aria-activedescendant");
|
||||
Assert.False(string.IsNullOrEmpty(activeDescendant));
|
||||
|
||||
var firstItem = component.FindAll(@"li[role=""menuitem""]")[0];
|
||||
@@ -74,12 +74,11 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
var component = RenderWithItems(ctx);
|
||||
|
||||
var wrapper = component.Find("div.rz-splitbutton");
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Code = "ArrowDown", AltKey = true });
|
||||
component.Find("div.rz-splitbutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown" });
|
||||
component.Find("button.rz-splitbutton-menubutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown" });
|
||||
component.Find(@"ul[role=""menu""]").KeyDown(new KeyboardEventArgs { Code = "ArrowDown" });
|
||||
|
||||
var items = component.FindAll(@"li[role=""menuitem""]");
|
||||
var activeDescendant = component.Find("div.rz-splitbutton").GetAttribute("aria-activedescendant");
|
||||
var activeDescendant = component.Find(@"ul[role=""menu""]").GetAttribute("aria-activedescendant");
|
||||
|
||||
Assert.Equal(items[1].Id, activeDescendant);
|
||||
Assert.Equal("-1", items[0].GetAttribute("tabindex"));
|
||||
@@ -94,11 +93,11 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
var component = RenderWithItems(ctx);
|
||||
|
||||
component.Find("div.rz-splitbutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown", AltKey = true });
|
||||
component.Find("div.rz-splitbutton").KeyDown(new KeyboardEventArgs { Code = "End" });
|
||||
component.Find("button.rz-splitbutton-menubutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown" });
|
||||
component.Find(@"ul[role=""menu""]").KeyDown(new KeyboardEventArgs { Code = "End" });
|
||||
|
||||
var items = component.FindAll(@"li[role=""menuitem""]");
|
||||
var activeDescendant = component.Find("div.rz-splitbutton").GetAttribute("aria-activedescendant");
|
||||
var activeDescendant = component.Find(@"ul[role=""menu""]").GetAttribute("aria-activedescendant");
|
||||
|
||||
Assert.Equal(items[items.Count - 1].Id, activeDescendant);
|
||||
}
|
||||
@@ -111,16 +110,32 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
var component = RenderWithItems(ctx);
|
||||
|
||||
component.Find("div.rz-splitbutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown", AltKey = true });
|
||||
component.Find("div.rz-splitbutton").KeyDown(new KeyboardEventArgs { Code = "End" });
|
||||
component.Find("div.rz-splitbutton").KeyDown(new KeyboardEventArgs { Code = "Home" });
|
||||
component.Find("button.rz-splitbutton-menubutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown" });
|
||||
component.Find(@"ul[role=""menu""]").KeyDown(new KeyboardEventArgs { Code = "End" });
|
||||
component.Find(@"ul[role=""menu""]").KeyDown(new KeyboardEventArgs { Code = "Home" });
|
||||
|
||||
var items = component.FindAll(@"li[role=""menuitem""]");
|
||||
var activeDescendant = component.Find("div.rz-splitbutton").GetAttribute("aria-activedescendant");
|
||||
var activeDescendant = component.Find(@"ul[role=""menu""]").GetAttribute("aria-activedescendant");
|
||||
|
||||
Assert.Equal(items[0].Id, activeDescendant);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitButton_ArrowUp_OpensMenu_FocusesLastItem()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
|
||||
var component = RenderWithItems(ctx);
|
||||
|
||||
component.Find("button.rz-splitbutton-menubutton").KeyDown(new KeyboardEventArgs { Code = "ArrowUp" });
|
||||
|
||||
var items = component.FindAll(@"li[role=""menuitem""]");
|
||||
var activeDescendant = component.Find(@"ul[role=""menu""]").GetAttribute("aria-activedescendant");
|
||||
|
||||
Assert.Equal(items[items.Count - 1].Id, activeDescendant);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SplitButton_Escape_ClosesMenu_ClearsAriaExpandedAndActiveDescendant()
|
||||
{
|
||||
@@ -129,13 +144,13 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
var component = RenderWithItems(ctx);
|
||||
|
||||
component.Find("div.rz-splitbutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown", AltKey = true });
|
||||
Assert.Equal("true", component.Find("div.rz-splitbutton").GetAttribute("aria-expanded"));
|
||||
component.Find("button.rz-splitbutton-menubutton").KeyDown(new KeyboardEventArgs { Code = "ArrowDown" });
|
||||
Assert.Equal("true", component.Find("button.rz-splitbutton-menubutton").GetAttribute("aria-expanded"));
|
||||
|
||||
component.Find("div.rz-splitbutton").KeyDown(new KeyboardEventArgs { Code = "Escape" });
|
||||
component.Find(@"ul[role=""menu""]").KeyDown(new KeyboardEventArgs { Code = "Escape" });
|
||||
|
||||
Assert.Equal("false", component.Find("div.rz-splitbutton").GetAttribute("aria-expanded"));
|
||||
Assert.Null(component.Find("div.rz-splitbutton").GetAttribute("aria-activedescendant"));
|
||||
Assert.Equal("false", component.Find("button.rz-splitbutton-menubutton").GetAttribute("aria-expanded"));
|
||||
Assert.Null(component.Find(@"ul[role=""menu""]").GetAttribute("aria-activedescendant"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -180,7 +195,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
component.SetParametersAndRender(parameters => parameters.Add(p => p.Icon, icon));
|
||||
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"" aria-hidden=""true"">{icon}</i>", component.Markup);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -199,7 +214,7 @@ namespace Radzen.Blazor.Tests
|
||||
parameters.Add(p => p.Icon, icon);
|
||||
});
|
||||
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<i class=""notranslate rz-button-icon-left rzi"" aria-hidden=""true"">{icon}</i>", component.Markup);
|
||||
Assert.Contains(@$"<span class=""rz-button-text"">{text}</span>", component.Markup);
|
||||
}
|
||||
|
||||
|
||||
@@ -108,24 +108,26 @@ namespace Radzen.Blazor.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tabs_Wrapper_IsFocusTarget_WithRoleTablist()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenTabs>();
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
Assert.Equal("tablist", wrapper.GetAttribute("role"));
|
||||
Assert.Equal("0", wrapper.GetAttribute("tabindex"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tabs_InnerNav_HasRolePresentation_ToAvoidDuplicateTablist()
|
||||
public void Tabs_Nav_IsFocusTarget_WithRoleTablist()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenTabs>();
|
||||
|
||||
var nav = component.Find("ul.rz-tabview-nav");
|
||||
Assert.NotEqual("tablist", nav.GetAttribute("role"));
|
||||
Assert.Equal("tablist", nav.GetAttribute("role"));
|
||||
Assert.Equal("0", nav.GetAttribute("tabindex"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Tabs_Wrapper_HasNoRole_ToAvoidTablistOwningPanels()
|
||||
{
|
||||
using var ctx = new TestContext();
|
||||
var component = ctx.RenderComponent<RadzenTabs>();
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
Assert.Null(wrapper.GetAttribute("role"));
|
||||
Assert.Null(wrapper.GetAttribute("tabindex"));
|
||||
Assert.Null(wrapper.GetAttribute("aria-activedescendant"));
|
||||
}
|
||||
|
||||
static RenderFragment TabsFragment(params string[] titles) => builder =>
|
||||
@@ -147,7 +149,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
var active = wrapper.GetAttribute("aria-activedescendant");
|
||||
Assert.False(string.IsNullOrEmpty(active));
|
||||
|
||||
@@ -307,7 +309,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
Assert.Contains("First-Content", component.Markup);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
// Simulate non-navigation keystrokes (e.g. a barcode scanner) on the focused tablist.
|
||||
// Pre-fix: the second keypress latched shouldRender = false, blocking all later renders.
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "a", Code = "KeyA" });
|
||||
@@ -334,7 +336,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two", "Three"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
Assert.Equal(expected, wrapper.GetAttribute("aria-orientation"));
|
||||
}
|
||||
|
||||
@@ -345,7 +347,7 @@ namespace Radzen.Blazor.Tests
|
||||
|
||||
static string ActiveDescendantText(IRenderedComponent<RadzenTabs> component)
|
||||
{
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
var active = wrapper.GetAttribute("aria-activedescendant");
|
||||
return component.Find($"[id='{active}']").TextContent;
|
||||
}
|
||||
@@ -360,7 +362,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two", "Three"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "ArrowDown", Code = "ArrowDown" });
|
||||
|
||||
Assert.Equal("Two", ActiveDescendantText(component));
|
||||
@@ -376,7 +378,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two", "Three"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "ArrowUp", Code = "ArrowUp" });
|
||||
|
||||
Assert.Equal("Two", ActiveDescendantText(component));
|
||||
@@ -392,7 +394,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two", "Three"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "ArrowRight", Code = "ArrowRight" });
|
||||
Assert.Equal("Two", ActiveDescendantText(component));
|
||||
|
||||
@@ -410,7 +412,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two", "Three"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "ArrowRight", Code = "ArrowRight" });
|
||||
|
||||
Assert.Equal("Two", ActiveDescendantText(component));
|
||||
@@ -426,7 +428,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two", "Three"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "ArrowDown", Code = "ArrowDown" });
|
||||
Assert.Equal("Two", ActiveDescendantText(component));
|
||||
|
||||
@@ -444,7 +446,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two", "Three"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "End", Code = "End" });
|
||||
Assert.Equal("Three", ActiveDescendantText(component));
|
||||
@@ -465,7 +467,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragmentWithContent(("One", "One-Content"), ("Two", "Two-Content"), ("Three", "Three-Content")))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "ArrowDown", Code = "ArrowDown" });
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "Enter", Code = "Enter" });
|
||||
|
||||
@@ -482,7 +484,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
Assert.Equal("Sections", wrapper.GetAttribute("aria-label"));
|
||||
}
|
||||
|
||||
@@ -495,7 +497,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
Assert.Equal("heading-id", wrapper.GetAttribute("aria-labelledby"));
|
||||
}
|
||||
|
||||
@@ -522,7 +524,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two", "Three"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "ArrowRight", Code = "ArrowRight" });
|
||||
|
||||
Assert.Equal("One", ActiveDescendantText(component));
|
||||
@@ -538,7 +540,7 @@ namespace Radzen.Blazor.Tests
|
||||
.Add(p => p.Tabs, TabsFragment("One", "Two", "Three"))
|
||||
);
|
||||
|
||||
var wrapper = component.Find("div.rz-tabview");
|
||||
var wrapper = component.Find("ul.rz-tabview-nav");
|
||||
wrapper.KeyDown(new KeyboardEventArgs { Key = "ArrowLeft", Code = "ArrowLeft" });
|
||||
|
||||
Assert.Equal("Three", ActiveDescendantText(component));
|
||||
|
||||
@@ -530,6 +530,17 @@ namespace Radzen
|
||||
return await TryCloseAsync(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to close the side dialog. Called from JavaScript ESC handler.
|
||||
/// </summary>
|
||||
/// <param name="result">The result.</param>
|
||||
/// <returns><c>true</c> if the side dialog was closed; <c>false</c> if closing was prevented.</returns>
|
||||
[JSInvokable("DialogService.TryCloseSide")]
|
||||
public virtual async Task<bool> TryCloseSideFromJs(dynamic? result = null)
|
||||
{
|
||||
return await TryCloseSideAsync(result);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -557,6 +568,7 @@ namespace Radzen
|
||||
options.Style = !String.IsNullOrEmpty(options.Style) ? options.Style : "";
|
||||
options.CssClass = !String.IsNullOrEmpty(options.CssClass) ? $"rz-dialog-confirm {options.CssClass}" : "rz-dialog-confirm";
|
||||
options.WrapperCssClass = !String.IsNullOrEmpty(options.WrapperCssClass) ? $"rz-dialog-wrapper {options.WrapperCssClass}" : "rz-dialog-wrapper";
|
||||
options.Role = "alertdialog";
|
||||
|
||||
return await OpenAsync(title, ds =>
|
||||
{
|
||||
@@ -606,6 +618,7 @@ namespace Radzen
|
||||
options.Style = !String.IsNullOrEmpty(options.Style) ? options.Style : "";
|
||||
options.CssClass = !String.IsNullOrEmpty(options.CssClass) ? $"rz-dialog-confirm {options.CssClass}" : "rz-dialog-confirm";
|
||||
options.WrapperCssClass = !String.IsNullOrEmpty(options.WrapperCssClass) ? $"rz-dialog-wrapper {options.WrapperCssClass}" : "rz-dialog-wrapper";
|
||||
options.Role = "alertdialog";
|
||||
|
||||
return await OpenAsync(title, ds =>
|
||||
{
|
||||
@@ -654,6 +667,7 @@ namespace Radzen
|
||||
options.Style = !String.IsNullOrEmpty(options.Style) ? options.Style : "";
|
||||
options.CssClass = !String.IsNullOrEmpty(options.CssClass) ? $"rz-dialog-alert {options.CssClass}" : "rz-dialog-alert";
|
||||
options.WrapperCssClass = !String.IsNullOrEmpty(options.WrapperCssClass) ? $"rz-dialog-wrapper {options.WrapperCssClass}" : "rz-dialog-wrapper";
|
||||
options.Role = "alertdialog";
|
||||
options.ContentCssClass = !String.IsNullOrEmpty(options.ContentCssClass) ? $"rz-dialog-content {options.ContentCssClass}" : "rz-dialog-content";
|
||||
|
||||
return await OpenAsync(title, ds =>
|
||||
@@ -697,6 +711,7 @@ namespace Radzen
|
||||
options.Style = !String.IsNullOrEmpty(options.Style) ? options.Style : "";
|
||||
options.CssClass = !String.IsNullOrEmpty(options.CssClass) ? $"rz-dialog-alert {options.CssClass}" : "rz-dialog-alert";
|
||||
options.WrapperCssClass = !String.IsNullOrEmpty(options.WrapperCssClass) ? $"rz-dialog-wrapper {options.WrapperCssClass}" : "rz-dialog-wrapper";
|
||||
options.Role = "alertdialog";
|
||||
options.ContentCssClass = !String.IsNullOrEmpty(options.ContentCssClass) ? $"rz-dialog-content {options.ContentCssClass}" : "rz-dialog-content";
|
||||
|
||||
return await OpenAsync(title, ds =>
|
||||
@@ -1074,7 +1089,7 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
private bool autoFocusFirstElement;
|
||||
private bool autoFocusFirstElement = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to focus the first focusable HTML element. Set to <c>true</c> by default.
|
||||
@@ -1371,6 +1386,8 @@ namespace Radzen
|
||||
}
|
||||
}
|
||||
|
||||
internal string Role { get; set; } = "dialog";
|
||||
|
||||
private bool closeDialogOnEsc = true;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -941,6 +941,12 @@ namespace Radzen
|
||||
await OnSelectItem(null, true);
|
||||
}
|
||||
|
||||
if (Multiple && !isFilter && selectedItems.Count > 0)
|
||||
{
|
||||
selectedIndex = -1;
|
||||
await ClearAll();
|
||||
}
|
||||
|
||||
if (AllowFiltering && isFilter)
|
||||
{
|
||||
Debounce(DebounceFilter, FilterDelay);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
role="heading" aria-level="@AriaLevel">
|
||||
<button type="button" @ref="@item.HeaderElement" @onclick="@((args) => SelectItem(item))"
|
||||
@onkeydown="@(args => OnHeaderKeyDown(args, item))" @onkeydown:preventDefault="preventKeyPress" disabled="@item.Disabled"
|
||||
aria-label="@ItemAriaLabel(i, item)" title="@ItemTitle(i, item)"
|
||||
aria-label="@(string.IsNullOrEmpty(item.Text) ? ItemAriaLabel(i, item) : null)" title="@(string.IsNullOrEmpty(item.Text) ? ItemTitle(i, item) : null)"
|
||||
id="@accordionId" aria-controls="@($"{accordionId}-content")" aria-expanded="@(item.GetSelected() ? "true" : "false")">
|
||||
<span class="@ToggleIconClass(item)">keyboard_arrow_down</span>
|
||||
@if (!string.IsNullOrEmpty(item.Icon))
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
@if (AllowClose)
|
||||
{
|
||||
<RadzenButton Click=@OnClose Icon="close" Variant="Variant.Text" ButtonStyle="@GetCloseButtonStyle()" Shade="@GetCloseButtonShade()" Size="@GetCloseButtonSize()" />
|
||||
<RadzenButton Click=@OnClose Icon="close" aria-label="@CloseAriaLabel" Variant="Variant.Text" ButtonStyle="@GetCloseButtonStyle()" Shade="@GetCloseButtonShade()" Size="@GetCloseButtonSize()" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@@ -126,6 +126,15 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public AlertSize Size { get; set; } = AlertSize.Medium;
|
||||
|
||||
private string? closeAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label of the close button.
|
||||
/// </summary>
|
||||
/// <value>The close button aria-label.</value>
|
||||
[Parameter]
|
||||
public string CloseAriaLabel { get => closeAriaLabel ?? Localize(nameof(RadzenStrings.Alert_CloseAriaLabel)); set => closeAriaLabel = value; }
|
||||
|
||||
ButtonSize GetCloseButtonSize()
|
||||
{
|
||||
return Size == AlertSize.ExtraSmall ? ButtonSize.ExtraSmall : ButtonSize.Small;
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
hasItems = true;
|
||||
itemIndex++;
|
||||
<li role="option" id="@ItemId(itemIndex)" class="rz-autocomplete-list-item" tabindex="-1"
|
||||
aria-selected="@(object.Equals(item, SelectedItem) ? "true" : "false")"
|
||||
aria-selected="@(selectedIndex >= 0 ? (itemIndex == selectedIndex ? "true" : "false") : (object.Equals(item, SelectedItem) ? "true" : "false"))"
|
||||
@onclick="@(() => OnSelectItem(item))" onmousedown="Radzen.activeElement = null">
|
||||
<span>
|
||||
@if (Template != null)
|
||||
|
||||
@@ -160,6 +160,7 @@ namespace Radzen.Blazor
|
||||
|
||||
string? customSearchText;
|
||||
int selectedIndex = -1;
|
||||
bool popupOpened;
|
||||
|
||||
/// <summary>
|
||||
/// Handles the FilterKeyPress event.
|
||||
@@ -195,19 +196,16 @@ namespace Radzen.Blazor
|
||||
selectedIndex = -1;
|
||||
}
|
||||
|
||||
if (key == "Tab" && JSRuntime != null)
|
||||
if (key == "Tab")
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
await ClosePopup();
|
||||
}
|
||||
}
|
||||
else if (key == "Escape")
|
||||
{
|
||||
selectedIndex = -1;
|
||||
|
||||
if (JSRuntime != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
}
|
||||
await ClosePopup();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -230,7 +228,8 @@ namespace Radzen.Blazor
|
||||
|
||||
if (value.Length < MinLength && !OpenOnFocus)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
await ClosePopup();
|
||||
await InvokeAsync(() => { StateHasChanged(); });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -260,14 +259,48 @@ namespace Radzen.Blazor
|
||||
|
||||
private string? ActiveDescendantId => selectedIndex >= 0 ? ItemId(selectedIndex) : null;
|
||||
|
||||
private bool IsPopupOpen => OpenOnFocus || (!string.IsNullOrEmpty(searchText) || !string.IsNullOrEmpty(customSearchText));
|
||||
private bool IsPopupOpen => popupOpened;
|
||||
|
||||
private async Task OnSelectItem(object item)
|
||||
/// <summary>
|
||||
/// Invoked from client-side code when the suggestion popup opens.
|
||||
/// </summary>
|
||||
[JSInvokable]
|
||||
public async Task OnPopupOpen()
|
||||
{
|
||||
if (!popupOpened)
|
||||
{
|
||||
popupOpened = true;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked from client-side code when the suggestion popup closes.
|
||||
/// </summary>
|
||||
[JSInvokable]
|
||||
public async Task OnPopupClose()
|
||||
{
|
||||
if (popupOpened || selectedIndex != -1)
|
||||
{
|
||||
popupOpened = false;
|
||||
selectedIndex = -1;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ClosePopup()
|
||||
{
|
||||
popupOpened = false;
|
||||
|
||||
if (JSRuntime != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closePopup", PopupID);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSelectItem(object item)
|
||||
{
|
||||
await ClosePopup();
|
||||
|
||||
await SelectItem(item);
|
||||
}
|
||||
@@ -421,7 +454,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
_jsRef = await JSRuntime.InvokeAsync<IJSObjectReference>(
|
||||
"Radzen.createAutoComplete", Element, PopupID, OpenOnFocus);
|
||||
"Radzen.createAutoComplete", Element, PopupID, OpenOnFocus, Reference, nameof(OnPopupOpen), nameof(OnPopupClose));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,6 +492,8 @@ namespace Radzen.Blazor
|
||||
|
||||
if (shouldClose && !firstRender && JSRuntime != null)
|
||||
{
|
||||
popupOpened = false;
|
||||
selectedIndex = -1;
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.destroyPopup", PopupID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@inherits RadzenComponentWithChildren
|
||||
|
||||
<CascadingValue Value="@Template">
|
||||
@if (Visible)
|
||||
{
|
||||
<nav class="@GetCssClass()" style="@Style" @attributes="@Attributes" id="@GetId()" aria-label="@AriaLabel">
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
<ol class="rz-breadcrumb-list">
|
||||
<CascadingValue Value="this">
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
</CascadingValue>
|
||||
</ol>
|
||||
</nav>
|
||||
}
|
||||
</CascadingValue>
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
{
|
||||
@@ -52,6 +53,39 @@ namespace Radzen.Blazor
|
||||
{
|
||||
return "rz-breadcrumb";
|
||||
}
|
||||
|
||||
readonly List<RadzenBreadCrumbItem> items = new List<RadzenBreadCrumbItem>();
|
||||
|
||||
internal void AddItem(RadzenBreadCrumbItem item)
|
||||
{
|
||||
if (!items.Contains(item))
|
||||
{
|
||||
var previousLast = items.Count > 0 ? items[items.Count - 1] : null;
|
||||
|
||||
items.Add(item);
|
||||
|
||||
previousLast?.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveItem(RadzenBreadCrumbItem item)
|
||||
{
|
||||
if (items.Remove(item) && !disposed && items.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
items[items.Count - 1].Refresh();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsLastItem(RadzenBreadCrumbItem item)
|
||||
{
|
||||
return items.Count > 0 && items[items.Count - 1] == item;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@inherits RadzenComponent
|
||||
@inherits RadzenComponent
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div class="@GetCssClass()" id="@GetId()" style="@Style" @attributes="@Attributes">
|
||||
<li class="@GetCssClass()" id="@GetId()" style="@Style" @attributes="@Attributes" aria-current="@ItemAriaCurrent">
|
||||
@if (ChildContent != null)
|
||||
{
|
||||
@ChildContent
|
||||
@@ -32,5 +32,5 @@
|
||||
<span class="rz-label" aria-current="page">@Text</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</li>
|
||||
}
|
||||
@@ -13,6 +13,12 @@ namespace Radzen.Blazor
|
||||
[CascadingParameter]
|
||||
public RenderFragment<RadzenBreadCrumbItem>? Template { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="RadzenBreadCrumb"/> component this item belongs to. Set via cascading value.
|
||||
/// </summary>
|
||||
[CascadingParameter]
|
||||
public RadzenBreadCrumb? BreadCrumb { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Displayed Text
|
||||
/// </summary>
|
||||
@@ -50,5 +56,30 @@ namespace Radzen.Blazor
|
||||
{
|
||||
return "rz-breadcrumb-item";
|
||||
}
|
||||
|
||||
string? ItemAriaCurrent => ChildContent == null && Template == null && string.IsNullOrWhiteSpace(Path)
|
||||
? null
|
||||
: BreadCrumb?.IsLastItem(this) == true ? "page" : null;
|
||||
|
||||
internal void Refresh()
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
|
||||
BreadCrumb?.AddItem(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Dispose()
|
||||
{
|
||||
BreadCrumb?.RemoveItem(this);
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
{
|
||||
@if (!string.IsNullOrEmpty(@Icon))
|
||||
{
|
||||
<i class="notranslate rz-button-icon-left rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@Icon</i>
|
||||
<i class="notranslate rz-button-icon-left rzi" aria-hidden="true" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@Icon</i>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Image))
|
||||
{
|
||||
|
||||
@@ -4,26 +4,30 @@
|
||||
<CascadingValue Value=this>
|
||||
@if (Visible)
|
||||
{
|
||||
<section @ref=@Element style=@Style @attributes=@Attributes class=@GetCssClass() id=@GetId() tabindex="0">
|
||||
<section @ref=@Element style=@Style @attributes=@Attributes class=@GetCssClass() id=@GetId() tabindex="0"
|
||||
aria-roledescription="carousel" aria-label="@AriaLabel"
|
||||
@onmouseenter="@OnCarouselMouseEnter" @onmouseleave="@OnCarouselMouseLeave"
|
||||
@onfocusin="@OnCarouselFocusIn" @onfocusout="@OnCarouselFocusOut"
|
||||
@onkeydown="@OnCarouselKeyDown" @onkeydown:preventDefault=preventKeyPress>
|
||||
@if(AllowPaging && (PagerPosition == PagerPosition.Top || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenStack class="rz-carousel-pager rz-carousel-pager-top" Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Center" Wrap="FlexWrap.Wrap" role="list">
|
||||
<RadzenStack class="rz-carousel-pager rz-carousel-pager-top" Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Center" Wrap="FlexWrap.Wrap">
|
||||
@for (var p = 0; p < PageCount; p++)
|
||||
{
|
||||
var pageIndex = p;
|
||||
var itemIndex = pageIndex * ItemsPerPage;
|
||||
<button type="button" role="listitem" @onclick="@(args => Navigate(itemIndex))" class="rz-carousel-pager-button @(pageIndex == ActivePage ? "rz-state-active" : "")" aria-label="@string.Format(PagerButtonAriaLabelFormat, pageIndex + 1)"></button>
|
||||
<button type="button" @onclick="@(args => Navigate(itemIndex))" class="rz-carousel-pager-button @(pageIndex == ActivePage ? "rz-state-active" : "")" aria-label="@string.Format(PagerButtonAriaLabelFormat, pageIndex + 1)" aria-current="@(pageIndex == ActivePage ? "true" : null)"></button>
|
||||
}
|
||||
</RadzenStack>
|
||||
}
|
||||
@if(AllowNavigation)
|
||||
{
|
||||
<RadzenButton class="rz-carousel-prev" Icon="@PrevIcon" Text="@PrevText" ButtonStyle="@ButtonStyle" Size="@ButtonSize" Variant="@ButtonVariant" Shade="@ButtonShade"
|
||||
Click=@Prev />
|
||||
aria-label="@(string.IsNullOrEmpty(PrevText) ? PrevAriaLabel : null)" Click=@Prev />
|
||||
<RadzenButton class="rz-carousel-next" Icon="@NextIcon" Text="@NextText" ButtonStyle="@ButtonStyle" Size="@ButtonSize" Variant="@ButtonVariant" Shade="@ButtonShade"
|
||||
Click=@Next/>
|
||||
aria-label="@(string.IsNullOrEmpty(NextText) ? NextAriaLabel : null)" Click=@Next/>
|
||||
}
|
||||
<ul @ref="itemsElement" class="rz-carousel-items @(AllowScroll ? "" : "rz-carousel-no-scroll")"
|
||||
<ul @ref="itemsElement" role="presentation" class="rz-carousel-items @(AllowScroll ? "" : "rz-carousel-no-scroll")"
|
||||
@ontouchstart="OnTouchStart"
|
||||
@ontouchend="OnTouchEnd"
|
||||
@ontouchcancel="OnTouchCancel">
|
||||
@@ -31,12 +35,12 @@
|
||||
</ul>
|
||||
@if(AllowPaging && (PagerPosition == PagerPosition.Bottom || PagerPosition == PagerPosition.TopAndBottom))
|
||||
{
|
||||
<RadzenStack class="rz-carousel-pager rz-carousel-pager-bottom" Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Center" Wrap="FlexWrap.Wrap" role="list">
|
||||
<RadzenStack class="rz-carousel-pager rz-carousel-pager-bottom" Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Center" Wrap="FlexWrap.Wrap">
|
||||
@for (var p = 0; p < PageCount; p++)
|
||||
{
|
||||
var pageIndex = p;
|
||||
var itemIndex = pageIndex * ItemsPerPage;
|
||||
<button type="button" role="listitem" @onclick="@(args => Navigate(itemIndex))" class="rz-carousel-pager-button @(pageIndex == ActivePage ? "rz-state-active" : "")" aria-label="@string.Format(PagerButtonAriaLabelFormat, pageIndex + 1)"></button>
|
||||
<button type="button" @onclick="@(args => Navigate(itemIndex))" class="rz-carousel-pager-button @(pageIndex == ActivePage ? "rz-state-active" : "")" aria-label="@string.Format(PagerButtonAriaLabelFormat, pageIndex + 1)" aria-current="@(pageIndex == ActivePage ? "true" : null)"></button>
|
||||
}
|
||||
</RadzenStack>
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Radzen.Blazor
|
||||
/// RadzenCarousel displays one item at a time with automatic or manual advancement and various navigation options.
|
||||
/// Perfect for image galleries, product showcases, hero sections, or any content that benefits from sequential presentation.
|
||||
/// Features automatic advancement with configurable interval, Previous/Next buttons with customizable icons and text, dot indicators or page numbers for direct item selection,
|
||||
/// infinite loop for continuous cycling from last to first item, keyboard control (Arrow keys for navigation, Page Up/Down for first/last), swipe gestures on touch devices,
|
||||
/// infinite loop for continuous cycling from last to first item, keyboard control (Left/Right Arrow keys for navigation), swipe gestures on touch devices,
|
||||
/// and customization of button styles, pager position (top/bottom/overlay), and navigation visibility.
|
||||
/// Items are defined using RadzenCarouselItem components. Each item can contain images, text, or complex layouts. Use Auto property to enable automatic cycling, and Interval to control slide duration.
|
||||
/// </summary>
|
||||
@@ -98,7 +98,14 @@ namespace Radzen.Blazor
|
||||
{
|
||||
if (Auto)
|
||||
{
|
||||
await Reset();
|
||||
if (hovered || focused)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
await Reset();
|
||||
}
|
||||
}
|
||||
|
||||
await GoTo(index);
|
||||
@@ -228,6 +235,106 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string PagerButtonAriaLabelFormat { get => pagerButtonAriaLabelFormat ?? Localize(nameof(RadzenStrings.Carousel_PagerButtonAriaLabelFormat)); set => pagerButtonAriaLabelFormat = value; }
|
||||
|
||||
private string? prevAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label of the previous button.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string PrevAriaLabel { get => prevAriaLabel ?? Localize(nameof(RadzenStrings.Carousel_PrevAriaLabel)); set => prevAriaLabel = value; }
|
||||
|
||||
private string? nextAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label of the next button.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string NextAriaLabel { get => nextAriaLabel ?? Localize(nameof(RadzenStrings.Carousel_NextAriaLabel)); set => nextAriaLabel = value; }
|
||||
|
||||
private string? slideAriaLabelFormat;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the slide aria-label format. Use {0} for the 1-based slide index and {1} for the total slide count.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string SlideAriaLabelFormat { get => slideAriaLabelFormat ?? Localize(nameof(RadzenStrings.Carousel_SlideAriaLabelFormat)); set => slideAriaLabelFormat = value; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label of the carousel container.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string? AriaLabel { get; set; }
|
||||
|
||||
internal string GetSlideAriaLabel(RadzenCarouselItem item)
|
||||
{
|
||||
return string.Format(System.Globalization.CultureInfo.CurrentCulture, SlideAriaLabelFormat, items.IndexOf(item) + 1, items.Count);
|
||||
}
|
||||
|
||||
bool hovered;
|
||||
bool focused;
|
||||
bool preventKeyPress;
|
||||
|
||||
void UpdateAutoCycle()
|
||||
{
|
||||
if (!Auto)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (hovered || focused)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
void OnCarouselMouseEnter()
|
||||
{
|
||||
hovered = true;
|
||||
UpdateAutoCycle();
|
||||
}
|
||||
|
||||
void OnCarouselMouseLeave()
|
||||
{
|
||||
hovered = false;
|
||||
UpdateAutoCycle();
|
||||
}
|
||||
|
||||
void OnCarouselFocusIn()
|
||||
{
|
||||
focused = true;
|
||||
UpdateAutoCycle();
|
||||
}
|
||||
|
||||
void OnCarouselFocusOut()
|
||||
{
|
||||
focused = false;
|
||||
UpdateAutoCycle();
|
||||
}
|
||||
|
||||
async Task OnCarouselKeyDown(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
if (key == "ArrowLeft")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
await Prev();
|
||||
}
|
||||
else if (key == "ArrowRight")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
await Next();
|
||||
}
|
||||
else
|
||||
{
|
||||
preventKeyPress = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task SetParametersAsync(ParameterView parameters)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@implements IDisposable
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
<li @ref="element" @attributes=@Attributes class=@Class style=@ItemStyle tabindex="@(IsActive ? "0" : "-1")" inert="@(!IsActive)">
|
||||
<li @ref="element" role="group" aria-roledescription="slide" aria-label="@(Carousel?.GetSlideAriaLabel(this))" @attributes=@Attributes class=@Class style=@ItemStyle tabindex="@(IsActive ? "0" : "-1")" inert="@(!IsActive)">
|
||||
@ChildContent
|
||||
<div class="rz-carousel-snapper"></div>
|
||||
</li>
|
||||
@@ -6,10 +6,10 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" @attributes="Attributes" class="@GetCssClass()" @onkeypress=@OnKeyPress @onkeypress:preventDefault @onclick=@Toggle @onclick:preventDefault style="@Style"
|
||||
role="checkbox" aria-checked="@CheckBoxAriaChecked" aria-disabled="@(Disabled || ReadOnly ? "true" : "false")"
|
||||
role="checkbox" aria-checked="@CheckBoxAriaChecked" aria-label="@AriaLabel" aria-disabled="@(Disabled || ReadOnly ? "true" : "false")"
|
||||
tabindex="@(Disabled || ReadOnly ? "-1" : $"{TabIndex}")" id="@GetId()">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input type="checkbox" @onchange=@Toggle value=@CheckBoxValue name=@Name id=@Name checked=@CheckBoxChecked aria-checked="@((Value as bool? == true).ToString().ToLowerInvariant())" @attributes="InputAttributes"
|
||||
<input type="checkbox" @onchange=@Toggle value=@CheckBoxValue name=@Name id=@Name checked=@CheckBoxChecked aria-hidden="true" @attributes="InputAttributes"
|
||||
tabindex="-1" readonly="@ReadOnly">
|
||||
</div>
|
||||
<div class=@BoxClass>
|
||||
|
||||
@@ -37,6 +37,13 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public IReadOnlyDictionary<string, object>? InputAttributes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label attribute of the checkbox.
|
||||
/// </summary>
|
||||
/// <value>The aria-label attribute.</value>
|
||||
[Parameter]
|
||||
public string? AriaLabel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the checkbox supports three states: checked (true), unchecked (false), and indeterminate (null).
|
||||
/// When enabled, clicking cycles through all three states. Use with nullable boolean (<c>bool?</c>) values.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{
|
||||
<div @ref=@Element style=@Style @onclick=@Toggle @attributes=@Attributes class=@GetCssClass() id=@GetId()
|
||||
role="button" aria-haspopup="dialog" aria-expanded="@isPopupOpen.ToString().ToLowerInvariant()" aria-controls="@($"{GetId()}-popup")" aria-disabled="@(Disabled.ToString().ToLowerInvariant())"
|
||||
tabindex="@(Disabled ? -1 : TabIndex)" @onkeypress="@(args => OnKeyPress(args, Toggle()))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation="stopKeypressPropagation">
|
||||
tabindex="@(Disabled ? -1 : TabIndex)" @onkeydown="@OnTriggerKeyDown" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeypressPropagation">
|
||||
@if (Icon != null)
|
||||
{
|
||||
<i class="notranslate rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@Icon</i>
|
||||
@@ -23,7 +23,9 @@
|
||||
@if (ShowHSV)
|
||||
{
|
||||
<Draggable class="rz-saturation-picker rz-colorpicker-section" style=@($"background-color: hsl({(HueHandleLeft * 360).ToInvariantString()}, 100%, 50%)") Drag=@OnSaturationMove
|
||||
id=@(GetId() + "hsl" ) tabindex="@(Disabled ? -1 : 0)" @onkeydown="@(args => OnHslKeyPress(args))">
|
||||
id=@(GetId() + "hsl" ) tabindex="@(Disabled ? -1 : 0)" @onkeydown="@(args => OnHslKeyPress(args))"
|
||||
role="slider" aria-roledescription="2D slider" aria-label="@SaturationAriaLabel"
|
||||
aria-valuemin="0" aria-valuemax="100" aria-valuenow="@SaturationPercent" aria-valuetext="@SaturationValueText">
|
||||
<div class="rz-saturation-white">
|
||||
<div class="rz-saturation-black"></div>
|
||||
<div class="rz-saturation-handle" style=@($"top: {(SaturationHandleTop * 100).ToInvariantString()}%; left: {(SaturationHandleLeft * 100).ToInvariantString()}%")></div>
|
||||
@@ -31,12 +33,16 @@
|
||||
</Draggable>
|
||||
<div class="rz-colorpicker-preview-area rz-colorpicker-section">
|
||||
<div class="rz-hue-and-alpha">
|
||||
<Draggable class="rz-hue-picker" Drag=@OnHueMove
|
||||
id=@(GetId() + "hue" ) tabindex="@(Disabled ? -1 : 0)" @onkeydown="@(args => OnHueKeyPress(args))">
|
||||
<Draggable class="rz-hue-picker" Drag=@OnHueMove
|
||||
id=@(GetId() + "hue" ) tabindex="@(Disabled ? -1 : 0)" @onkeydown="@(args => OnHueKeyPress(args))"
|
||||
role="slider" aria-orientation="horizontal" aria-label="@HueAriaLabel"
|
||||
aria-valuemin="0" aria-valuemax="360" aria-valuenow="@HuePercent">
|
||||
<div class="rz-hue-handle" style=@($"top: 0; left: {(HueHandleLeft * 100).ToInvariantString()}%")></div>
|
||||
</Draggable>
|
||||
<Draggable style=@($"background-image: linear-gradient(to right, {AlphaGradientStart} 0%, {AlphaGradientEnd} 100%)") class="rz-alpha-picker" Drag=@OnAlphaMove
|
||||
id=@(GetId() + "alpha" ) tabindex="@(Disabled ? -1 : 0)" @onkeydown="@(args => OnAlphaKeyPress(args))">
|
||||
id=@(GetId() + "alpha" ) tabindex="@(Disabled ? -1 : 0)" @onkeydown="@(args => OnAlphaKeyPress(args))"
|
||||
role="slider" aria-orientation="horizontal" aria-label="@AlphaAriaLabel"
|
||||
aria-valuemin="0" aria-valuemax="100" aria-valuenow="@Alpha">
|
||||
<div class="rz-alpha-handle" style=@($"top: 0; left: {(AlphaHandleLeft * 100).ToInvariantString()}%")></div>
|
||||
</Draggable>
|
||||
</div>
|
||||
|
||||
@@ -126,6 +126,43 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string AlphaText { get => alphaText ?? Localize(nameof(RadzenStrings.ColorPicker_AlphaText)); set => alphaText = value; }
|
||||
|
||||
private string? hueAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria label text of the hue slider.
|
||||
/// </summary>
|
||||
/// <value>The aria label text of the hue slider.</value>
|
||||
[Parameter]
|
||||
public string HueAriaLabel { get => hueAriaLabel ?? Localize(nameof(RadzenStrings.ColorPicker_HueAriaLabel)); set => hueAriaLabel = value; }
|
||||
|
||||
private string? alphaAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria label text of the alpha slider.
|
||||
/// </summary>
|
||||
/// <value>The aria label text of the alpha slider.</value>
|
||||
[Parameter]
|
||||
public string AlphaAriaLabel { get => alphaAriaLabel ?? Localize(nameof(RadzenStrings.ColorPicker_AlphaAriaLabel)); set => alphaAriaLabel = value; }
|
||||
|
||||
private string? saturationAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria label text of the saturation and brightness area.
|
||||
/// </summary>
|
||||
/// <value>The aria label text of the saturation and brightness area.</value>
|
||||
[Parameter]
|
||||
public string SaturationAriaLabel { get => saturationAriaLabel ?? Localize(nameof(RadzenStrings.ColorPicker_SaturationAriaLabel)); set => saturationAriaLabel = value; }
|
||||
|
||||
private string? saturationValueTextFormat;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format string used to build the aria-valuetext of the saturation and brightness area.
|
||||
/// The first argument is the saturation percent and the second one is the brightness percent.
|
||||
/// </summary>
|
||||
/// <value>The aria-valuetext format string of the saturation and brightness area.</value>
|
||||
[Parameter]
|
||||
public string SaturationValueTextFormat { get => saturationValueTextFormat ?? Localize(nameof(RadzenStrings.ColorPicker_SaturationValueTextFormat)); set => saturationValueTextFormat = value; }
|
||||
|
||||
private string? buttonText;
|
||||
|
||||
/// <summary>
|
||||
@@ -175,6 +212,14 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
double HuePercent => Math.Round(HueHandleLeft * 360);
|
||||
|
||||
double SaturationPercent => Math.Round(SaturationHandleLeft * 100);
|
||||
|
||||
double BrightnessPercent => Math.Round((1 - SaturationHandleTop) * 100);
|
||||
|
||||
string SaturationValueText => string.Format(System.Globalization.CultureInfo.CurrentCulture, SaturationValueTextFormat, SaturationPercent, BrightnessPercent);
|
||||
|
||||
double Red
|
||||
{
|
||||
get
|
||||
@@ -632,16 +677,16 @@ namespace Radzen.Blazor
|
||||
|
||||
bool preventKeyPress;
|
||||
bool stopKeypressPropagation;
|
||||
async Task OnKeyPress(KeyboardEventArgs args, Task task)
|
||||
async Task OnTriggerKeyDown(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
if (key == "Space" || key == "Enter")
|
||||
if (key == "Space" || key == "Enter" || key == "NumpadEnter")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
stopKeypressPropagation = true;
|
||||
|
||||
await task;
|
||||
await Toggle();
|
||||
}
|
||||
else if (key == "Escape")
|
||||
{
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
<div class="rz-colorpicker-item @(isSelected ? "selected" : "")" style="background-color: @Background" @onmousedown:preventDefault @onclick=@OnClick
|
||||
role="button" aria-label="@Value" aria-disabled="@(ColorPicker?.Disabled == true ? "true" : "false")"
|
||||
tabindex="@(ColorPicker?.Disabled == true ? -1 : 0)" @onkeypress="@(args => OnKeyPress(args, OnClick()))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation="stopKeypressPropagation"></div>
|
||||
tabindex="@(ColorPicker?.Disabled == true ? -1 : 0)" @onkeydown="@OnKeyDown" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeypressPropagation"></div>
|
||||
|
||||
@@ -79,16 +79,16 @@ namespace Radzen.Blazor
|
||||
|
||||
bool preventKeyPress;
|
||||
bool stopKeypressPropagation;
|
||||
async Task OnKeyPress(KeyboardEventArgs args, Task task)
|
||||
async Task OnKeyDown(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
if (key == "Space" || key == "Enter")
|
||||
if (key == "Space" || key == "Enter" || key == "NumpadEnter")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
stopKeypressPropagation = true;
|
||||
|
||||
await task;
|
||||
await OnClick();
|
||||
}
|
||||
else if (key == "Escape")
|
||||
{
|
||||
|
||||
@@ -338,6 +338,33 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string CustomText { get => customText ?? Localize(nameof(RadzenStrings.DataFilter_CustomText)); set => customText = value; }
|
||||
|
||||
private string? propertyAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label of the filter property dropdown.
|
||||
/// </summary>
|
||||
/// <value>The aria-label of the filter property dropdown.</value>
|
||||
[Parameter]
|
||||
public string PropertyAriaLabel { get => propertyAriaLabel ?? Localize(nameof(RadzenStrings.DataFilter_PropertyAriaLabel)); set => propertyAriaLabel = value; }
|
||||
|
||||
private string? filterOperatorAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label of the filter operator dropdown.
|
||||
/// </summary>
|
||||
/// <value>The aria-label of the filter operator dropdown.</value>
|
||||
[Parameter]
|
||||
public string FilterOperatorAriaLabel { get => filterOperatorAriaLabel ?? Localize(nameof(RadzenStrings.DataFilter_FilterOperatorAriaLabel)); set => filterOperatorAriaLabel = value; }
|
||||
|
||||
private string? filterValueAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label of the filter value editor.
|
||||
/// </summary>
|
||||
/// <value>The aria-label of the filter value editor.</value>
|
||||
[Parameter]
|
||||
public string FilterValueAriaLabel { get => filterValueAriaLabel ?? Localize(nameof(RadzenStrings.DataFilter_FilterValueAriaLabel)); set => filterValueAriaLabel = value; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the columns can be filtered.
|
||||
/// </summary>
|
||||
|
||||
@@ -29,6 +29,7 @@ else if (Filter != null)
|
||||
{
|
||||
<RadzenDropDown @bind-Value="@Filter.Property" Data="@(DataFilter?.properties)" TextProperty="Title" ValueProperty="Property" TValue="string"
|
||||
DisabledProperty="@(DataFilter?.UniqueFilters == true ? nameof(property.IsSelected) : null)"
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", $"{DataFilter?.PropertyAriaLabel} {property?.Title ?? property?.Property}".Trim() }})"
|
||||
Change="@OnPropertyChange" AllowFiltering="@(DataFilter?.AllowColumnFiltering ?? false)" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" class="rz-datafilter-property">
|
||||
<Template>
|
||||
@{
|
||||
@@ -40,6 +41,7 @@ else if (Filter != null)
|
||||
if (property != null)
|
||||
{
|
||||
<RadzenDropDown @onclick:preventDefault="true" Data="@(property.GetFilterOperators().Select(t => new DropDownItem<FilterOperator> { Text = property.GetFilterOperatorText(t), Value = t }))"
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", $"{DataFilter?.FilterOperatorAriaLabel} {(Filter.FilterOperator != null ? property.GetFilterOperatorText(Filter.FilterOperator.Value) : "")}".Trim() }})"
|
||||
TextProperty="Text" ValueProperty="Value" TValue="FilterOperator?" @bind-Value="@Filter.FilterOperator" Change="@OnOperatorChange" class="rz-datafilter-operator" />
|
||||
@if (property.FilterTemplate != null)
|
||||
{
|
||||
@@ -50,6 +52,7 @@ else if (Filter != null)
|
||||
else if (PropertyAccess.IsNullableEnum(property.FilterPropertyType) || PropertyAccess.IsEnum(property.FilterPropertyType))
|
||||
{
|
||||
<RadzenDropDown Disabled="@IsOperatorNullOrEmpty()" AllowClear="false" AllowFiltering="false" TValue="@object" class="rz-datafilter-editor"
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", $"{DataFilter?.FilterValueAriaLabel} {Filter.FilterValue}".Trim() }})"
|
||||
@bind-Value=@Filter.FilterValue Multiple="false" Placeholder="@(DataFilter?.EnumFilterSelectText ?? "")" TextProperty="Text" ValueProperty="Value"
|
||||
Data=@EnumExtensions.EnumAsKeyValuePair(property.FilterPropertyType != null ? (Nullable.GetUnderlyingType(property.FilterPropertyType!)! ?? property.FilterPropertyType) : typeof(object)) Change=@(args => { _ = InvokeAsync(ApplyFilter); }) />
|
||||
}
|
||||
@@ -60,15 +63,17 @@ else if (Filter != null)
|
||||
else if (PropertyAccess.IsDate(property.FilterPropertyType))
|
||||
{
|
||||
<RadzenDatePicker Disabled="@IsOperatorNullOrEmpty()" @bind-Value=@Filter.FilterValue TValue="@object" ShowTime="true" class="rz-datafilter-editor"
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", $"{DataFilter?.FilterValueAriaLabel} {Filter.FilterValue}".Trim() }})"
|
||||
ShowTimeOkButton="true" DateFormat="@getFilterDateFormat()" Change=@(args => InvokeAsync(ApplyFilter)) />
|
||||
}
|
||||
else if (property.FilterPropertyType == typeof(bool) || property.FilterPropertyType == typeof(bool?))
|
||||
{
|
||||
<RadzenCheckBox Disabled="@IsOperatorNullOrEmpty()" TriState="true" TValue="@object" @bind-Value=@Filter.FilterValue Change=@(args => InvokeAsync(ApplyFilter)) class="rz-datafilter-check" />
|
||||
<RadzenCheckBox Disabled="@IsOperatorNullOrEmpty()" TriState="true" TValue="@object" @bind-Value=@Filter.FilterValue Change=@(args => InvokeAsync(ApplyFilter)) class="rz-datafilter-check"
|
||||
InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", $"{DataFilter?.FilterValueAriaLabel} {Filter.FilterValue}".Trim() }})" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Disabled="@IsOperatorNullOrEmpty()" class="rz-datafilter-editor" Value="@($"{Filter.FilterValue}")" Change=@(args => { Filter.FilterValue = args; InvokeAsync(ApplyFilter); }) />
|
||||
<RadzenTextBox Disabled="@IsOperatorNullOrEmpty()" class="rz-datafilter-editor" aria-label="@($"{DataFilter?.FilterValueAriaLabel} {Filter.FilterValue}".Trim())" Value="@($"{Filter.FilterValue}")" Change=@(args => { Filter.FilterValue = args; InvokeAsync(ApplyFilter); }) />
|
||||
}
|
||||
|
||||
<RadzenButton title="@(DataFilter?.RemoveFilterText ?? "")" class="rz-datafilter-item-clear" Icon="clear" Click="@RemoveFilter" Variant="Variant.Text" Size="ButtonSize.Small" ButtonStyle="ButtonStyle.Dark"/>
|
||||
@@ -356,6 +361,8 @@ else if (Filter != null)
|
||||
}
|
||||
}
|
||||
|
||||
builder.AddAttribute(5, "InputAttributes", new Dictionary<string, object>() { { "aria-label", $"{DataFilter?.FilterValueAriaLabel} {Filter?.FilterValue}".Trim() } });
|
||||
|
||||
builder.CloseComponent();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
var visibleColumns = columns.Where(c => c.GetVisible()).ToList();
|
||||
|
||||
<div @ref=@Element style="@Style" @attributes="Attributes" class="rz-data-grid @GetCssClass()" id="@GetId()"
|
||||
role="grid"
|
||||
role="@(LoadChildData.HasDelegate ? "treegrid" : "grid")"
|
||||
aria-multiselectable="@(SelectionMode == DataGridSelectionMode.Multiple ? "true" : null)"
|
||||
aria-rowcount="@GridAriaRowCount()"
|
||||
aria-activedescendant="@GetActiveDescendantId()"
|
||||
@onkeydown="@OnKeyDown" @onkeydown:preventDefault="preventKeyDown" @onkeydown:stopPropagation="stopKeydownPropagation" tabindex="@TabIndex"
|
||||
@onblur=@OnBlur @oncontextmenu=OnContextMenu @oncontextmenu:preventDefault="@this.ContextMenu.HasDelegate" @oncontextmenu:stopPropagation="@this.ContextMenu.HasDelegate">
|
||||
@@ -672,6 +674,7 @@
|
||||
{
|
||||
<span class="rz-cell-toggle">
|
||||
<button type="button" tabindex="-1" id="@(GetId() + "exp")" aria-label="@ExpandChildItemAriaLabel"
|
||||
aria-expanded="@(this.IsRowExpanded(Item) ? "true" : "false")"
|
||||
class="rz-button rz-button-sm rz-button-icon-only rz-variant-text rz-base rz-shade-default"
|
||||
style="@(getExpandIconStyle(this, Item, rowArgs.Item1.Expandable))"
|
||||
@onclick="_ => this.ExpandItem(Item)" @onclick:stopPropagation="true">
|
||||
|
||||
@@ -177,6 +177,8 @@ namespace Radzen.Blazor
|
||||
|
||||
List<TItem> virtualDataItems = new List<TItem>();
|
||||
|
||||
int virtualItemsStartIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Clears the internal data cache and refreshes the DataGrid, reloading data from the source.
|
||||
/// When virtualization is enabled, this method refreshes the Virtualize component. Otherwise, it triggers a standard reload.
|
||||
@@ -234,6 +236,8 @@ namespace Radzen.Blazor
|
||||
|
||||
virtualDataItems = (LoadData.HasDelegate ? (itemsToInsert.Count > 0 ? itemsToInsert.ToList().Concat(Data ?? Enumerable.Empty<TItem>()) : Data) : itemsToInsert.Count > 0 ? itemsToInsert.ToList().Concat(view.Skip(request.StartIndex).Take(top)) : view.Skip(request.StartIndex).Take(top))?.ToList() ?? new List<TItem>();
|
||||
|
||||
virtualItemsStartIndex = request.StartIndex;
|
||||
|
||||
return new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderResult<TItem>(virtualDataItems, totalItemsCount);
|
||||
}
|
||||
|
||||
@@ -600,14 +604,16 @@ namespace Radzen.Blazor
|
||||
|
||||
internal Func<bool>? HasActiveDescendant { get; set; }
|
||||
|
||||
bool hasActiveRow;
|
||||
|
||||
internal string? GetActiveDescendantId()
|
||||
{
|
||||
if (HasActiveDescendant != null && !HasActiveDescendant())
|
||||
if (HasActiveDescendant != null)
|
||||
{
|
||||
return null;
|
||||
return HasActiveDescendant() ? $"{GetId()}-active-item" : null;
|
||||
}
|
||||
|
||||
return $"{GetId()}-active-item";
|
||||
return hasActiveRow ? $"{GetId()}-active-item" : null;
|
||||
}
|
||||
|
||||
internal string? GridId()
|
||||
@@ -632,6 +638,7 @@ namespace Radzen.Blazor
|
||||
var result = await JSRuntime.InvokeAsync<int[]>("Radzen.focusTableRow", UniqueID, key, focusedIndex, focusedCellIndex, IsVirtualizationAllowed());
|
||||
focusedIndex = result[0];
|
||||
focusedCellIndex = result[1];
|
||||
hasActiveRow = true;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -709,7 +716,7 @@ namespace Radzen.Blazor
|
||||
|
||||
await FocusRow(key);
|
||||
}
|
||||
else if (IsVirtualizationAllowed() && (key == "PageUp" || key == "PageDown" || key == "Home" || key == "End"))
|
||||
else if (key == "PageUp" || key == "PageDown" || key == "Home" || key == "End")
|
||||
{
|
||||
preventKeyDown = true;
|
||||
stopKeydownPropagation = true;
|
||||
@@ -2781,6 +2788,36 @@ namespace Radzen.Blazor
|
||||
return selectedItems.Keys.Any(i => ItemEquals(i, item)) ? "true" : "false";
|
||||
}
|
||||
|
||||
int HeaderRowCount()
|
||||
{
|
||||
return (ShowHeader ? deepestChildColumnLevel + 1 : 0) + (FilterRowActive ? 1 : 0);
|
||||
}
|
||||
|
||||
internal string? GridAriaRowCount()
|
||||
{
|
||||
return IsVirtualizationAllowed() && Groups.Count == 0 ? (Count + HeaderRowCount()).ToString(CultureInfo.InvariantCulture) : null;
|
||||
}
|
||||
|
||||
internal string? RowAriaRowIndex(int index)
|
||||
{
|
||||
return IsVirtualizationAllowed() && Groups.Count == 0 ? (virtualItemsStartIndex + index + HeaderRowCount() + 1).ToString(CultureInfo.InvariantCulture) : null;
|
||||
}
|
||||
|
||||
internal string? RowAriaLevel(TItem item)
|
||||
{
|
||||
if (!LoadChildData.HasDelegate)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var child = childData.Count > 0 ? childData.Where(c => c.Value?.Data?.Contains(item) == true).FirstOrDefault() :
|
||||
default(KeyValuePair<TItem, DataGridChildData<TItem>>);
|
||||
|
||||
var level = !object.Equals(child, default(KeyValuePair<TItem, DataGridChildData<TItem>>)) ? child.Value.Level : 0;
|
||||
|
||||
return (level + 1).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
internal Tuple<Radzen.RowRenderEventArgs<TItem>, IReadOnlyDictionary<string, object>> RowAttributes(TItem item, int index)
|
||||
{
|
||||
var args = new Radzen.RowRenderEventArgs<TItem>() { Data = item, Index = index, Expandable = Template != null || LoadChildData.HasDelegate };
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{
|
||||
<th role="columnheader" rowspan="@(Column.GetRowSpan())" colspan="@(Column.GetColSpan())" @attributes="@Attributes" class="@CssClass"
|
||||
scope="col" style="@GetStyle()" data-column-index="@ColumnIndex" @onmouseup=@(args => Grid.EndColumnReorder(args, ColumnIndex))
|
||||
aria-sort="@(Grid.AllowSorting && Column.Sortable ? (Column.GetSortOrder() == SortOrder.Ascending ? "ascending" : Column.GetSortOrder() == SortOrder.Descending ? "descending" : "none") : null)">
|
||||
aria-sort="@(Grid.AllowSorting && Column.Sortable ? (Column.GetSortOrder() == SortOrder.Ascending ? "ascending" : Column.GetSortOrder() == SortOrder.Descending ? "descending" : null) : null)">
|
||||
<div @onclick='@((args) => Grid.OnSort(args, Column))'>
|
||||
@if ((Grid.AllowColumnReorder && Column.Reorderable || Grid.AllowGrouping && Column.Groupable))
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@{var firstLevel = Grid?.AllowCompositeDataCells == true ? 0 : (Grid?.deepestChildColumnLevel ?? 0); }
|
||||
@for(var i = firstLevel; (Grid?.AllowCompositeDataCells == true ? i <= (Grid?.deepestChildColumnLevel ?? 0) + 1 : i < (Grid?.deepestChildColumnLevel ?? 0) + 1); i++)
|
||||
{
|
||||
<tr role="row" aria-selected="@(Grid?.RowAriaSelected(Item, Index))" class="@(Grid?.RowStyle(Item, Index) ?? "")" @attributes="@(rowArgs?.Item2)">
|
||||
<tr role="row" aria-selected="@(Grid?.RowAriaSelected(Item, Index))" aria-level="@(Grid?.RowAriaLevel(Item))" aria-rowindex="@(Grid?.RowAriaRowIndex(Index))" class="@(Grid?.RowStyle(Item, Index) ?? "")" @attributes="@(rowArgs?.Item2)">
|
||||
@if (Grid?.ShowGroupExpandColumn == true)
|
||||
{
|
||||
@foreach(var g in Grid.Groups)
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
{
|
||||
@if (!WrapItems)
|
||||
{
|
||||
<ul class="rz-datalist-data">
|
||||
@DrawDataListRows()
|
||||
</ul>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Radzen.Blazor
|
||||
{
|
||||
builder.OpenComponent(0, typeof(Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem>));
|
||||
builder.AddAttribute(1, "ItemsProvider", new Microsoft.AspNetCore.Components.Web.Virtualization.ItemsProviderDelegate<TItem>(LoadItems));
|
||||
|
||||
|
||||
builder.AddAttribute(2, "ChildContent", (RenderFragment<TItem>)((context) =>
|
||||
{
|
||||
return (RenderFragment)((b) =>
|
||||
@@ -148,6 +148,11 @@ namespace Radzen.Blazor
|
||||
});
|
||||
}));
|
||||
|
||||
if (!WrapItems)
|
||||
{
|
||||
builder.AddAttribute(3, "SpacerElement", "li");
|
||||
}
|
||||
|
||||
builder.AddComponentReferenceCapture(4, c => { virtualize = (Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize<TItem>)c; });
|
||||
|
||||
builder.CloseComponent();
|
||||
|
||||
@@ -2,18 +2,16 @@
|
||||
|
||||
@if (DataList != null && !DataList.WrapItems)
|
||||
{
|
||||
<ul class="rz-datalist-data">
|
||||
<li>
|
||||
@if (DataList.Template != null)
|
||||
{
|
||||
@DataList.Template(Item!)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Template</span>
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
<li>
|
||||
@if (DataList.Template != null)
|
||||
{
|
||||
@DataList.Template(Item!)
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Template</span>
|
||||
}
|
||||
</li>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -764,7 +764,9 @@ namespace Radzen.Blazor
|
||||
|
||||
try
|
||||
{
|
||||
var newDate = Culture.Calendar.AddMonths(FocusedDate, key == "PageUp" ? -1 : 1);
|
||||
var newDate = args.ShiftKey
|
||||
? Culture.Calendar.AddYears(FocusedDate, key == "PageUp" ? -1 : 1)
|
||||
: Culture.Calendar.AddMonths(FocusedDate, key == "PageUp" ? -1 : 1);
|
||||
FocusedDate = newDate;
|
||||
CurrentDate = newDate;
|
||||
shouldFocusDay = true;
|
||||
|
||||
@@ -234,6 +234,7 @@
|
||||
builder.CloseComponent(); // Close CascadingValue
|
||||
});
|
||||
isSideDialogOpen = true;
|
||||
sideDialogJsOpened = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -247,6 +248,8 @@
|
||||
|
||||
private bool sideDialogClosing = false;
|
||||
|
||||
private bool sideDialogJsOpened = false;
|
||||
|
||||
private async Task OnSideCloseAsync()
|
||||
{
|
||||
sideDialogClosing = true;
|
||||
@@ -257,9 +260,18 @@
|
||||
|
||||
isSideDialogOpen = false;
|
||||
sideDialogClosing = false;
|
||||
sideDialogJsOpened = false;
|
||||
|
||||
StateHasChanged();
|
||||
|
||||
try
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.closeSideDialog");
|
||||
}
|
||||
catch (Exception ex) when (ex is JSDisconnectedException || ex is OperationCanceledException || ex is JSException)
|
||||
{
|
||||
}
|
||||
|
||||
Service?.OnSideCloseComplete();
|
||||
}
|
||||
|
||||
@@ -313,7 +325,11 @@
|
||||
|
||||
if (isSideDialogOpen)
|
||||
{
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.openSideDialog", sideDialogOptions);
|
||||
if (!sideDialogJsOpened)
|
||||
{
|
||||
sideDialogJsOpened = true;
|
||||
await JSRuntime.InvokeAsync<string>("Radzen.openSideDialog", sideDialogOptions, Service?.Reference);
|
||||
}
|
||||
|
||||
if (sideDialogOptions is { Resizable: true } && resizeBarElement.HasValue)
|
||||
{
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" aria-label="@(!Multiple && selectedItem != null ? GetItemOrValueFromProperty(selectedItem, TextProperty ?? string.Empty) : EmptyAriaLabel)" @attributes="Attributes" class="@GetCssClass()"
|
||||
<div @ref="@Element" aria-label="@SelectedAriaLabel" @attributes="Attributes" class="@GetCssClass()"
|
||||
role="combobox" aria-haspopup="listbox" aria-autocomplete="@(AllowFiltering ? "list" : "none")" aria-expanded="@isPopupOpen.ToString().ToLowerInvariant()" aria-controls="@ListId" aria-activedescendant="@ActiveDescendantId" aria-disabled="@(Disabled.ToString().ToLowerInvariant())"
|
||||
@onclick="@(args => OpenPopup("ArrowDown", false, true))" @onclick:preventDefault @onclick:stopPropagation style="@Style" tabindex="@(Disabled ? "-1" : $"{TabIndex}")"
|
||||
@onkeydown="@((args) => OnKeyPress(args))" @onkeydown:preventDefault="@preventKeydown" id="@GetId()" @onfocus=@this.AsNonRenderingEventHandler(OnFocus)>
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input disabled="@Disabled" aria-haspopup="listbox" readonly="" type="text" tabindex="-1"
|
||||
<input disabled="@Disabled" aria-haspopup="listbox" aria-hidden="true" readonly="" type="text" tabindex="-1"
|
||||
name="@Name" value="@(internalValue != null ? internalValue : "")" id="@Name"
|
||||
aria-label="@(!Multiple && internalValue != null ? internalValue : EmptyAriaLabel)" @attributes="InputAttributes"/>
|
||||
</div>
|
||||
@@ -59,7 +59,7 @@
|
||||
@GetItemOrValueFromProperty(item, TextProperty ?? string.Empty)
|
||||
}
|
||||
</span>
|
||||
<button tabindex="0"
|
||||
<button tabindex="-1"
|
||||
title="@(RemoveChipTitle + " " + GetItemOrValueFromProperty(item, TextProperty ?? ""))"
|
||||
aria-label="@(RemoveChipTitle + " " + GetItemOrValueFromProperty(item, TextProperty ?? ""))"
|
||||
type=button class="rz-button rz-button-xs rz-variant-text rz-base rz-shade-default rz-button-icon-only @(Disabled ?"rz-state-disabled":"")"
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Radzen.Blazor.Rendering;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -286,6 +287,29 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string SelectAllText { get; set; } = string.Empty;
|
||||
|
||||
internal string? SelectedAriaLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Multiple)
|
||||
{
|
||||
return selectedItem != null ? $"{GetItemOrValueFromProperty(selectedItem, TextProperty ?? string.Empty)}" : EmptyAriaLabel;
|
||||
}
|
||||
|
||||
if (selectedItems.Count == 0)
|
||||
{
|
||||
return EmptyAriaLabel;
|
||||
}
|
||||
|
||||
if (selectedItems.Count < MaxSelectedLabels)
|
||||
{
|
||||
return string.Join(Separator, selectedItems.Select(i => $"{GetItemOrValueFromProperty(i, TextProperty ?? string.Empty)}"));
|
||||
}
|
||||
|
||||
return $"{selectedItems.Count} {SelectedItemsText}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback for when a dropdown is opened.
|
||||
/// </summary>
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" aria-label="@(!Multiple && internalValue != null ? PropertyAccess.GetItemOrValueFromProperty(internalValue, TextProperty) : EmptyAriaLabel)" @attributes="Attributes" class="@GetCssClass()" @onfocus=@this.AsNonRenderingEventHandler(OnFocus)
|
||||
role="combobox" aria-haspopup="grid" aria-expanded="@isPopupOpen.ToString().ToLowerInvariant()" aria-controls="@PopupID" aria-disabled="@(Disabled.ToString().ToLowerInvariant())" aria-activedescendant="@ActiveDescendantId"
|
||||
<div @ref="@Element" aria-label="@SelectedAriaLabel" @attributes="Attributes" class="@GetCssClass()" @onfocus=@this.AsNonRenderingEventHandler(OnFocus)
|
||||
role="combobox" aria-haspopup="grid" aria-expanded="@isPopupOpen.ToString().ToLowerInvariant()" aria-controls="@GridID" aria-disabled="@(Disabled.ToString().ToLowerInvariant())" aria-activedescendant="@ActiveDescendantId"
|
||||
style="@Style" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" id="@GetId()" @onclick="@(args => OpenPopup("ArrowDown", false, true))" @onclick:preventDefault @onclick:stopPropagation
|
||||
@onkeydown="@((args) => OnKeyPress(args))" @onkeydown:preventDefault="@preventKeydown">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input tabindex="-1" disabled="@Disabled" style="width:100%" aria-haspopup="listbox" readonly="" type="text" id="@Name"
|
||||
<input tabindex="-1" disabled="@Disabled" style="width:100%" aria-haspopup="grid" aria-hidden="true" readonly="" type="text" id="@Name"
|
||||
name="@Name" aria-label="@(!Multiple && internalValue != null ? PropertyAccess.GetItemOrValueFromProperty(internalValue, TextProperty) : EmptyAriaLabel)" @attributes="InputAttributes" />
|
||||
|
||||
</div>
|
||||
@@ -62,7 +62,7 @@
|
||||
@GetItemOrValueFromProperty(item!, TextProperty ?? string.Empty)
|
||||
}
|
||||
</span>
|
||||
<button tabindex="0"
|
||||
<button tabindex="-1"
|
||||
title="@(RemoveChipTitle + " " + GetItemOrValueFromProperty(item!, TextProperty ?? string.Empty))"
|
||||
aria-label="@(RemoveChipTitle + " " + GetItemOrValueFromProperty(item!, TextProperty ?? string.Empty))"
|
||||
type="button" class="rz-button rz-button-xs rz-variant-text rz-base rz-shade-default rz-button-icon-only @(Disabled ?"rz-state-disabled":"")"
|
||||
@@ -135,7 +135,7 @@
|
||||
<div class="rz-lookup-search">
|
||||
<div class="rz-lookup-search-input-container">
|
||||
<input aria-label="@SearchAriaLabel" class="rz-lookup-search-input" id="@SearchID" @ref="@search" tabindex="0" placeholder="@(SearchTextPlaceholder ?? string.Empty)"
|
||||
role="combobox" aria-controls="@PopupID" aria-haspopup="grid" aria-expanded="@isPopupOpen.ToString().ToLowerInvariant()" aria-autocomplete="list" aria-activedescendant="@ActiveDescendantId"
|
||||
role="combobox" aria-controls="@GridID" aria-haspopup="grid" aria-expanded="@isPopupOpen.ToString().ToLowerInvariant()" aria-autocomplete="list" aria-activedescendant="@ActiveDescendantId"
|
||||
@onchange="@OnFilter" @onkeydown="@OnFilterKeyPress" value="@(searchText ?? string.Empty)" style="@(ShowSearch ? "" : "margin-right:0px;")"
|
||||
@oninput="@OnFilterInput" />
|
||||
@if (!string.IsNullOrEmpty(searchText))
|
||||
@@ -163,7 +163,7 @@
|
||||
}
|
||||
@if (Template != null)
|
||||
{
|
||||
<RadzenDataGrid TabIndex="-1" GridLines=@GridLines EmptyTemplate=@EmptyTemplate FooterTemplate=@FooterTemplate AllowVirtualization="@IsVirtualizationAllowed()" VirtualizationOverscanCount="@GetVirtualizationOverscanCount()" AllowRowSelectOnRowClick="@AllowRowSelectOnRowClick" PagerHorizontalAlign="@PagerHorizontalAlign" PagerAlwaysVisible="@PagerAlwaysVisible" Responsive="@Responsive" AllowColumnResize="@AllowColumnResize" AllowColumnPicking="@AllowColumnPicking" AllowColumnReorder="@AllowColumnReorder" ColumnWidth="@ColumnWidth" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate ? Count : count)" LoadData="@OnLoadData" LoadChildData="@LoadChildData"
|
||||
<RadzenDataGrid id="@GridID" TabIndex="-1" GridLines=@GridLines EmptyTemplate=@EmptyTemplate FooterTemplate=@FooterTemplate AllowVirtualization="@IsVirtualizationAllowed()" VirtualizationOverscanCount="@GetVirtualizationOverscanCount()" AllowRowSelectOnRowClick="@AllowRowSelectOnRowClick" PagerHorizontalAlign="@PagerHorizontalAlign" PagerAlwaysVisible="@PagerAlwaysVisible" Responsive="@Responsive" AllowColumnResize="@AllowColumnResize" AllowColumnPicking="@AllowColumnPicking" AllowColumnReorder="@AllowColumnReorder" ColumnWidth="@ColumnWidth" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate ? Count : count)" LoadData="@OnLoadData" LoadChildData="@LoadChildData"
|
||||
TItem="object" ColumnReordered="@ColumnReordered" ColumnResized="@ColumnResized" ColumnReordering="@ColumnReordering" ContextMenu="@ContextMenuDataGrid"
|
||||
CellRender="@OnCellRender" RowRender="@OnRowRender" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" PageSize="@PageSize" PageSizeOptions="@PageSizeOptions" PageNumbersCount="@PageNumbersCount" AllowPaging="@(!IsVirtualizationAllowed())" AllowSorting="@AllowSorting" RowSelect="@OnRowSelect" Style="@(IsVirtualizationAllowed() ? "height:285px" : "")" Density="@Density" IsLoading="@IsLoading" FirstPageTitle="@FirstPageTitle" FirstPageAriaLabel="@FirstPageAriaLabel" PrevPageAriaLabel="@PrevPageAriaLabel" PrevPageTitle="@PrevPageTitle" NextPageAriaLabel="@NextPageAriaLabel" NextPageTitle="@NextPageTitle" LastPageAriaLabel="@LastPageAriaLabel" LastPageTitle="@LastPageTitle" PageAriaLabelFormat="@PageAriaLabelFormat" PageTitleFormat="@PageTitleFormat">
|
||||
<Columns>
|
||||
@@ -179,7 +179,7 @@
|
||||
{
|
||||
if (!string.IsNullOrEmpty(TextProperty) || Columns != null)
|
||||
{
|
||||
<RadzenDataGrid TabIndex="-1" GridLines=@GridLines EmptyTemplate=@EmptyTemplate FooterTemplate=@FooterTemplate AllowVirtualization="@IsVirtualizationAllowed()" VirtualizationOverscanCount="@GetVirtualizationOverscanCount()" AllowRowSelectOnRowClick="@AllowRowSelectOnRowClick" PagerHorizontalAlign="@PagerHorizontalAlign" PagerAlwaysVisible="@PagerAlwaysVisible" Responsive="@Responsive" AllowColumnResize="@AllowColumnResize" AllowColumnPicking="@AllowColumnPicking" AllowColumnReorder="@AllowColumnReorder" ColumnWidth="@ColumnWidth" EmptyText="@EmptyText" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate? Count : count)" LoadData="@OnLoadData" LoadChildData="@LoadChildData"
|
||||
<RadzenDataGrid id="@GridID" TabIndex="-1" GridLines=@GridLines EmptyTemplate=@EmptyTemplate FooterTemplate=@FooterTemplate AllowVirtualization="@IsVirtualizationAllowed()" VirtualizationOverscanCount="@GetVirtualizationOverscanCount()" AllowRowSelectOnRowClick="@AllowRowSelectOnRowClick" PagerHorizontalAlign="@PagerHorizontalAlign" PagerAlwaysVisible="@PagerAlwaysVisible" Responsive="@Responsive" AllowColumnResize="@AllowColumnResize" AllowColumnPicking="@AllowColumnPicking" AllowColumnReorder="@AllowColumnReorder" ColumnWidth="@ColumnWidth" EmptyText="@EmptyText" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate? Count : count)" LoadData="@OnLoadData" LoadChildData="@LoadChildData"
|
||||
TItem="object" ColumnReordered="@ColumnReordered" ColumnResized="@ColumnResized" ColumnReordering="@ColumnReordering" ContextMenu="@ContextMenuDataGrid"
|
||||
CellRender="@OnCellRender" RowRender="@OnRowRender" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" PageSize="@PageSize" PageSizeOptions="@PageSizeOptions" PageNumbersCount="@PageNumbersCount" AllowPaging="@(!IsVirtualizationAllowed())" AllowSorting="@AllowSorting" RowSelect="@OnRowSelect" Style="@(IsVirtualizationAllowed() ? "height:285px" : "")" Density="@Density" IsLoading="@IsLoading" FirstPageTitle="@FirstPageTitle" FirstPageAriaLabel="@FirstPageAriaLabel" PrevPageAriaLabel="@PrevPageAriaLabel" PrevPageTitle="@PrevPageTitle" NextPageAriaLabel="@NextPageAriaLabel" NextPageTitle="@NextPageTitle" LastPageAriaLabel="@LastPageAriaLabel" LastPageTitle="@LastPageTitle" PageAriaLabelFormat="@PageAriaLabelFormat" PageTitleFormat="@PageTitleFormat">
|
||||
<Columns>
|
||||
@@ -196,7 +196,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenDataGrid TabIndex="-1" GridLines=@GridLines EmptyTemplate=@EmptyTemplate FooterTemplate=@FooterTemplate AllowVirtualization="@IsVirtualizationAllowed()" VirtualizationOverscanCount="@GetVirtualizationOverscanCount()" AllowRowSelectOnRowClick="@AllowRowSelectOnRowClick" PagerHorizontalAlign="@PagerHorizontalAlign" PagerAlwaysVisible="@PagerAlwaysVisible" Responsive="@Responsive" AllowColumnResize="@AllowColumnResize" AllowColumnPicking="@AllowColumnPicking" AllowColumnReorder="@AllowColumnReorder" ColumnWidth="@ColumnWidth" EmptyText="@EmptyText" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate? Count : count)" LoadData="@OnLoadData" LoadChildData="@LoadChildData"
|
||||
<RadzenDataGrid id="@GridID" TabIndex="-1" GridLines=@GridLines EmptyTemplate=@EmptyTemplate FooterTemplate=@FooterTemplate AllowVirtualization="@IsVirtualizationAllowed()" VirtualizationOverscanCount="@GetVirtualizationOverscanCount()" AllowRowSelectOnRowClick="@AllowRowSelectOnRowClick" PagerHorizontalAlign="@PagerHorizontalAlign" PagerAlwaysVisible="@PagerAlwaysVisible" Responsive="@Responsive" AllowColumnResize="@AllowColumnResize" AllowColumnPicking="@AllowColumnPicking" AllowColumnReorder="@AllowColumnReorder" ColumnWidth="@ColumnWidth" EmptyText="@EmptyText" @ref="grid" Data="@(LoadData.HasDelegate ? (Data != null ? Data.Cast<object>() : Enumerable.Empty<object>()) : pagedData)" Count="@(LoadData.HasDelegate? Count : count)" LoadData="@OnLoadData" LoadChildData="@LoadChildData"
|
||||
TItem="object" ColumnReordered="@ColumnReordered" ColumnResized="@ColumnResized" ColumnReordering="@ColumnReordering" ContextMenu="@ContextMenuDataGrid"
|
||||
CellRender="@OnCellRender" RowRender="@OnRowRender" ShowPagingSummary="@ShowPagingSummary" PagingSummaryFormat="@PagingSummaryFormat" PageSize="@PageSize" PageSizeOptions="@PageSizeOptions" PageNumbersCount="@PageNumbersCount" AllowPaging="@(!IsVirtualizationAllowed())" AllowSorting="@AllowSorting" RowSelect="@OnRowSelect" Style="@(IsVirtualizationAllowed() ? "height:285px" : "")" Density="@Density" IsLoading="@IsLoading" FirstPageTitle="@FirstPageTitle" FirstPageAriaLabel="@FirstPageAriaLabel" PrevPageAriaLabel="@PrevPageAriaLabel" PrevPageTitle="@PrevPageTitle" NextPageAriaLabel="@NextPageAriaLabel" NextPageTitle="@NextPageTitle" LastPageAriaLabel="@LastPageAriaLabel" LastPageTitle="@LastPageTitle" PageAriaLabelFormat="@PageAriaLabelFormat" PageTitleFormat="@PageTitleFormat">
|
||||
<Columns>
|
||||
|
||||
@@ -523,6 +523,33 @@ namespace Radzen.Blazor
|
||||
/// <returns>The active row identifier or null.</returns>
|
||||
internal string? ActiveDescendantId => selectedIndex >= 0 && grid != null ? $"{grid.GridId()}-active-item" : null;
|
||||
|
||||
internal string GridID => $"{PopupID}-grid";
|
||||
|
||||
internal string? SelectedAriaLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Multiple)
|
||||
{
|
||||
return internalValue != null ? $"{PropertyAccess.GetItemOrValueFromProperty(internalValue, TextProperty)}" : EmptyAriaLabel;
|
||||
}
|
||||
|
||||
var itemsToUse = SelectedValue is IEnumerable && SelectedValue is not string ? ((IEnumerable)SelectedValue).Cast<object>().ToHashSet() : selectedItems;
|
||||
|
||||
if (itemsToUse.Count == 0)
|
||||
{
|
||||
return EmptyAriaLabel;
|
||||
}
|
||||
|
||||
if (itemsToUse.Count < MaxSelectedLabels)
|
||||
{
|
||||
return string.Join(Separator, itemsToUse.Select(i => $"{PropertyAccess.GetItemOrValueFromProperty(i, TextProperty)}"));
|
||||
}
|
||||
|
||||
return $"{itemsToUse.Count} {SelectedItemsText}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of maximum selected labels.
|
||||
/// </summary>
|
||||
@@ -1100,6 +1127,12 @@ namespace Radzen.Blazor
|
||||
await OnSelectItem(null, true);
|
||||
}
|
||||
|
||||
if (Multiple && !isFilter && (selectedItems.Count > 0 || SelectedValue is IEnumerable && SelectedValue is not string))
|
||||
{
|
||||
selectedIndex = -1;
|
||||
await Clear();
|
||||
}
|
||||
|
||||
if (AllowFiltering && isFilter)
|
||||
{
|
||||
Debounce(DebounceFilter, FilterDelay);
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<i @ref="@Element" style="@getStyle()" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">@Icon</i>
|
||||
<i @ref="@Element" style="@getStyle()" aria-hidden="@getAriaHidden()" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">@Icon</i>
|
||||
}
|
||||
@@ -64,5 +64,10 @@ namespace Radzen.Blazor
|
||||
{
|
||||
return $"{(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor};" : null)}{(!string.IsNullOrEmpty(Style) ? Style : null)}";
|
||||
}
|
||||
|
||||
string? getAriaHidden()
|
||||
{
|
||||
return Attributes != null && (Attributes.ContainsKey("aria-label") || Attributes.ContainsKey("role")) ? null : "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
@inherits DropDownBase<TValue>
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" tabindex="@(Disabled ? "-1" : $"{TabIndex}")" @onkeydown="@OnKeyDown" id="@GetId()"
|
||||
role="listbox" aria-label="@ListboxAriaLabel" aria-multiselectable="@(Multiple ? "true" : "false")" aria-disabled="@(Disabled ? "true" : "false")" aria-activedescendant="@ActiveDescendantId">
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" @onkeydown="@OnKeyDown" id="@GetId()">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input name="@Name" readonly="@ReadOnly" disabled="@Disabled" type="text" aria-label="@(!Multiple && internalValue != null ? internalValue : EmptyAriaLabel)" @attributes=@InputAttributes />
|
||||
<input name="@Name" readonly="@ReadOnly" disabled="@Disabled" type="text" tabindex="-1" aria-hidden="true" aria-label="@(!Multiple && internalValue != null ? internalValue : EmptyAriaLabel)" @attributes=@InputAttributes />
|
||||
</div>
|
||||
@if (View != null && (AllowFiltering || (Multiple && AllowSelectAll) || HeaderTemplate != null))
|
||||
{
|
||||
@@ -44,7 +43,7 @@
|
||||
@if (AllowFiltering)
|
||||
{
|
||||
<div class="rz-listbox-filter-container">
|
||||
<input id="@SearchID" @ref="@search" disabled="@Disabled" class="rz-inputtext" role="textbox" type="text" placeholder="@(Placeholder ?? string.Empty)"
|
||||
<input id="@SearchID" @ref="@search" disabled="@Disabled" class="rz-inputtext" type="text" placeholder="@(Placeholder ?? string.Empty)"
|
||||
@onchange="@OnFilter" @onkeydown="@OnFilterKeyDown" value="@(searchText ?? string.Empty)" @onkeydown:stopPropagation="stopKeydownPropagation"
|
||||
@oninput="@OnFilterInput" aria-label="@SearchAriaLabel" />
|
||||
<span class="notranslate rz-listbox-filter-icon rzi rzi-search"></span>
|
||||
@@ -56,7 +55,9 @@
|
||||
@if (View != null)
|
||||
{
|
||||
<div class="rz-listbox-list-wrapper">
|
||||
<ul @ref="list" id="@ListId" class="rz-listbox-list" role="presentation">
|
||||
<ul @ref="list" id="@ListId" class="rz-listbox-list" role="listbox" tabindex="@(Disabled ? "-1" : $"{TabIndex}")"
|
||||
aria-label="@ListboxAriaLabel" aria-labelledby="@ListboxAriaLabelledBy" aria-multiselectable="@(Multiple ? "true" : "false")"
|
||||
aria-disabled="@(Disabled ? "true" : "false")" aria-activedescendant="@ActiveDescendantId">
|
||||
@RenderItems()
|
||||
</ul>
|
||||
@if (!View.Cast<object>().Any())
|
||||
|
||||
@@ -125,15 +125,20 @@ namespace Radzen.Blazor
|
||||
internal string? ActiveDescendantId => selectedIndex >= 0 ? GetItemId(selectedIndex) : null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the accessible name applied to the listbox, falling back to the empty selection label
|
||||
/// unless the consumer supplies an explicit aria-label or aria-labelledby attribute.
|
||||
/// Gets the accessible name applied to the listbox. Uses the consumer supplied aria-label attribute when present,
|
||||
/// falls back to the empty selection label unless the consumer supplies an aria-labelledby attribute.
|
||||
/// </summary>
|
||||
/// <returns>The accessible name or null when one is supplied via attributes.</returns>
|
||||
/// <returns>The accessible name or null when aria-labelledby is supplied via attributes.</returns>
|
||||
internal string? ListboxAriaLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Attributes != null && (Attributes.ContainsKey("aria-label") || Attributes.ContainsKey("aria-labelledby")))
|
||||
if (Attributes != null && Attributes.TryGetValue("aria-label", out var ariaLabel))
|
||||
{
|
||||
return Convert.ToString(ariaLabel, Culture);
|
||||
}
|
||||
|
||||
if (Attributes != null && Attributes.ContainsKey("aria-labelledby"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -142,6 +147,12 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the consumer supplied aria-labelledby attribute value applied to the listbox, or null when not supplied.
|
||||
/// </summary>
|
||||
/// <returns>The labelling element identifier or null.</returns>
|
||||
internal string? ListboxAriaLabelledBy => Attributes != null && Attributes.TryGetValue("aria-labelledby", out var ariaLabelledBy) ? Convert.ToString(ariaLabelledBy, Culture) : null;
|
||||
|
||||
/// <summary>
|
||||
/// Handles the key down event.
|
||||
/// </summary>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
@onfocus=@OnFocus>
|
||||
@if (Responsive)
|
||||
{
|
||||
<li class="rz-menu-toggle-item">
|
||||
<li class="rz-menu-toggle-item" role="none">
|
||||
<button type="button" aria-label=@ToggleAriaLabel class="rz-menu-toggle" @onclick=@OnToggle
|
||||
aria-haspopup="menu" aria-expanded="@IsOpen.ToString().ToLowerInvariant()" aria-controls="@GetId()">
|
||||
@if (IsOpen)
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
{ "role", "button" },
|
||||
{ "tabindex", "0" }
|
||||
} : null;
|
||||
<div aria-live="polite" class="rz-notification-item-wrapper rz-open @classes.Item1" style="@(clickable ? "cursor: pointer;" : "") @Style"
|
||||
@attributes="wrapperAttributes" @onclick="NotificationClicked" @onkeydown="OnKeyDown">
|
||||
<div role="@(Message?.Severity == NotificationSeverity.Error ? "alert" : null)" class="rz-notification-item-wrapper rz-open @classes.Item1" style="@(clickable ? "cursor: pointer;" : "") @Style">
|
||||
<div class="rz-notification-item">
|
||||
<div class="rz-notification-message-wrapper">
|
||||
<span class="notranslate rzi rz-notification-icon @classes.Item2"></span>
|
||||
<div class="rz-notification-message-wrapper" @attributes="wrapperAttributes" @onclick="NotificationClicked" @onkeydown="OnKeyDown">
|
||||
<span class="notranslate rzi rz-notification-icon @classes.Item2" aria-hidden="true"></span>
|
||||
<div class="rz-notification-message">
|
||||
<div class="rz-notification-title">@if (Message?.SummaryContent != null && Service != null) { @Message.SummaryContent(Service) } else { @Message?.Summary }</div>
|
||||
<div class="rz-notification-content">@if (Message?.DetailContent != null && Service != null) { @Message.DetailContent(Service) } else { @Message?.Detail }</div>
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
@if (GetVisible())
|
||||
{
|
||||
<nav @ref="@Element" @attributes="Attributes" class="@GetCssClass()" style="@Style" id="@GetId()"
|
||||
aria-label="@NavigationAriaLabel" aria-activedescendant="@ActiveDescendantId"
|
||||
@onkeydown="@OnKeyDown" @onkeydown:preventDefault="preventKeyDown" @onkeydown:stopPropagation="stopKeydownPropagation" tabindex=0
|
||||
@onfocus=@this.AsNonRenderingEventHandler(OnFocus)>
|
||||
aria-label="@NavigationAriaLabel"
|
||||
@onkeydown="@OnKeyDown" @onkeydown:preventDefault="preventKeyDown" @onkeydown:stopPropagation="stopKeydownPropagation">
|
||||
@if(ShowPagingSummary)
|
||||
{
|
||||
<span class="rz-pager-summary">
|
||||
@@ -20,13 +19,13 @@
|
||||
}
|
||||
<ul class="rz-pager-pages" role="list">
|
||||
<li class="rz-pager-item">
|
||||
<button id="@(GetId() + "fp")" type="button" tabindex="-1" class="rz-pager-first rz-pager-element @(skip > 0 ? "": "rz-state-disabled") @(focusedIndex == -2 ? "rz-state-focused": "")"
|
||||
<button id="@(GetId() + "fp")" type="button" tabindex="@GetButtonTabIndex(-2)" class="rz-pager-first rz-pager-element @(skip > 0 ? "": "rz-state-disabled") @(focusedIndex == -2 ? "rz-state-focused": "")"
|
||||
@onclick="@(() => OnFirstPageClick())" aria-label="@FirstPageAriaLabel" title="@FirstPageTitle" disabled="@(CurrentPage <= 0)" aria-disabled="@(CurrentPage <= 0 ? "true" : "false")">
|
||||
<span class="notranslate rz-pager-icon rzi rzi-step-backward"></span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="rz-pager-item">
|
||||
<button id="@(GetId() + "pp")" type="button" tabindex="-1" class="rz-pager-prev rz-pager-element @(skip > 0 ? "": "rz-state-disabled") @(focusedIndex == -1 ? "rz-state-focused": "")"
|
||||
<button id="@(GetId() + "pp")" type="button" tabindex="@GetButtonTabIndex(-1)" class="rz-pager-prev rz-pager-element @(skip > 0 ? "": "rz-state-disabled") @(focusedIndex == -1 ? "rz-state-focused": "")"
|
||||
@onclick="@(() => OnPrevPageClick())" aria-label="@PrevPageAriaLabel" title="@PrevPageTitle" disabled="@(CurrentPage <= 0)" aria-disabled="@(CurrentPage <= 0 ? "true" : "false")">
|
||||
<span class="notranslate rz-pager-icon rzi rzi-caret-left"></span>
|
||||
@if (PrevPageLabel != null)
|
||||
@@ -38,13 +37,13 @@
|
||||
@foreach (var i in Enumerable.Range(startPage, Math.Min(endPage + 1, PageNumbersCount)))
|
||||
{
|
||||
<li class="rz-pager-item">
|
||||
<button id="@(GetId() + i.ToString() + "p")" type="button" tabindex="-1" class="rz-pager-page rz-pager-element @(i == CurrentPage ? "rz-state-active" : "") @(startPage + focusedIndex == i ? "rz-state-focused": "")"
|
||||
<button id="@(GetId() + i.ToString() + "p")" type="button" tabindex="@GetButtonTabIndex(i - startPage)" class="rz-pager-page rz-pager-element @(i == CurrentPage ? "rz-state-active" : "") @(startPage + focusedIndex == i ? "rz-state-focused": "")"
|
||||
@onclick="@(() => OnPageClick(i, startPage))" aria-current="@(i == CurrentPage ? "page" : null)" aria-label="@string.Format(PageAriaLabelFormat, (i + 1).ToString())"
|
||||
title="@string.Format(PageTitleFormat, (i + 1).ToString())">@(i + 1)</button>
|
||||
</li>
|
||||
}
|
||||
<li class="rz-pager-item">
|
||||
<button id="@(GetId() + "np")" type="button" tabindex="-1" class="rz-pager-next rz-pager-element @((CurrentPage != numberOfPages - 1) ? "": "rz-state-disabled") @(focusedIndex == Math.Min(endPage + 1, PageNumbersCount)? "rz-state-focused": "")"
|
||||
<button id="@(GetId() + "np")" type="button" tabindex="@GetButtonTabIndex(Math.Min(endPage + 1, PageNumbersCount))" class="rz-pager-next rz-pager-element @((CurrentPage != numberOfPages - 1) ? "": "rz-state-disabled") @(focusedIndex == Math.Min(endPage + 1, PageNumbersCount)? "rz-state-focused": "")"
|
||||
@onclick="@(() => OnNextPageClick(endPage))" aria-label="@NextPageAriaLabel" title="@NextPageTitle" disabled="@(CurrentPage >= (numberOfPages - 1))" aria-disabled="@(CurrentPage >= (numberOfPages - 1) ? "true" : "false")">
|
||||
@if (NextPageLabel != null)
|
||||
{
|
||||
@@ -54,7 +53,7 @@
|
||||
</button>
|
||||
</li>
|
||||
<li class="rz-pager-item">
|
||||
<button id="@(GetId() + "lp")" type="button" tabindex="-1" class="rz-pager-last rz-pager-element @((CurrentPage != numberOfPages - 1) ? "": "rz-state-disabled") @(focusedIndex == Math.Min(endPage + 1, PageNumbersCount) + 1 ? "rz-state-focused": "")"
|
||||
<button id="@(GetId() + "lp")" type="button" tabindex="@GetButtonTabIndex(Math.Min(endPage + 1, PageNumbersCount) + 1)" class="rz-pager-last rz-pager-element @((CurrentPage != numberOfPages - 1) ? "": "rz-state-disabled") @(focusedIndex == Math.Min(endPage + 1, PageNumbersCount) + 1 ? "rz-state-focused": "")"
|
||||
@onclick="@(() => OnLastPageClick(endPage))" aria-label="@LastPageAriaLabel" title="@LastPageTitle" disabled="@(CurrentPage >= (numberOfPages - 1))" aria-disabled="@(CurrentPage >= (numberOfPages - 1) ? "true" : "false")">
|
||||
<span class="notranslate rz-pager-icon rzi rzi-step-forward"></span>
|
||||
</button>
|
||||
@@ -62,7 +61,7 @@
|
||||
@if(AllowReload)
|
||||
{
|
||||
<li class="rz-pager-item">
|
||||
<button id="@(GetId() + "rl")" type="button" tabindex="-1" class="rz-pager-reload rz-pager-element"
|
||||
<button id="@(GetId() + "rl")" type="button" tabindex="@TabIndex" class="rz-pager-reload rz-pager-element"
|
||||
@onclick="@OnReloadClick" aria-label="@ReloadAriaLabel" title="@ReloadTitle">
|
||||
<span class="notranslate rz-pager-icon rz-pager-reload-icon rzi rzi-reload"></span>
|
||||
</button>
|
||||
@@ -72,7 +71,7 @@
|
||||
|
||||
@if(PageSizeOptions != null && PageSizeOptions.Any())
|
||||
{
|
||||
<RadzenDropDown TValue="int" Data="@PageSizeOptions" Value="@PageSize" Change="@OnPageSizeChanged" />
|
||||
<RadzenDropDown TValue="int" Data="@PageSizeOptions" Value="@PageSize" Change="@OnPageSizeChanged" InputAttributes="@(new Dictionary<string, object>() { { "aria-label", PageSizeText } })" />
|
||||
<span class="rz-pagesize-text">@PageSizeText</span>
|
||||
}
|
||||
</nav>
|
||||
|
||||
@@ -420,6 +420,7 @@ namespace Radzen.Blazor
|
||||
if (skip == 0)
|
||||
{
|
||||
focusedIndex = focusedIndex + 2;
|
||||
shouldFocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,6 +433,7 @@ namespace Radzen.Blazor
|
||||
if (skip == 0)
|
||||
{
|
||||
focusedIndex++;
|
||||
shouldFocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,6 +452,7 @@ namespace Radzen.Blazor
|
||||
if (CurrentPage == numberOfPages - 1)
|
||||
{
|
||||
focusedIndex--;
|
||||
shouldFocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,6 +465,7 @@ namespace Radzen.Blazor
|
||||
if (CurrentPage == numberOfPages - 1)
|
||||
{
|
||||
focusedIndex = focusedIndex - 2;
|
||||
shouldFocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,35 +554,58 @@ namespace Radzen.Blazor
|
||||
bool stopKeydownPropagation;
|
||||
int focusedIndex = -3;
|
||||
|
||||
string? ActiveDescendantId
|
||||
/// <summary>
|
||||
/// Gets or sets the tabindex applied to the currently active pager button. All other pager buttons get tabindex <c>-1</c> following the roving tabindex pattern.
|
||||
/// </summary>
|
||||
/// <value>The tabindex of the active pager button. Default is <c>0</c>.</value>
|
||||
[Parameter]
|
||||
public int TabIndex { get; set; }
|
||||
|
||||
int RovingIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (focusedIndex == -3)
|
||||
{
|
||||
return null;
|
||||
var numberOfDisplayedPages = Math.Min(endPage + 1, PageNumbersCount);
|
||||
|
||||
return Math.Clamp(CurrentPage - startPage, 0, Math.Max(numberOfDisplayedPages - 1, 0));
|
||||
}
|
||||
|
||||
var numberOfDisplayedPages = Math.Min(endPage + 1, PageNumbersCount);
|
||||
return focusedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (focusedIndex == -2)
|
||||
string GetButtonTabIndex(int index)
|
||||
{
|
||||
return index == RovingIndex ? TabIndex.ToString(System.Globalization.CultureInfo.InvariantCulture) : "-1";
|
||||
}
|
||||
|
||||
string ActiveButtonId
|
||||
{
|
||||
get
|
||||
{
|
||||
var numberOfDisplayedPages = Math.Min(endPage + 1, PageNumbersCount);
|
||||
var index = RovingIndex;
|
||||
|
||||
if (index == -2)
|
||||
{
|
||||
return $"{GetId()}fp";
|
||||
}
|
||||
if (focusedIndex == -1)
|
||||
if (index == -1)
|
||||
{
|
||||
return $"{GetId()}pp";
|
||||
}
|
||||
if (focusedIndex == numberOfDisplayedPages)
|
||||
if (index == numberOfDisplayedPages)
|
||||
{
|
||||
return $"{GetId()}np";
|
||||
}
|
||||
if (focusedIndex == numberOfDisplayedPages + 1)
|
||||
if (index == numberOfDisplayedPages + 1)
|
||||
{
|
||||
return $"{GetId()}lp";
|
||||
}
|
||||
|
||||
return $"{GetId()}{startPage + focusedIndex}p";
|
||||
return $"{GetId()}{startPage + index}p";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,58 +613,29 @@ namespace Radzen.Blazor
|
||||
/// Handles the key down event.
|
||||
/// </summary>
|
||||
/// <param name="args">The <see cref="KeyboardEventArgs"/> instance containing the event data.</param>
|
||||
protected virtual async Task OnKeyDown(KeyboardEventArgs args)
|
||||
protected virtual Task OnKeyDown(KeyboardEventArgs args)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(args);
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
var numberOfDisplayedPages = Math.Min(endPage + 1, PageNumbersCount);
|
||||
|
||||
if (key == "ArrowLeft" || key == "ArrowRight")
|
||||
if (key == "ArrowLeft" || key == "ArrowRight" || key == "Home" || key == "End")
|
||||
{
|
||||
preventKeyDown = true;
|
||||
stopKeydownPropagation = true;
|
||||
|
||||
focusedIndex = Math.Clamp(focusedIndex + (key == "ArrowLeft" ? -1 : 1), -2, numberOfDisplayedPages + 1);
|
||||
|
||||
if (CurrentPage == 0 && focusedIndex < 0)
|
||||
if (key == "Home")
|
||||
{
|
||||
focusedIndex = 0;
|
||||
focusedIndex = -2;
|
||||
}
|
||||
else if (CurrentPage == numberOfPages - 1 && focusedIndex > numberOfDisplayedPages - 1)
|
||||
else if (key == "End")
|
||||
{
|
||||
focusedIndex = numberOfDisplayedPages - 1;
|
||||
focusedIndex = numberOfDisplayedPages + 1;
|
||||
}
|
||||
}
|
||||
else if (key == "Space" || key == "Enter")
|
||||
{
|
||||
preventKeyDown = true;
|
||||
stopKeydownPropagation = true;
|
||||
|
||||
if (focusedIndex == -2)
|
||||
else
|
||||
{
|
||||
await FirstPage();
|
||||
shouldFocus = true;
|
||||
}
|
||||
else if (focusedIndex == -1)
|
||||
{
|
||||
await PrevPage();
|
||||
shouldFocus = true;
|
||||
}
|
||||
else if (focusedIndex == numberOfDisplayedPages)
|
||||
{
|
||||
await NextPage();
|
||||
shouldFocus = true;
|
||||
}
|
||||
else if (focusedIndex == numberOfDisplayedPages + 1)
|
||||
{
|
||||
await LastPage();
|
||||
shouldFocus = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
await GoToPage(focusedIndex + startPage);
|
||||
shouldFocus = true;
|
||||
focusedIndex = Math.Clamp(RovingIndex + (key == "ArrowLeft" ? -1 : 1), -2, numberOfDisplayedPages + 1);
|
||||
}
|
||||
|
||||
if (CurrentPage == 0 && focusedIndex < 0)
|
||||
@@ -648,31 +646,20 @@ namespace Radzen.Blazor
|
||||
{
|
||||
focusedIndex = numberOfDisplayedPages - 1;
|
||||
}
|
||||
|
||||
shouldFocus = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
preventKeyDown = false;
|
||||
stopKeydownPropagation = false;
|
||||
shouldFocus = false;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
bool shouldFocus;
|
||||
|
||||
void OnFocus()
|
||||
{
|
||||
focusedIndex = focusedIndex == -3 ? 0 : focusedIndex;
|
||||
|
||||
if (CurrentPage == 0 && focusedIndex < 0)
|
||||
{
|
||||
focusedIndex = 0;
|
||||
}
|
||||
else if (CurrentPage == numberOfPages - 1 && focusedIndex > numberOfPages - 1)
|
||||
{
|
||||
focusedIndex = numberOfPages - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
@@ -681,8 +668,14 @@ namespace Radzen.Blazor
|
||||
if (shouldFocus && JSRuntime != null)
|
||||
{
|
||||
shouldFocus = false;
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", GetId());
|
||||
}
|
||||
try
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", ActiveButtonId);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
{
|
||||
<li @ref=@Element style=@Style @attributes=@Attributes class="@(GetCssClass() + ExpandableClass)" id=@GetId()
|
||||
role="menuitem" tabindex="-1" aria-disabled="@(Disabled ? "true" : "false")"
|
||||
aria-haspopup="@(ChildContent != null ? "menu" : null)"
|
||||
aria-controls="@(RenderSubmenu ? $"{GetId()}-submenu" : null)"
|
||||
aria-expanded="@(ChildContent != null ? expanded.ToString().ToLowerInvariant() : null)"
|
||||
@onclick=@(this.AsNonRenderingEventHandler<MouseEventArgs>(OnClick)) @onclick:stopPropagation @onkeydown="OnKeyDown">
|
||||
@@ -38,9 +37,7 @@
|
||||
else
|
||||
{
|
||||
<div class="rz-navigation-item-link" style="@(Parent?.DisplayStyle == MenuItemDisplayStyle.Icon?"margin-inline-end:0px;":"")"
|
||||
role="button" tabindex="-1" aria-expanded="@expanded.ToString().ToLowerInvariant()"
|
||||
aria-controls="@(RenderSubmenu ? $"{GetId()}-submenu" : null)"
|
||||
aria-haspopup="@(ChildContent != null ? "menu" : null)"
|
||||
tabindex="-1"
|
||||
@onclick="@Toggle" @onkeydown="OnToggleKeyDown">
|
||||
@if (!string.IsNullOrEmpty(Icon) && Parent?.DisplayStyle != MenuItemDisplayStyle.Text)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
<RadzenStack class="rz-picklist-source-wrapper">
|
||||
@if (ShowHeader && SourceHeader != null)
|
||||
{
|
||||
@SourceHeader
|
||||
<div id="@(GetId() + "-source-header")">
|
||||
@SourceHeader
|
||||
</div>
|
||||
}
|
||||
<CascadingValue Value="@((EditContext?)null)" IsFixed=true>
|
||||
<RadzenListBox @ref=sourceListBox Value=@selectedSourceItems ValueChanged="@(EventCallback.Factory.Create<object>(this, OnSelectedSourceItemsChanged))" Data="@source" Multiple="@Multiple" @bind-SearchText=@sourceSearchText
|
||||
@@ -20,23 +22,27 @@
|
||||
Disabled=@(Disabled || Source == null || (Source != null && !Source.Any()))
|
||||
EmptyText="@(SourceEmptyText ?? EmptyText)" EmptyTemplate="@(SourceEmptyTemplate ?? EmptyTemplate)"
|
||||
AllowVirtualization="@AllowVirtualization"
|
||||
aria-label="@(ShowHeader && SourceHeader != null ? null : SourceAriaLabel)"
|
||||
aria-labelledby="@(ShowHeader && SourceHeader != null ? GetId() + "-source-header" : null)"
|
||||
/>
|
||||
</CascadingValue>
|
||||
</RadzenStack>
|
||||
<RadzenStack Orientation="@(Orientation == Orientation.Vertical ? Orientation.Horizontal : Orientation.Vertical)" JustifyContent="@ButtonJustifyContent" Gap="@ButtonGap" class="rz-picklist-buttons">
|
||||
<RadzenButton Icon="@SelectedSourceToTargetIcon" title="@SelectedSourceToTargetTitle" Click="@SelectedSourceToTarget" Disabled=@(Disabled || selectedSourceItems == null || (Multiple && (selectedSourceItems as IEnumerable)?.Cast<object>().Any() != true))
|
||||
<RadzenButton Icon="@SelectedSourceToTargetIcon" title="@SelectedSourceToTargetTitle" aria-label="@SelectedSourceToTargetTitle" Click="@SelectedSourceToTarget" Disabled=@(Disabled || selectedSourceItems == null || (Multiple && (selectedSourceItems as IEnumerable)?.Cast<object>().Any() != true))
|
||||
ButtonStyle="@ButtonStyle" Size="@ButtonSize" Variant="@ButtonVariant" Shade="@ButtonShade" />
|
||||
<RadzenButton Icon="@SelectedTargetToSourceIcon" title="@SelectedTargetToSourceTitle" Click="@SelectedTargetToSource" Disabled=@(Disabled || selectedTargetItems == null || (Multiple && (selectedTargetItems as IEnumerable)?.Cast<object>().Any() != true))
|
||||
<RadzenButton Icon="@SelectedTargetToSourceIcon" title="@SelectedTargetToSourceTitle" aria-label="@SelectedTargetToSourceTitle" Click="@SelectedTargetToSource" Disabled=@(Disabled || selectedTargetItems == null || (Multiple && (selectedTargetItems as IEnumerable)?.Cast<object>().Any() != true))
|
||||
ButtonStyle="@ButtonStyle" Size="@ButtonSize" Variant="@ButtonVariant" Shade="@ButtonShade"/>
|
||||
<RadzenButton Icon="@SourceToTargetIcon" title="@SourceToTargetTitle" Click="@SourceToTarget" Disabled=@(Disabled || source == null || (source != null && !source.Any()))
|
||||
<RadzenButton Icon="@SourceToTargetIcon" title="@SourceToTargetTitle" aria-label="@SourceToTargetTitle" Click="@SourceToTarget" Disabled=@(Disabled || source == null || (source != null && !source.Any()))
|
||||
ButtonStyle="@ButtonStyle" Size="@ButtonSize" Variant="@ButtonVariant" Shade="@ButtonShade" Visible=@(AllowMoveAll && AllowMoveAllSourceToTarget) />
|
||||
<RadzenButton Icon="@TargetToSourceIcon" title="@TargetToSourceTitle" Click="@TargetToSource" Disabled=@(Disabled || target == null|| (target != null && !target.Any()))
|
||||
<RadzenButton Icon="@TargetToSourceIcon" title="@TargetToSourceTitle" aria-label="@TargetToSourceTitle" Click="@TargetToSource" Disabled=@(Disabled || target == null|| (target != null && !target.Any()))
|
||||
ButtonStyle="@ButtonStyle" Size="@ButtonSize" Variant="@ButtonVariant" Shade="@ButtonShade" Visible=@(AllowMoveAll && AllowMoveAllTargetToSource)/>
|
||||
</RadzenStack>
|
||||
<RadzenStack class="rz-picklist-target-wrapper">
|
||||
@if (ShowHeader && TargetHeader != null)
|
||||
{
|
||||
@TargetHeader
|
||||
<div id="@(GetId() + "-target-header")">
|
||||
@TargetHeader
|
||||
</div>
|
||||
}
|
||||
<CascadingValue Value="@((EditContext?)null)" IsFixed=true>
|
||||
<RadzenListBox @ref=targetListBox Value=@selectedTargetItems ValueChanged="@(EventCallback.Factory.Create<object>(this, OnSelectedTargetItemsChanged))" Data="@target" Multiple="@Multiple" @bind-SearchText=@targetSearchText
|
||||
@@ -46,6 +52,8 @@
|
||||
Disabled=@(Disabled || Target == null|| (Target != null && !Target.Any()))
|
||||
EmptyText="@(TargetEmptyText ?? EmptyText)" EmptyTemplate="@(TargetEmptyTemplate ?? EmptyTemplate)"
|
||||
AllowVirtualization="@AllowVirtualization"
|
||||
aria-label="@(ShowHeader && TargetHeader != null ? null : TargetAriaLabel)"
|
||||
aria-labelledby="@(ShowHeader && TargetHeader != null ? GetId() + "-target-header" : null)"
|
||||
/>
|
||||
</CascadingValue>
|
||||
</RadzenStack>
|
||||
|
||||
@@ -188,6 +188,24 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string EmptyText { get => emptyText ?? Localize(nameof(RadzenStrings.PickList_EmptyText)); set => emptyText = value; }
|
||||
|
||||
private string? sourceAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label of the source list. Ignored when <see cref="SourceHeader"/> is rendered - the source list is labelled by the header instead.
|
||||
/// </summary>
|
||||
/// <value>The source list aria-label.</value>
|
||||
[Parameter]
|
||||
public string SourceAriaLabel { get => sourceAriaLabel ?? Localize(nameof(RadzenStrings.PickList_SourceAriaLabel)); set => sourceAriaLabel = value; }
|
||||
|
||||
private string? targetAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aria-label of the target list. Ignored when <see cref="TargetHeader"/> is rendered - the target list is labelled by the header instead.
|
||||
/// </summary>
|
||||
/// <value>The target list aria-label.</value>
|
||||
[Parameter]
|
||||
public string TargetAriaLabel { get => targetAriaLabel ?? Localize(nameof(RadzenStrings.PickList_TargetAriaLabel)); set => targetAriaLabel = value; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the empty text shown when the source list has no items. Overrides <see cref="EmptyText"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
role="presentation" tabindex="-1">
|
||||
<li class="rz-navigation-item" role="presentation">
|
||||
<div @ref="@toggleElement" class="rz-navigation-item-wrapper" role="button" tabindex="0" aria-haspopup="menu"
|
||||
aria-label="@ToggleAriaLabel" aria-activedescendant="@ActiveDescendantId"
|
||||
aria-label="@ToggleAriaLabel"
|
||||
aria-expanded="@((!Collapsed).ToString().ToLowerInvariant())" aria-controls="@($"{GetId()}-menu")"
|
||||
@onkeydown="@OnKeyPress" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeydownPropagation">
|
||||
<div class="rz-navigation-item-link">
|
||||
@@ -24,7 +24,8 @@
|
||||
</div>
|
||||
<ul @ref="@menuElement" id="@($"{GetId()}-menu")" class="rz-navigation-menu" role="menu" style="@contentStyle"
|
||||
tabindex="-1" aria-label="@ToggleAriaLabel" aria-hidden="@(Collapsed ? "true" : "false")"
|
||||
@onkeydown:stopPropagation="stopGuardKeydownPropagation" @onkeydown="OnGuardKeyDown">
|
||||
aria-activedescendant="@ActiveDescendantId"
|
||||
@onkeydown="@OnKeyPress" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeydownPropagation">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
|
||||
@@ -41,6 +41,25 @@ namespace Radzen.Blazor
|
||||
_jsRef = await JSRuntime.InvokeAsync<IJSObjectReference>(
|
||||
"Radzen.createProfileMenu", Element);
|
||||
}
|
||||
|
||||
if (shouldFocusMenu)
|
||||
{
|
||||
shouldFocusMenu = false;
|
||||
|
||||
try
|
||||
{
|
||||
await menuElement.FocusAsync(preventScroll: true);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
}
|
||||
catch (JSDisconnectedException)
|
||||
{
|
||||
}
|
||||
catch (JSException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -134,6 +153,8 @@ namespace Radzen.Blazor
|
||||
|
||||
internal int focusedIndex = -1;
|
||||
|
||||
bool shouldFocusMenu;
|
||||
|
||||
bool preventKeyPress = true;
|
||||
bool stopKeydownPropagation;
|
||||
async Task OnKeyPress(KeyboardEventArgs args)
|
||||
@@ -150,6 +171,8 @@ namespace Radzen.Blazor
|
||||
await Toggle(new MouseEventArgs());
|
||||
|
||||
focusedIndex = key == "ArrowUp" ? items.Count - 1 : 0;
|
||||
|
||||
shouldFocusMenu = true;
|
||||
}
|
||||
else if (items.Count > 0)
|
||||
{
|
||||
@@ -165,6 +188,8 @@ namespace Radzen.Blazor
|
||||
if (Collapsed)
|
||||
{
|
||||
await Toggle(new MouseEventArgs());
|
||||
|
||||
shouldFocusMenu = true;
|
||||
}
|
||||
|
||||
focusedIndex = key == "Home" ? 0 : items.Count - 1;
|
||||
@@ -194,6 +219,8 @@ namespace Radzen.Blazor
|
||||
if (!Collapsed)
|
||||
{
|
||||
focusedIndex = focusedIndex != -1 ? focusedIndex : 0;
|
||||
|
||||
shouldFocusMenu = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@($"--rz-progressbar-value: {(NormalizedValue * 100).ToInvariantString()}%;{Style}")" aria-valuemax="@Max" aria-valuemin="@Min" role="progressbar" @attributes="Attributes" class="@GetCssClass()"
|
||||
aria-valuenow="@Value" aria-label="@AriaLabel" id="@GetId()">
|
||||
aria-valuenow="@(Mode == ProgressBarMode.Indeterminate ? null : (double?)Value)" aria-label="@AriaLabel" id="@GetId()">
|
||||
<div class="rz-progressbar-value"></div>
|
||||
@if (ShowValue)
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@Style" aria-valuemax="@Max" aria-valuemin="@Min" role="progressbar" @attributes="Attributes" class="@GetCssClass()"
|
||||
aria-valuenow="@Value" aria-label="@AriaLabel" id="@GetId()">
|
||||
aria-valuenow="@(Mode == ProgressBarMode.Indeterminate ? null : (double?)Value)" aria-label="@AriaLabel" id="@GetId()">
|
||||
<svg class="rz-progressbar-circular-viewbox" viewBox="-19 -19 38 38">
|
||||
<circle class="rz-progressbar-circular-background" r="15.91549" fill="none" />
|
||||
<circle class="rz-progressbar-circular-value" r="15.91549" fill="none" stroke-dashoffset="@(((1 - NormalizedValue) * 100).ToInvariantString())" />
|
||||
|
||||
@@ -3,20 +3,20 @@
|
||||
@inherits FormComponent<int>
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style=@Style @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<div @ref="@Element" style=@Style @attributes="Attributes" class="@GetCssClass()" id="@GetId()" role="radiogroup" aria-label="@AriaLabel" aria-readonly="@(ReadOnly ? "true" : null)">
|
||||
@if (!ReadOnly)
|
||||
{
|
||||
<button type="button" id="@(GetId() + "cl")" aria-label="@ClearAriaLabel" @onclick="@(args => SetValue(0))" class="rz-rating-cancel"
|
||||
tabindex="@(Disabled ? "-1" : $"{TabIndex}")"
|
||||
@onkeypress="@(args => OnKeyPress(args, SetValue(0)))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation="stopKeypressPropagation">
|
||||
tabindex="@(Disabled ? "-1" : $"{TabIndex}")">
|
||||
<span class="notranslate rz-rating-icon rzi rzi-ban"></span>
|
||||
</button>
|
||||
}
|
||||
@foreach (var index in Enumerable.Range(1, Stars))
|
||||
{
|
||||
<button type="button" id="@(GetId() + index.ToString() + "r")" aria-label="@RateAriaLabel" @onclick="@(args => SetValue(index))"
|
||||
tabindex="@(Disabled ? "-1" : $"{TabIndex}")"
|
||||
@onkeypress="@(args => OnKeyPress(args, SetValue(index)))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation="stopKeypressPropagation">
|
||||
<button type="button" id="@(GetId() + index.ToString() + "r")" role="radio" aria-checked="@(index == Value ? "true" : "false")"
|
||||
aria-posinset="@index" aria-setsize="@Stars" aria-label="@($"{RateAriaLabel} {index}")" @onclick="@(args => SetValue(index))"
|
||||
tabindex="@(Disabled ? "-1" : index == FocusableStar ? $"{TabIndex}" : "-1")"
|
||||
@onkeydown="@(args => OnKeyDown(args, index))" @onkeydown:preventDefault=preventKeyDown @onkeydown:stopPropagation=preventKeyDown>
|
||||
<span class="notranslate rz-rating-icon rzi @(index <= Value ? "rzi-star": "rzi-star-o")"></span>
|
||||
</button>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Radzen.Blazor
|
||||
@@ -42,6 +44,16 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public int Stars { get; set; } = 5;
|
||||
|
||||
private string? ariaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the accessible label text for the rating radio group.
|
||||
/// Used by screen readers to announce the purpose of the component.
|
||||
/// </summary>
|
||||
/// <value>The ARIA label for the rating group. Default is "Rating".</value>
|
||||
[Parameter]
|
||||
public string AriaLabel { get => ariaLabel ?? Localize(nameof(RadzenStrings.Rating_AriaLabel)); set => ariaLabel = value; }
|
||||
|
||||
private string? clearAriaLabel;
|
||||
|
||||
/// <summary>
|
||||
@@ -83,23 +95,35 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
bool preventKeyPress = true;
|
||||
bool stopKeypressPropagation;
|
||||
async Task OnKeyPress(KeyboardEventArgs args, Task task)
|
||||
int FocusableStar => Value >= 1 && Value <= Stars ? Value : 1;
|
||||
|
||||
bool preventKeyDown;
|
||||
|
||||
async Task OnKeyDown(KeyboardEventArgs args, int index)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
if (key == "Space" || key == "Enter")
|
||||
if (key == "ArrowRight" || key == "ArrowUp" || key == "ArrowLeft" || key == "ArrowDown")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
stopKeypressPropagation = true;
|
||||
preventKeyDown = true;
|
||||
|
||||
await task;
|
||||
if (Disabled || ReadOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var next = key == "ArrowRight" || key == "ArrowUp" ? Math.Min(index + 1, Stars) : Math.Max(index - 1, 1);
|
||||
|
||||
await SetValue(next);
|
||||
|
||||
if (JSRuntime != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", GetId() + next.ToString(System.Globalization.CultureInfo.InvariantCulture) + "r");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
preventKeyPress = false;
|
||||
stopKeypressPropagation = false;
|
||||
preventKeyDown = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,18 +20,18 @@
|
||||
<div class="rz-scheduler-nav-prev-next">
|
||||
@if (ShowNavigationButtons)
|
||||
{
|
||||
<button type="button" tabindex="0" class="rz-button rz-prev" @onclick=@OnPrev title="@PrevText"><RadzenIcon Icon="chevron_left" /></button>
|
||||
<button type="button" tabindex="0" class="rz-button rz-next" @onclick=@OnNext title="@NextText"><RadzenIcon Icon="chevron_right" /></button>
|
||||
<button type="button" tabindex="0" class="rz-button rz-prev" @onclick=@OnPrev title="@PrevText" aria-label="@PrevText"><RadzenIcon Icon="chevron_left" /></button>
|
||||
<button type="button" tabindex="0" class="rz-button rz-next" @onclick=@OnNext title="@NextText" aria-label="@NextText"><RadzenIcon Icon="chevron_right" /></button>
|
||||
}
|
||||
@if (ShowTodayButton)
|
||||
{
|
||||
<button type="button" tabindex="0" class="rz-button rz-today" @onclick=@OnToday title="@TodayText">@TodayText</button>
|
||||
<button type="button" tabindex="0" class="rz-button rz-today" @onclick=@OnToday title="@TodayText" aria-label="@TodayText">@TodayText</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (ShowDateTitle)
|
||||
{
|
||||
<div class="rz-scheduler-nav-title">@SelectedView?.Title</div>
|
||||
<div class="rz-scheduler-nav-title" aria-live="polite">@SelectedView?.Title</div>
|
||||
}
|
||||
<div class="rz-scheduler-nav-views">
|
||||
@if (NavigationTemplate != null)
|
||||
@@ -42,7 +42,7 @@
|
||||
{
|
||||
@foreach (var view in Views)
|
||||
{
|
||||
<RadzenButton Click=@(args => OnChangeView(view)) Icon=@view.Icon Text=@view.Text class="@($"{(IsSelected(view) ? " rz-state-active" : "")}")" />
|
||||
<RadzenButton Click=@(args => OnChangeView(view)) Icon=@view.Icon Text=@view.Text aria-pressed="@(IsSelected(view) ? "true" : "false")" class="@($"{(IsSelected(view) ? " rz-state-active" : "")}")" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@inherits FormComponent<string>
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style=@Style @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<div @ref="@Element" style=@Style @attributes="Attributes" class="@GetCssClass()" id="@GetId()" role="group" aria-label="@AriaLabel">
|
||||
<div class="rz-helper-hidden-accessible">
|
||||
<input disabled="@Disabled" type="hidden" name="@Name">
|
||||
</div>
|
||||
@@ -13,15 +13,15 @@
|
||||
{
|
||||
@if (Type == SecurityCodeType.Password)
|
||||
{
|
||||
<RadzenPassword Value="@ElementAt(index - 1)" Disabled="@Disabled" autocomplete="one-time-code" MaxLength="1" size="1" class="rz-security-code-input" />
|
||||
<RadzenPassword Value="@ElementAt(index - 1)" Disabled="@Disabled" autocomplete="one-time-code" MaxLength="1" size="1" class="rz-security-code-input" aria-label="@GetInputAriaLabel(index)" />
|
||||
}
|
||||
else if (Type == SecurityCodeType.Numeric)
|
||||
{
|
||||
<RadzenTextBox inputmode="numeric" pattern="[0-9]*" Value="@ElementAt(index - 1)" Disabled="@Disabled" autocomplete="one-time-code" MaxLength="1" size="1" class="rz-security-code-input" />
|
||||
<RadzenTextBox inputmode="numeric" pattern="[0-9]*" Value="@ElementAt(index - 1)" Disabled="@Disabled" autocomplete="one-time-code" MaxLength="1" size="1" class="rz-security-code-input" aria-label="@GetInputAriaLabel(index)" />
|
||||
}
|
||||
else
|
||||
{
|
||||
<RadzenTextBox Value="@ElementAt(index - 1)" Disabled="@Disabled" autocomplete="one-time-code" MaxLength="1" size="1" class="rz-security-code-input" />
|
||||
<RadzenTextBox Value="@ElementAt(index - 1)" Disabled="@Disabled" autocomplete="one-time-code" MaxLength="1" size="1" class="rz-security-code-input" aria-label="@GetInputAriaLabel(index)" />
|
||||
}
|
||||
}
|
||||
</RadzenStack>
|
||||
|
||||
@@ -44,6 +44,30 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string? Gap { get; set; }
|
||||
|
||||
private string? ariaLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the accessible label text of the security code group.
|
||||
/// </summary>
|
||||
/// <value>The ARIA label of the security code group. Default is "Security code".</value>
|
||||
[Parameter]
|
||||
public string AriaLabel { get => ariaLabel ?? Localize(nameof(RadzenStrings.SecurityCode_AriaLabel)); set => ariaLabel = value; }
|
||||
|
||||
private string? inputAriaLabelFormat;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format string used to build the accessible label of each input.
|
||||
/// The first argument is the input position and the second one is the total number of inputs.
|
||||
/// </summary>
|
||||
/// <value>The ARIA label format of each input. Default is "Character {0} of {1}".</value>
|
||||
[Parameter]
|
||||
public string InputAriaLabelFormat { get => inputAriaLabelFormat ?? Localize(nameof(RadzenStrings.SecurityCode_InputAriaLabelFormat)); set => inputAriaLabelFormat = value; }
|
||||
|
||||
string GetInputAriaLabel(int index)
|
||||
{
|
||||
return string.Format(System.Globalization.CultureInfo.CurrentCulture, InputAriaLabelFormat, index, Count);
|
||||
}
|
||||
|
||||
IJSObjectReference? _jsRef;
|
||||
|
||||
bool firstRender;
|
||||
|
||||
@@ -304,16 +304,26 @@ namespace Radzen.Blazor
|
||||
var direction = key == "ArrowLeft" || key == "ArrowUp" ? -1 : 1;
|
||||
|
||||
var start = focusedIndex < 0 ? 0 : focusedIndex;
|
||||
var next = start + direction;
|
||||
var next = start;
|
||||
|
||||
while (next >= 0 && next < navigableItems.Count && navigableItems[next].Disabled)
|
||||
for (var step = 0; step < navigableItems.Count; step++)
|
||||
{
|
||||
next += direction;
|
||||
next = (next + direction + navigableItems.Count) % navigableItems.Count;
|
||||
|
||||
if (!navigableItems[next].Disabled)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next >= 0 && next < navigableItems.Count)
|
||||
if (!navigableItems[next].Disabled)
|
||||
{
|
||||
focusedIndex = next;
|
||||
|
||||
if (!Multiple && !IsSelected(navigableItems[focusedIndex]))
|
||||
{
|
||||
await SelectItem(navigableItems[focusedIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key == "Home" || key == "End")
|
||||
@@ -337,6 +347,11 @@ namespace Radzen.Blazor
|
||||
focusedIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Multiple && focusedIndex >= 0 && focusedIndex < navigableItems.Count && !navigableItems[focusedIndex].Disabled && !IsSelected(navigableItems[focusedIndex]))
|
||||
{
|
||||
await SelectItem(navigableItems[focusedIndex]);
|
||||
}
|
||||
}
|
||||
else if (key == "Space" || key == "Enter")
|
||||
{
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
@inherits RadzenComponentWithChildren
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()"
|
||||
tabindex="@(Disabled ? -1 : TabIndex)" role="button" aria-activedescendant="@ActiveDescendantId" aria-haspopup="menu" aria-controls="@PopupID" aria-expanded="@(IsOpen ? "true" : "false")" @onkeydown="@OnKeyPress" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeydownPropagation">
|
||||
<button aria-label="@(ButtonAriaLabel ?? Text)" tabindex="-1" disabled="@IsDisabled" class=@ButtonClass type="@((Enum.GetName(typeof(ButtonType), ButtonType) ?? ButtonType.ToString()).ToLower())" @onclick="@OnClick">
|
||||
<div @ref="@Element" style="@Style" @attributes="Attributes" class="@GetCssClass()" id="@GetId()">
|
||||
<button aria-label="@(ButtonAriaLabel ?? Text)" tabindex="@(IsDisabled ? -1 : TabIndex)" disabled="@IsDisabled" class=@ButtonClass type="@((Enum.GetName(typeof(ButtonType), ButtonType) ?? ButtonType.ToString()).ToLower())" @onclick="@OnClick">
|
||||
<span class="rz-button-box">
|
||||
@if (ButtonContent != null)
|
||||
{
|
||||
@@ -25,7 +24,7 @@
|
||||
{
|
||||
@if (!string.IsNullOrEmpty(@Icon))
|
||||
{
|
||||
<i class="notranslate rz-button-icon-left rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@Icon</i>
|
||||
<i class="notranslate rz-button-icon-left rzi" aria-hidden="true" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@Icon</i>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Image))
|
||||
{
|
||||
@@ -43,12 +42,14 @@
|
||||
}
|
||||
</span>
|
||||
</button>
|
||||
<button tabindex="-1" disabled="@IsDisabled" class=@PopupButtonClass type="button" @onclick="@OnToggleClick"
|
||||
aria-label="@OpenAriaLabel">
|
||||
<button id="@ToggleButtonId" tabindex="@(IsDisabled ? -1 : TabIndex)" disabled="@IsDisabled" class=@PopupButtonClass type="button" @onclick="@OnToggleClick"
|
||||
aria-label="@OpenAriaLabel" aria-haspopup="menu" aria-controls="@PopupID" aria-expanded="@(IsOpen ? "true" : "false")"
|
||||
@onkeydown="@OnToggleKeyDown" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeydownPropagation">
|
||||
<RadzenIcon Icon="@DropDownIcon" />
|
||||
</button>
|
||||
<div id="@PopupID" class="@PopupMenuClass">
|
||||
<ul class="rz-menu-list" role="menu" aria-orientation="vertical" aria-label="@OpenAriaLabel">
|
||||
<ul id="@MenuId" class="rz-menu-list" role="menu" aria-orientation="vertical" aria-label="@OpenAriaLabel" tabindex="-1"
|
||||
aria-activedescendant="@ActiveDescendantId" @onkeydown="@OnMenuKeyDown" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeydownPropagation">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
|
||||
@@ -207,6 +207,11 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.togglePopup", Element, PopupID);
|
||||
|
||||
if (IsOpen)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", MenuId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -219,7 +224,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
void OnToggleClick()
|
||||
async Task OnToggleClick()
|
||||
{
|
||||
if (Disabled)
|
||||
{
|
||||
@@ -228,9 +233,17 @@ namespace Radzen.Blazor
|
||||
|
||||
IsOpen = !IsOpen;
|
||||
|
||||
if (IsOpen && focusedIndex == -1 && items.Count > 0)
|
||||
if (IsOpen)
|
||||
{
|
||||
focusedIndex = 0;
|
||||
if (focusedIndex == -1 && items.Count > 0)
|
||||
{
|
||||
focusedIndex = 0;
|
||||
}
|
||||
|
||||
if (JSRuntime != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", MenuId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +272,10 @@ namespace Radzen.Blazor
|
||||
}
|
||||
}
|
||||
|
||||
private string MenuId => $"{GetId()}-menu";
|
||||
|
||||
private string ToggleButtonId => $"{GetId()}-toggle";
|
||||
|
||||
string ButtonClass => ClassList.Create("rz-button")
|
||||
.AddButtonSize(Size)
|
||||
.AddVariant(Variant)
|
||||
@@ -333,7 +350,7 @@ namespace Radzen.Blazor
|
||||
}
|
||||
|
||||
internal int focusedIndex = -1;
|
||||
bool preventKeyPress = true;
|
||||
bool preventKeyPress;
|
||||
bool stopKeydownPropagation;
|
||||
|
||||
async Task Open(int index)
|
||||
@@ -345,41 +362,53 @@ namespace Radzen.Blazor
|
||||
if (JSRuntime != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.togglePopup", Element, PopupID);
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", MenuId);
|
||||
}
|
||||
}
|
||||
|
||||
async Task OnKeyPress(KeyboardEventArgs args)
|
||||
async Task OnToggleKeyDown(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
if (!IsOpen && (key == "ArrowDown" || key == "ArrowUp") && items.Count > 0)
|
||||
{
|
||||
preventKeyPress = true;
|
||||
stopKeydownPropagation = true;
|
||||
|
||||
await Open(key == "ArrowDown" ? 0 : items.Count - 1);
|
||||
}
|
||||
else if (IsOpen && key == "Escape")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
stopKeydownPropagation = true;
|
||||
|
||||
await CloseAndFocusToggle();
|
||||
}
|
||||
else
|
||||
{
|
||||
preventKeyPress = false;
|
||||
stopKeydownPropagation = false;
|
||||
}
|
||||
}
|
||||
|
||||
async Task CloseAndFocusToggle()
|
||||
{
|
||||
Close();
|
||||
|
||||
if (JSRuntime != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", ToggleButtonId);
|
||||
}
|
||||
}
|
||||
|
||||
async Task OnMenuKeyDown(KeyboardEventArgs args)
|
||||
{
|
||||
var key = args.Code != null ? args.Code : args.Key;
|
||||
|
||||
if (!IsOpen)
|
||||
{
|
||||
if (key == "Enter" || key == "Space" || key == "NumpadEnter")
|
||||
{
|
||||
preventKeyPress = true;
|
||||
stopKeydownPropagation = true;
|
||||
|
||||
await OnClick(new MouseEventArgs());
|
||||
}
|
||||
else if (key == "ArrowDown" && items.Count > 0)
|
||||
{
|
||||
preventKeyPress = true;
|
||||
stopKeydownPropagation = true;
|
||||
|
||||
await Open(0);
|
||||
}
|
||||
else if (key == "ArrowUp" && items.Count > 0)
|
||||
{
|
||||
preventKeyPress = true;
|
||||
stopKeydownPropagation = true;
|
||||
|
||||
await Open(items.Count - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
preventKeyPress = false;
|
||||
stopKeydownPropagation = false;
|
||||
}
|
||||
preventKeyPress = false;
|
||||
stopKeydownPropagation = false;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -410,9 +439,10 @@ namespace Radzen.Blazor
|
||||
{
|
||||
await items[focusedIndex].OnClick(new MouseEventArgs());
|
||||
}
|
||||
else
|
||||
|
||||
if (JSRuntime != null)
|
||||
{
|
||||
await OnClick(new MouseEventArgs());
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", ToggleButtonId);
|
||||
}
|
||||
}
|
||||
else if (key == "Escape")
|
||||
@@ -420,12 +450,7 @@ namespace Radzen.Blazor
|
||||
preventKeyPress = true;
|
||||
stopKeydownPropagation = true;
|
||||
|
||||
Close();
|
||||
|
||||
if (JSRuntime != null)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("Radzen.focusElement", GetId());
|
||||
}
|
||||
await CloseAndFocusToggle();
|
||||
}
|
||||
else if (args.Key != null && args.Key.Length == 1 && !args.AltKey && !args.CtrlKey && !args.MetaKey && !char.IsControl(args.Key[0]))
|
||||
{
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
role="button"
|
||||
aria-label="@CollapseAriaLabel"
|
||||
aria-expanded="@AriaExpanded"
|
||||
@onkeypress="@(args => OnKeyPress(args, false))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation=stopKeypressPropagation
|
||||
@onkeydown="@(args => OnKeyPress(args, false))" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation=stopKeypressPropagation
|
||||
@onmousedown:preventDefault="true" @onmousedown:stopPropagation="true" @onmousedown=@(args => Splitter!.OnCollapse(Index))>
|
||||
</span>
|
||||
}
|
||||
@@ -55,7 +55,7 @@
|
||||
role="button"
|
||||
aria-label="@ExpandAriaLabel"
|
||||
aria-expanded="@AriaExpanded"
|
||||
@onkeypress="@(args => OnKeyPress(args, true))" @onkeypress:preventDefault=preventKeyPress @onkeypress:stopPropagation=stopKeypressPropagation
|
||||
@onkeydown="@(args => OnKeyPress(args, true))" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation=stopKeypressPropagation
|
||||
@onmousedown:preventDefault="true" @onmousedown:stopPropagation="true" @onmousedown=@(args => Splitter!.OnExpand(Index))>
|
||||
</span>
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
var index = i;
|
||||
@if (step.Visible)
|
||||
{
|
||||
<li class="@step.GetItemCssClass()" @attributes="step.Attributes" style="@step.Style">
|
||||
<li class="@step.GetItemCssClass()" role="presentation" @attributes="step.Attributes" style="@step.Style">
|
||||
<button type="button" role="tab" id="@(GetId() + i.ToString() + "s")" title="@step.Title" aria-label="@step.AriaLabel"
|
||||
aria-selected="@(IsSelected(i, step) ? "true" : "false")"
|
||||
aria-controls="@($"{GetId()}-panel-{i}")"
|
||||
|
||||
16
Radzen.Blazor/RadzenStrings.Designer.cs
generated
16
Radzen.Blazor/RadzenStrings.Designer.cs
generated
@@ -299,8 +299,12 @@ namespace Radzen.Blazor {
|
||||
public static string AIChat_EmptyMessage { get { return ResourceManager.GetString("AIChat_EmptyMessage", resourceCulture); } }
|
||||
public static string AIChat_UserAvatarText { get { return ResourceManager.GetString("AIChat_UserAvatarText", resourceCulture); } }
|
||||
public static string AIChat_AssistantAvatarText { get { return ResourceManager.GetString("AIChat_AssistantAvatarText", resourceCulture); } }
|
||||
public static string Alert_CloseAriaLabel { get { return ResourceManager.GetString("Alert_CloseAriaLabel", resourceCulture); } }
|
||||
public static string Button_ImageAlternateText { get { return ResourceManager.GetString("Button_ImageAlternateText", resourceCulture); } }
|
||||
public static string Carousel_PagerButtonAriaLabelFormat { get { return ResourceManager.GetString("Carousel_PagerButtonAriaLabelFormat", resourceCulture); } }
|
||||
public static string Carousel_PrevAriaLabel { get { return ResourceManager.GetString("Carousel_PrevAriaLabel", resourceCulture); } }
|
||||
public static string Carousel_NextAriaLabel { get { return ResourceManager.GetString("Carousel_NextAriaLabel", resourceCulture); } }
|
||||
public static string Carousel_SlideAriaLabelFormat { get { return ResourceManager.GetString("Carousel_SlideAriaLabelFormat", resourceCulture); } }
|
||||
public static string Chat_Placeholder { get { return ResourceManager.GetString("Chat_Placeholder", resourceCulture); } }
|
||||
public static string Chat_EmptyMessage { get { return ResourceManager.GetString("Chat_EmptyMessage", resourceCulture); } }
|
||||
public static string Chat_NewMessagesText { get { return ResourceManager.GetString("Chat_NewMessagesText", resourceCulture); } }
|
||||
@@ -314,6 +318,10 @@ namespace Radzen.Blazor {
|
||||
public static string ColorPicker_BlueText { get { return ResourceManager.GetString("ColorPicker_BlueText", resourceCulture); } }
|
||||
public static string ColorPicker_AlphaText { get { return ResourceManager.GetString("ColorPicker_AlphaText", resourceCulture); } }
|
||||
public static string ColorPicker_ButtonText { get { return ResourceManager.GetString("ColorPicker_ButtonText", resourceCulture); } }
|
||||
public static string ColorPicker_HueAriaLabel { get { return ResourceManager.GetString("ColorPicker_HueAriaLabel", resourceCulture); } }
|
||||
public static string ColorPicker_AlphaAriaLabel { get { return ResourceManager.GetString("ColorPicker_AlphaAriaLabel", resourceCulture); } }
|
||||
public static string ColorPicker_SaturationAriaLabel { get { return ResourceManager.GetString("ColorPicker_SaturationAriaLabel", resourceCulture); } }
|
||||
public static string ColorPicker_SaturationValueTextFormat { get { return ResourceManager.GetString("ColorPicker_SaturationValueTextFormat", resourceCulture); } }
|
||||
public static string DataAnnotationValidator_MessageSeparator { get { return ResourceManager.GetString("DataAnnotationValidator_MessageSeparator", resourceCulture); } }
|
||||
public static string DataFilter_FilterText { get { return ResourceManager.GetString("DataFilter_FilterText", resourceCulture); } }
|
||||
public static string DataFilter_EnumFilterSelectText { get { return ResourceManager.GetString("DataFilter_EnumFilterSelectText", resourceCulture); } }
|
||||
@@ -341,6 +349,9 @@ namespace Radzen.Blazor {
|
||||
public static string DataFilter_IsEmptyText { get { return ResourceManager.GetString("DataFilter_IsEmptyText", resourceCulture); } }
|
||||
public static string DataFilter_IsNotEmptyText { get { return ResourceManager.GetString("DataFilter_IsNotEmptyText", resourceCulture); } }
|
||||
public static string DataFilter_CustomText { get { return ResourceManager.GetString("DataFilter_CustomText", resourceCulture); } }
|
||||
public static string DataFilter_PropertyAriaLabel { get { return ResourceManager.GetString("DataFilter_PropertyAriaLabel", resourceCulture); } }
|
||||
public static string DataFilter_FilterOperatorAriaLabel { get { return ResourceManager.GetString("DataFilter_FilterOperatorAriaLabel", resourceCulture); } }
|
||||
public static string DataFilter_FilterValueAriaLabel { get { return ResourceManager.GetString("DataFilter_FilterValueAriaLabel", resourceCulture); } }
|
||||
public static string DataGrid_FilterText { get { return ResourceManager.GetString("DataGrid_FilterText", resourceCulture); } }
|
||||
public static string DataGrid_EnumFilterSelectText { get { return ResourceManager.GetString("DataGrid_EnumFilterSelectText", resourceCulture); } }
|
||||
public static string DataGrid_EnumNullFilterText { get { return ResourceManager.GetString("DataGrid_EnumNullFilterText", resourceCulture); } }
|
||||
@@ -519,6 +530,8 @@ namespace Radzen.Blazor {
|
||||
public static string PickList_SelectedSourceToTargetTitle { get { return ResourceManager.GetString("PickList_SelectedSourceToTargetTitle", resourceCulture); } }
|
||||
public static string PickList_TargetToSourceTitle { get { return ResourceManager.GetString("PickList_TargetToSourceTitle", resourceCulture); } }
|
||||
public static string PickList_SelectedTargetToSourceTitle { get { return ResourceManager.GetString("PickList_SelectedTargetToSourceTitle", resourceCulture); } }
|
||||
public static string PickList_SourceAriaLabel { get { return ResourceManager.GetString("PickList_SourceAriaLabel", resourceCulture); } }
|
||||
public static string PickList_TargetAriaLabel { get { return ResourceManager.GetString("PickList_TargetAriaLabel", resourceCulture); } }
|
||||
public static string PivotDataGrid_EmptyText { get { return ResourceManager.GetString("PivotDataGrid_EmptyText", resourceCulture); } }
|
||||
public static string PivotDataGrid_FieldsPickerHeaderText { get { return ResourceManager.GetString("PivotDataGrid_FieldsPickerHeaderText", resourceCulture); } }
|
||||
public static string PivotDataGrid_RowsText { get { return ResourceManager.GetString("PivotDataGrid_RowsText", resourceCulture); } }
|
||||
@@ -555,6 +568,7 @@ namespace Radzen.Blazor {
|
||||
public static string PivotDataGrid_CustomText { get { return ResourceManager.GetString("PivotDataGrid_CustomText", resourceCulture); } }
|
||||
public static string ProfileMenu_ToggleAriaLabel { get { return ResourceManager.GetString("ProfileMenu_ToggleAriaLabel", resourceCulture); } }
|
||||
public static string ProfileMenuItem_ImageAlternateText { get { return ResourceManager.GetString("ProfileMenuItem_ImageAlternateText", resourceCulture); } }
|
||||
public static string Rating_AriaLabel { get { return ResourceManager.GetString("Rating_AriaLabel", resourceCulture); } }
|
||||
public static string Rating_ClearAriaLabel { get { return ResourceManager.GetString("Rating_ClearAriaLabel", resourceCulture); } }
|
||||
public static string Rating_RateAriaLabel { get { return ResourceManager.GetString("Rating_RateAriaLabel", resourceCulture); } }
|
||||
public static string SankeyDiagram_ValueText { get { return ResourceManager.GetString("SankeyDiagram_ValueText", resourceCulture); } }
|
||||
@@ -564,6 +578,8 @@ namespace Radzen.Blazor {
|
||||
public static string Scheduler_TodayText { get { return ResourceManager.GetString("Scheduler_TodayText", resourceCulture); } }
|
||||
public static string Scheduler_NextText { get { return ResourceManager.GetString("Scheduler_NextText", resourceCulture); } }
|
||||
public static string Scheduler_PrevText { get { return ResourceManager.GetString("Scheduler_PrevText", resourceCulture); } }
|
||||
public static string SecurityCode_AriaLabel { get { return ResourceManager.GetString("SecurityCode_AriaLabel", resourceCulture); } }
|
||||
public static string SecurityCode_InputAriaLabelFormat { get { return ResourceManager.GetString("SecurityCode_InputAriaLabelFormat", resourceCulture); } }
|
||||
public static string SidebarToggle_ToggleAriaLabel { get { return ResourceManager.GetString("SidebarToggle_ToggleAriaLabel", resourceCulture); } }
|
||||
public static string SignaturePad_ClearAriaLabel { get { return ResourceManager.GetString("SignaturePad_ClearAriaLabel", resourceCulture); } }
|
||||
public static string SpeechToTextButton_Title { get { return ResourceManager.GetString("SpeechToTextButton_Title", resourceCulture); } }
|
||||
|
||||
@@ -795,6 +795,10 @@
|
||||
<data name="AIChat_AssistantAvatarText" xml:space="preserve">
|
||||
<value>KI</value>
|
||||
</data>
|
||||
<!-- Alert -->
|
||||
<data name="Alert_CloseAriaLabel" xml:space="preserve">
|
||||
<value>Schließen</value>
|
||||
</data>
|
||||
<!-- Button -->
|
||||
<data name="Button_ImageAlternateText" xml:space="preserve">
|
||||
<value>Schaltfläche</value>
|
||||
@@ -803,6 +807,15 @@
|
||||
<data name="Carousel_PagerButtonAriaLabelFormat" xml:space="preserve">
|
||||
<value>Zu Folie {0} wechseln</value>
|
||||
</data>
|
||||
<data name="Carousel_PrevAriaLabel" xml:space="preserve">
|
||||
<value>Zurück</value>
|
||||
</data>
|
||||
<data name="Carousel_NextAriaLabel" xml:space="preserve">
|
||||
<value>Weiter</value>
|
||||
</data>
|
||||
<data name="Carousel_SlideAriaLabelFormat" xml:space="preserve">
|
||||
<value>{0} von {1}</value>
|
||||
</data>
|
||||
<!-- Chat -->
|
||||
<data name="Chat_Placeholder" xml:space="preserve">
|
||||
<value>Geben Sie Ihre Nachricht ein...</value>
|
||||
@@ -846,6 +859,18 @@
|
||||
<data name="ColorPicker_ButtonText" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="ColorPicker_HueAriaLabel" xml:space="preserve">
|
||||
<value>Farbton</value>
|
||||
</data>
|
||||
<data name="ColorPicker_AlphaAriaLabel" xml:space="preserve">
|
||||
<value>Alpha</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationAriaLabel" xml:space="preserve">
|
||||
<value>Sättigung und Helligkeit</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationValueTextFormat" xml:space="preserve">
|
||||
<value>Sättigung {0} % Helligkeit {1} %</value>
|
||||
</data>
|
||||
<!-- DataAnnotationValidator -->
|
||||
<data name="DataAnnotationValidator_MessageSeparator" xml:space="preserve">
|
||||
<value> und </value>
|
||||
@@ -929,6 +954,15 @@
|
||||
<data name="DataFilter_CustomText" xml:space="preserve">
|
||||
<value>Benutzerdefiniert</value>
|
||||
</data>
|
||||
<data name="DataFilter_PropertyAriaLabel" xml:space="preserve">
|
||||
<value>Filtereigenschaft</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterOperatorAriaLabel" xml:space="preserve">
|
||||
<value>Filteroperator</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterValueAriaLabel" xml:space="preserve">
|
||||
<value>Filterwert</value>
|
||||
</data>
|
||||
<!-- DataGrid -->
|
||||
<data name="DataGrid_FilterText" xml:space="preserve">
|
||||
<value>Filter</value>
|
||||
@@ -1508,6 +1542,12 @@
|
||||
<data name="PickList_SelectedTargetToSourceTitle" xml:space="preserve">
|
||||
<value>Ausgewählte Zielelemente in die Quellsammlung verschieben</value>
|
||||
</data>
|
||||
<data name="PickList_SourceAriaLabel" xml:space="preserve">
|
||||
<value>Quellelemente</value>
|
||||
</data>
|
||||
<data name="PickList_TargetAriaLabel" xml:space="preserve">
|
||||
<value>Zielelemente</value>
|
||||
</data>
|
||||
<!-- PivotDataGrid -->
|
||||
<data name="PivotDataGrid_EmptyText" xml:space="preserve">
|
||||
<value>Keine Datensätze zum Anzeigen.</value>
|
||||
@@ -1620,6 +1660,9 @@
|
||||
<value>Bild</value>
|
||||
</data>
|
||||
<!-- Rating -->
|
||||
<data name="Rating_AriaLabel" xml:space="preserve">
|
||||
<value>Bewertung</value>
|
||||
</data>
|
||||
<data name="Rating_ClearAriaLabel" xml:space="preserve">
|
||||
<value>Löschen</value>
|
||||
</data>
|
||||
@@ -1649,6 +1692,13 @@
|
||||
<data name="Scheduler_PrevText" xml:space="preserve">
|
||||
<value>Zurück</value>
|
||||
</data>
|
||||
<!-- SecurityCode -->
|
||||
<data name="SecurityCode_AriaLabel" xml:space="preserve">
|
||||
<value>Sicherheitscode</value>
|
||||
</data>
|
||||
<data name="SecurityCode_InputAriaLabelFormat" xml:space="preserve">
|
||||
<value>Zeichen {0} von {1}</value>
|
||||
</data>
|
||||
<!-- SidebarToggle -->
|
||||
<data name="SidebarToggle_ToggleAriaLabel" xml:space="preserve">
|
||||
<value>Umschalten</value>
|
||||
|
||||
@@ -795,6 +795,10 @@
|
||||
<data name="AIChat_AssistantAvatarText" xml:space="preserve">
|
||||
<value>IA</value>
|
||||
</data>
|
||||
<!-- Alert -->
|
||||
<data name="Alert_CloseAriaLabel" xml:space="preserve">
|
||||
<value>Cerrar</value>
|
||||
</data>
|
||||
<!-- Button -->
|
||||
<data name="Button_ImageAlternateText" xml:space="preserve">
|
||||
<value>botón</value>
|
||||
@@ -803,6 +807,15 @@
|
||||
<data name="Carousel_PagerButtonAriaLabelFormat" xml:space="preserve">
|
||||
<value>Ir a la diapositiva {0}</value>
|
||||
</data>
|
||||
<data name="Carousel_PrevAriaLabel" xml:space="preserve">
|
||||
<value>Anterior</value>
|
||||
</data>
|
||||
<data name="Carousel_NextAriaLabel" xml:space="preserve">
|
||||
<value>Siguiente</value>
|
||||
</data>
|
||||
<data name="Carousel_SlideAriaLabelFormat" xml:space="preserve">
|
||||
<value>{0} de {1}</value>
|
||||
</data>
|
||||
<!-- Chat -->
|
||||
<data name="Chat_Placeholder" xml:space="preserve">
|
||||
<value>Escriba su mensaje...</value>
|
||||
@@ -846,6 +859,18 @@
|
||||
<data name="ColorPicker_ButtonText" xml:space="preserve">
|
||||
<value>Aceptar</value>
|
||||
</data>
|
||||
<data name="ColorPicker_HueAriaLabel" xml:space="preserve">
|
||||
<value>Tono</value>
|
||||
</data>
|
||||
<data name="ColorPicker_AlphaAriaLabel" xml:space="preserve">
|
||||
<value>Alfa</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationAriaLabel" xml:space="preserve">
|
||||
<value>Saturación y brillo</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationValueTextFormat" xml:space="preserve">
|
||||
<value>Saturación {0}% Brillo {1}%</value>
|
||||
</data>
|
||||
<!-- DataAnnotationValidator -->
|
||||
<data name="DataAnnotationValidator_MessageSeparator" xml:space="preserve">
|
||||
<value> y </value>
|
||||
@@ -929,6 +954,15 @@
|
||||
<data name="DataFilter_CustomText" xml:space="preserve">
|
||||
<value>Personalizado</value>
|
||||
</data>
|
||||
<data name="DataFilter_PropertyAriaLabel" xml:space="preserve">
|
||||
<value>Propiedad del filtro</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterOperatorAriaLabel" xml:space="preserve">
|
||||
<value>Operador de filtro</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterValueAriaLabel" xml:space="preserve">
|
||||
<value>Valor de filtro</value>
|
||||
</data>
|
||||
<!-- DataGrid -->
|
||||
<data name="DataGrid_FilterText" xml:space="preserve">
|
||||
<value>Filtrar</value>
|
||||
@@ -1508,6 +1542,12 @@
|
||||
<data name="PickList_SelectedTargetToSourceTitle" xml:space="preserve">
|
||||
<value>Mover los elementos de destino seleccionados a la colección de origen</value>
|
||||
</data>
|
||||
<data name="PickList_SourceAriaLabel" xml:space="preserve">
|
||||
<value>Elementos de origen</value>
|
||||
</data>
|
||||
<data name="PickList_TargetAriaLabel" xml:space="preserve">
|
||||
<value>Elementos de destino</value>
|
||||
</data>
|
||||
<!-- PivotDataGrid -->
|
||||
<data name="PivotDataGrid_EmptyText" xml:space="preserve">
|
||||
<value>No hay registros para mostrar.</value>
|
||||
@@ -1620,6 +1660,9 @@
|
||||
<value>imagen</value>
|
||||
</data>
|
||||
<!-- Rating -->
|
||||
<data name="Rating_AriaLabel" xml:space="preserve">
|
||||
<value>Calificación</value>
|
||||
</data>
|
||||
<data name="Rating_ClearAriaLabel" xml:space="preserve">
|
||||
<value>Borrar</value>
|
||||
</data>
|
||||
@@ -1649,6 +1692,13 @@
|
||||
<data name="Scheduler_PrevText" xml:space="preserve">
|
||||
<value>Anterior</value>
|
||||
</data>
|
||||
<!-- SecurityCode -->
|
||||
<data name="SecurityCode_AriaLabel" xml:space="preserve">
|
||||
<value>Código de seguridad</value>
|
||||
</data>
|
||||
<data name="SecurityCode_InputAriaLabelFormat" xml:space="preserve">
|
||||
<value>Carácter {0} de {1}</value>
|
||||
</data>
|
||||
<!-- SidebarToggle -->
|
||||
<data name="SidebarToggle_ToggleAriaLabel" xml:space="preserve">
|
||||
<value>Alternar</value>
|
||||
|
||||
@@ -795,6 +795,10 @@
|
||||
<data name="AIChat_AssistantAvatarText" xml:space="preserve">
|
||||
<value>IA</value>
|
||||
</data>
|
||||
<!-- Alert -->
|
||||
<data name="Alert_CloseAriaLabel" xml:space="preserve">
|
||||
<value>Fermer</value>
|
||||
</data>
|
||||
<!-- Button -->
|
||||
<data name="Button_ImageAlternateText" xml:space="preserve">
|
||||
<value>bouton</value>
|
||||
@@ -803,6 +807,15 @@
|
||||
<data name="Carousel_PagerButtonAriaLabelFormat" xml:space="preserve">
|
||||
<value>Aller à la diapositive {0}</value>
|
||||
</data>
|
||||
<data name="Carousel_PrevAriaLabel" xml:space="preserve">
|
||||
<value>Précédent</value>
|
||||
</data>
|
||||
<data name="Carousel_NextAriaLabel" xml:space="preserve">
|
||||
<value>Suivant</value>
|
||||
</data>
|
||||
<data name="Carousel_SlideAriaLabelFormat" xml:space="preserve">
|
||||
<value>{0} sur {1}</value>
|
||||
</data>
|
||||
<!-- Chat -->
|
||||
<data name="Chat_Placeholder" xml:space="preserve">
|
||||
<value>Saisissez votre message...</value>
|
||||
@@ -846,6 +859,18 @@
|
||||
<data name="ColorPicker_ButtonText" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="ColorPicker_HueAriaLabel" xml:space="preserve">
|
||||
<value>Teinte</value>
|
||||
</data>
|
||||
<data name="ColorPicker_AlphaAriaLabel" xml:space="preserve">
|
||||
<value>Alpha</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationAriaLabel" xml:space="preserve">
|
||||
<value>Saturation et luminosité</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationValueTextFormat" xml:space="preserve">
|
||||
<value>Saturation {0} % Luminosité {1} %</value>
|
||||
</data>
|
||||
<!-- DataAnnotationValidator -->
|
||||
<data name="DataAnnotationValidator_MessageSeparator" xml:space="preserve">
|
||||
<value> et </value>
|
||||
@@ -929,6 +954,15 @@
|
||||
<data name="DataFilter_CustomText" xml:space="preserve">
|
||||
<value>Personnalisé</value>
|
||||
</data>
|
||||
<data name="DataFilter_PropertyAriaLabel" xml:space="preserve">
|
||||
<value>Propriété du filtre</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterOperatorAriaLabel" xml:space="preserve">
|
||||
<value>Opérateur de filtre</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterValueAriaLabel" xml:space="preserve">
|
||||
<value>Valeur du filtre</value>
|
||||
</data>
|
||||
<!-- DataGrid -->
|
||||
<data name="DataGrid_FilterText" xml:space="preserve">
|
||||
<value>Filtrer</value>
|
||||
@@ -1508,6 +1542,12 @@
|
||||
<data name="PickList_SelectedTargetToSourceTitle" xml:space="preserve">
|
||||
<value>Déplacer les éléments cibles sélectionnés vers la collection source</value>
|
||||
</data>
|
||||
<data name="PickList_SourceAriaLabel" xml:space="preserve">
|
||||
<value>Éléments source</value>
|
||||
</data>
|
||||
<data name="PickList_TargetAriaLabel" xml:space="preserve">
|
||||
<value>Éléments cibles</value>
|
||||
</data>
|
||||
<!-- PivotDataGrid -->
|
||||
<data name="PivotDataGrid_EmptyText" xml:space="preserve">
|
||||
<value>Aucun enregistrement à afficher.</value>
|
||||
@@ -1620,6 +1660,9 @@
|
||||
<value>image</value>
|
||||
</data>
|
||||
<!-- Rating -->
|
||||
<data name="Rating_AriaLabel" xml:space="preserve">
|
||||
<value>Évaluation</value>
|
||||
</data>
|
||||
<data name="Rating_ClearAriaLabel" xml:space="preserve">
|
||||
<value>Effacer</value>
|
||||
</data>
|
||||
@@ -1649,6 +1692,13 @@
|
||||
<data name="Scheduler_PrevText" xml:space="preserve">
|
||||
<value>Précédent</value>
|
||||
</data>
|
||||
<!-- SecurityCode -->
|
||||
<data name="SecurityCode_AriaLabel" xml:space="preserve">
|
||||
<value>Code de sécurité</value>
|
||||
</data>
|
||||
<data name="SecurityCode_InputAriaLabelFormat" xml:space="preserve">
|
||||
<value>Caractère {0} sur {1}</value>
|
||||
</data>
|
||||
<!-- SidebarToggle -->
|
||||
<data name="SidebarToggle_ToggleAriaLabel" xml:space="preserve">
|
||||
<value>Basculer</value>
|
||||
|
||||
@@ -795,6 +795,10 @@
|
||||
<data name="AIChat_AssistantAvatarText" xml:space="preserve">
|
||||
<value>AI</value>
|
||||
</data>
|
||||
<!-- Alert -->
|
||||
<data name="Alert_CloseAriaLabel" xml:space="preserve">
|
||||
<value>Chiudi</value>
|
||||
</data>
|
||||
<!-- Button -->
|
||||
<data name="Button_ImageAlternateText" xml:space="preserve">
|
||||
<value>pulsante</value>
|
||||
@@ -803,6 +807,15 @@
|
||||
<data name="Carousel_PagerButtonAriaLabelFormat" xml:space="preserve">
|
||||
<value>Vai alla diapositiva {0}</value>
|
||||
</data>
|
||||
<data name="Carousel_PrevAriaLabel" xml:space="preserve">
|
||||
<value>Precedente</value>
|
||||
</data>
|
||||
<data name="Carousel_NextAriaLabel" xml:space="preserve">
|
||||
<value>Successivo</value>
|
||||
</data>
|
||||
<data name="Carousel_SlideAriaLabelFormat" xml:space="preserve">
|
||||
<value>{0} di {1}</value>
|
||||
</data>
|
||||
<!-- Chat -->
|
||||
<data name="Chat_Placeholder" xml:space="preserve">
|
||||
<value>Scrivi il tuo messaggio...</value>
|
||||
@@ -846,6 +859,18 @@
|
||||
<data name="ColorPicker_ButtonText" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="ColorPicker_HueAriaLabel" xml:space="preserve">
|
||||
<value>Tonalità</value>
|
||||
</data>
|
||||
<data name="ColorPicker_AlphaAriaLabel" xml:space="preserve">
|
||||
<value>Alfa</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationAriaLabel" xml:space="preserve">
|
||||
<value>Saturazione e luminosità</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationValueTextFormat" xml:space="preserve">
|
||||
<value>Saturazione {0}% Luminosità {1}%</value>
|
||||
</data>
|
||||
<!-- DataAnnotationValidator -->
|
||||
<data name="DataAnnotationValidator_MessageSeparator" xml:space="preserve">
|
||||
<value> e </value>
|
||||
@@ -929,6 +954,15 @@
|
||||
<data name="DataFilter_CustomText" xml:space="preserve">
|
||||
<value>Personalizzato</value>
|
||||
</data>
|
||||
<data name="DataFilter_PropertyAriaLabel" xml:space="preserve">
|
||||
<value>Proprietà del filtro</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterOperatorAriaLabel" xml:space="preserve">
|
||||
<value>Operatore del filtro</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterValueAriaLabel" xml:space="preserve">
|
||||
<value>Valore del filtro</value>
|
||||
</data>
|
||||
<!-- DataGrid -->
|
||||
<data name="DataGrid_FilterText" xml:space="preserve">
|
||||
<value>Filtra</value>
|
||||
@@ -1508,6 +1542,12 @@
|
||||
<data name="PickList_SelectedTargetToSourceTitle" xml:space="preserve">
|
||||
<value>Sposta gli elementi di destinazione selezionati nella raccolta di origine</value>
|
||||
</data>
|
||||
<data name="PickList_SourceAriaLabel" xml:space="preserve">
|
||||
<value>Elementi di origine</value>
|
||||
</data>
|
||||
<data name="PickList_TargetAriaLabel" xml:space="preserve">
|
||||
<value>Elementi di destinazione</value>
|
||||
</data>
|
||||
<!-- PivotDataGrid -->
|
||||
<data name="PivotDataGrid_EmptyText" xml:space="preserve">
|
||||
<value>Nessun record da visualizzare.</value>
|
||||
@@ -1620,6 +1660,9 @@
|
||||
<value>immagine</value>
|
||||
</data>
|
||||
<!-- Rating -->
|
||||
<data name="Rating_AriaLabel" xml:space="preserve">
|
||||
<value>Valutazione</value>
|
||||
</data>
|
||||
<data name="Rating_ClearAriaLabel" xml:space="preserve">
|
||||
<value>Cancella</value>
|
||||
</data>
|
||||
@@ -1649,6 +1692,13 @@
|
||||
<data name="Scheduler_PrevText" xml:space="preserve">
|
||||
<value>Precedente</value>
|
||||
</data>
|
||||
<!-- SecurityCode -->
|
||||
<data name="SecurityCode_AriaLabel" xml:space="preserve">
|
||||
<value>Codice di sicurezza</value>
|
||||
</data>
|
||||
<data name="SecurityCode_InputAriaLabelFormat" xml:space="preserve">
|
||||
<value>Carattere {0} di {1}</value>
|
||||
</data>
|
||||
<!-- SidebarToggle -->
|
||||
<data name="SidebarToggle_ToggleAriaLabel" xml:space="preserve">
|
||||
<value>Attiva/disattiva</value>
|
||||
|
||||
@@ -795,6 +795,10 @@
|
||||
<data name="AIChat_AssistantAvatarText" xml:space="preserve">
|
||||
<value>AI</value>
|
||||
</data>
|
||||
<!-- Alert -->
|
||||
<data name="Alert_CloseAriaLabel" xml:space="preserve">
|
||||
<value>閉じる</value>
|
||||
</data>
|
||||
<!-- Button -->
|
||||
<data name="Button_ImageAlternateText" xml:space="preserve">
|
||||
<value>ボタン</value>
|
||||
@@ -803,6 +807,15 @@
|
||||
<data name="Carousel_PagerButtonAriaLabelFormat" xml:space="preserve">
|
||||
<value>スライド {0} へ移動</value>
|
||||
</data>
|
||||
<data name="Carousel_PrevAriaLabel" xml:space="preserve">
|
||||
<value>前へ</value>
|
||||
</data>
|
||||
<data name="Carousel_NextAriaLabel" xml:space="preserve">
|
||||
<value>次へ</value>
|
||||
</data>
|
||||
<data name="Carousel_SlideAriaLabelFormat" xml:space="preserve">
|
||||
<value>{0} / {1}</value>
|
||||
</data>
|
||||
<!-- Chat -->
|
||||
<data name="Chat_Placeholder" xml:space="preserve">
|
||||
<value>メッセージを入力...</value>
|
||||
@@ -846,6 +859,18 @@
|
||||
<data name="ColorPicker_ButtonText" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="ColorPicker_HueAriaLabel" xml:space="preserve">
|
||||
<value>色相</value>
|
||||
</data>
|
||||
<data name="ColorPicker_AlphaAriaLabel" xml:space="preserve">
|
||||
<value>アルファ</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationAriaLabel" xml:space="preserve">
|
||||
<value>彩度と明度</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationValueTextFormat" xml:space="preserve">
|
||||
<value>彩度 {0}% 明度 {1}%</value>
|
||||
</data>
|
||||
<!-- DataAnnotationValidator -->
|
||||
<data name="DataAnnotationValidator_MessageSeparator" xml:space="preserve">
|
||||
<value> および </value>
|
||||
@@ -929,6 +954,15 @@
|
||||
<data name="DataFilter_CustomText" xml:space="preserve">
|
||||
<value>カスタム</value>
|
||||
</data>
|
||||
<data name="DataFilter_PropertyAriaLabel" xml:space="preserve">
|
||||
<value>フィルタープロパティ</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterOperatorAriaLabel" xml:space="preserve">
|
||||
<value>フィルター演算子</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterValueAriaLabel" xml:space="preserve">
|
||||
<value>フィルター値</value>
|
||||
</data>
|
||||
<!-- DataGrid -->
|
||||
<data name="DataGrid_FilterText" xml:space="preserve">
|
||||
<value>フィルター</value>
|
||||
@@ -1508,6 +1542,12 @@
|
||||
<data name="PickList_SelectedTargetToSourceTitle" xml:space="preserve">
|
||||
<value>選択した対象の項目を元のコレクションへ移動</value>
|
||||
</data>
|
||||
<data name="PickList_SourceAriaLabel" xml:space="preserve">
|
||||
<value>元の項目</value>
|
||||
</data>
|
||||
<data name="PickList_TargetAriaLabel" xml:space="preserve">
|
||||
<value>対象の項目</value>
|
||||
</data>
|
||||
<!-- PivotDataGrid -->
|
||||
<data name="PivotDataGrid_EmptyText" xml:space="preserve">
|
||||
<value>表示するレコードがありません。</value>
|
||||
@@ -1620,6 +1660,9 @@
|
||||
<value>画像</value>
|
||||
</data>
|
||||
<!-- Rating -->
|
||||
<data name="Rating_AriaLabel" xml:space="preserve">
|
||||
<value>評価</value>
|
||||
</data>
|
||||
<data name="Rating_ClearAriaLabel" xml:space="preserve">
|
||||
<value>クリア</value>
|
||||
</data>
|
||||
@@ -1649,6 +1692,13 @@
|
||||
<data name="Scheduler_PrevText" xml:space="preserve">
|
||||
<value>前へ</value>
|
||||
</data>
|
||||
<!-- SecurityCode -->
|
||||
<data name="SecurityCode_AriaLabel" xml:space="preserve">
|
||||
<value>セキュリティコード</value>
|
||||
</data>
|
||||
<data name="SecurityCode_InputAriaLabelFormat" xml:space="preserve">
|
||||
<value>{1}文字中{0}文字目</value>
|
||||
</data>
|
||||
<!-- SidebarToggle -->
|
||||
<data name="SidebarToggle_ToggleAriaLabel" xml:space="preserve">
|
||||
<value>切り替え</value>
|
||||
|
||||
@@ -795,6 +795,10 @@
|
||||
<data name="AIChat_AssistantAvatarText" xml:space="preserve">
|
||||
<value>AI</value>
|
||||
</data>
|
||||
<!-- Alert -->
|
||||
<data name="Alert_CloseAriaLabel" xml:space="preserve">
|
||||
<value>Close</value>
|
||||
</data>
|
||||
<!-- Button -->
|
||||
<data name="Button_ImageAlternateText" xml:space="preserve">
|
||||
<value>button</value>
|
||||
@@ -803,6 +807,15 @@
|
||||
<data name="Carousel_PagerButtonAriaLabelFormat" xml:space="preserve">
|
||||
<value>Go to slide {0}</value>
|
||||
</data>
|
||||
<data name="Carousel_PrevAriaLabel" xml:space="preserve">
|
||||
<value>Previous</value>
|
||||
</data>
|
||||
<data name="Carousel_NextAriaLabel" xml:space="preserve">
|
||||
<value>Next</value>
|
||||
</data>
|
||||
<data name="Carousel_SlideAriaLabelFormat" xml:space="preserve">
|
||||
<value>{0} of {1}</value>
|
||||
</data>
|
||||
<!-- Chat -->
|
||||
<data name="Chat_Placeholder" xml:space="preserve">
|
||||
<value>Type your message...</value>
|
||||
@@ -846,6 +859,18 @@
|
||||
<data name="ColorPicker_ButtonText" xml:space="preserve">
|
||||
<value>OK</value>
|
||||
</data>
|
||||
<data name="ColorPicker_HueAriaLabel" xml:space="preserve">
|
||||
<value>Hue</value>
|
||||
</data>
|
||||
<data name="ColorPicker_AlphaAriaLabel" xml:space="preserve">
|
||||
<value>Alpha</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationAriaLabel" xml:space="preserve">
|
||||
<value>Saturation and brightness</value>
|
||||
</data>
|
||||
<data name="ColorPicker_SaturationValueTextFormat" xml:space="preserve">
|
||||
<value>Saturation {0}% Brightness {1}%</value>
|
||||
</data>
|
||||
<!-- DataAnnotationValidator -->
|
||||
<data name="DataAnnotationValidator_MessageSeparator" xml:space="preserve">
|
||||
<value> and </value>
|
||||
@@ -929,6 +954,15 @@
|
||||
<data name="DataFilter_CustomText" xml:space="preserve">
|
||||
<value>Custom</value>
|
||||
</data>
|
||||
<data name="DataFilter_PropertyAriaLabel" xml:space="preserve">
|
||||
<value>Filter property</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterOperatorAriaLabel" xml:space="preserve">
|
||||
<value>Filter operator</value>
|
||||
</data>
|
||||
<data name="DataFilter_FilterValueAriaLabel" xml:space="preserve">
|
||||
<value>Filter value</value>
|
||||
</data>
|
||||
<!-- DataGrid -->
|
||||
<data name="DataGrid_FilterText" xml:space="preserve">
|
||||
<value>Filter</value>
|
||||
@@ -1508,6 +1542,12 @@
|
||||
<data name="PickList_SelectedTargetToSourceTitle" xml:space="preserve">
|
||||
<value>Move selected target items to source collection</value>
|
||||
</data>
|
||||
<data name="PickList_SourceAriaLabel" xml:space="preserve">
|
||||
<value>Source items</value>
|
||||
</data>
|
||||
<data name="PickList_TargetAriaLabel" xml:space="preserve">
|
||||
<value>Target items</value>
|
||||
</data>
|
||||
<!-- PivotDataGrid -->
|
||||
<data name="PivotDataGrid_EmptyText" xml:space="preserve">
|
||||
<value>No records to display.</value>
|
||||
@@ -1620,6 +1660,9 @@
|
||||
<value>image</value>
|
||||
</data>
|
||||
<!-- Rating -->
|
||||
<data name="Rating_AriaLabel" xml:space="preserve">
|
||||
<value>Rating</value>
|
||||
</data>
|
||||
<data name="Rating_ClearAriaLabel" xml:space="preserve">
|
||||
<value>Clear</value>
|
||||
</data>
|
||||
@@ -1649,6 +1692,13 @@
|
||||
<data name="Scheduler_PrevText" xml:space="preserve">
|
||||
<value>Previous</value>
|
||||
</data>
|
||||
<!-- SecurityCode -->
|
||||
<data name="SecurityCode_AriaLabel" xml:space="preserve">
|
||||
<value>Security code</value>
|
||||
</data>
|
||||
<data name="SecurityCode_InputAriaLabelFormat" xml:space="preserve">
|
||||
<value>Character {0} of {1}</value>
|
||||
</data>
|
||||
<!-- SidebarToggle -->
|
||||
<data name="SidebarToggle_ToggleAriaLabel" xml:space="preserve">
|
||||
<value>Toggle</value>
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
<CascadingValue Value=this>
|
||||
@if (Visible)
|
||||
{
|
||||
<div @ref=@Element style=@Style @attributes=@Attributes class=@GetCssClass() id=@GetId()
|
||||
role="tablist"
|
||||
aria-orientation="@(IsVertical ? "vertical" : "horizontal")"
|
||||
aria-label="@AriaLabel"
|
||||
aria-labelledby="@AriaLabelledBy"
|
||||
aria-activedescendant="@GetActiveDescendantId()"
|
||||
tabindex=0 @onkeydown="@(args => OnKeyPress(args))" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeydownPropagation">
|
||||
<ul role="presentation" class="rz-tabview-nav">
|
||||
<div @ref=@Element style=@Style @attributes=@Attributes class=@GetCssClass() id=@GetId()>
|
||||
<ul @ref=@tablistElement class="rz-tabview-nav"
|
||||
role="tablist"
|
||||
aria-orientation="@(IsVertical ? "vertical" : "horizontal")"
|
||||
aria-label="@AriaLabel"
|
||||
aria-labelledby="@AriaLabelledBy"
|
||||
aria-activedescendant="@GetActiveDescendantId()"
|
||||
tabindex=0 @onkeydown="@(args => OnKeyPress(args))" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeydownPropagation">
|
||||
@Tabs
|
||||
</ul>
|
||||
<div class="rz-tabview-panels">
|
||||
|
||||
@@ -129,6 +129,8 @@ namespace Radzen.Blazor
|
||||
[Parameter]
|
||||
public string? AriaLabelledBy { get; set; }
|
||||
|
||||
internal ElementReference tablistElement;
|
||||
|
||||
List<RadzenTabsItem> tabs = new List<RadzenTabsItem>();
|
||||
|
||||
internal List<RadzenTabsItem> NavigableTabs()
|
||||
@@ -255,7 +257,7 @@ namespace Radzen.Blazor
|
||||
|
||||
try
|
||||
{
|
||||
await Element.FocusAsync(preventScroll: true);
|
||||
await tablistElement.FocusAsync(preventScroll: true);
|
||||
}
|
||||
catch (JSDisconnectedException)
|
||||
{
|
||||
@@ -409,7 +411,7 @@ namespace Radzen.Blazor
|
||||
|
||||
try
|
||||
{
|
||||
await Element.FocusAsync(preventScroll: true);
|
||||
await tablistElement.FocusAsync(preventScroll: true);
|
||||
}
|
||||
catch (JSDisconnectedException)
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
{
|
||||
@if (!string.IsNullOrEmpty(GetIcon()))
|
||||
{
|
||||
<i class="notranslate rz-button-icon-left rzi" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@GetIcon()</i>
|
||||
<i class="notranslate rz-button-icon-left rzi" aria-hidden="true" style="@(!string.IsNullOrEmpty(IconColor) ? $"color:{IconColor}" : null)">@GetIcon()</i>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Image))
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
role="tree" aria-multiselectable="@(AllowCheckBoxes ? "true" : null)"
|
||||
aria-label="@AriaLabel" aria-labelledby="@AriaLabelledBy" aria-activedescendant="@ActiveDescendantId"
|
||||
tabindex="0" @onkeydown="@OnKeyPress" @onkeydown:preventDefault=preventKeyPress @onkeydown:stopPropagation="stopKeydownPropagation">
|
||||
<ul class="rz-tree-container">
|
||||
<ul class="rz-tree-container" role="presentation">
|
||||
<CascadingValue Value=this>
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@using Radzen.Blazor.Rendering
|
||||
@implements IDisposable
|
||||
@{var itemArgs = Tree?.ItemAttributes(this); }
|
||||
<li class="rz-treenode" @attributes="@(itemArgs?.Item1.Attributes.Any() == true ? itemArgs.Item1.Attributes : Attributes)"
|
||||
<li class="rz-treenode" role="presentation" @attributes="@(itemArgs?.Item1.Attributes.Any() == true ? itemArgs.Item1.Attributes : Attributes)"
|
||||
@oncontextmenu="OnContextMenu" @oncontextmenu:preventDefault="@(Tree?.ItemContextMenu.HasDelegate ?? false)" @oncontextmenu:stopPropagation>
|
||||
<div id="@ElementId" class=@ContentClass role="treeitem" tabindex="-1"
|
||||
aria-level="@Level"
|
||||
@@ -14,7 +14,7 @@
|
||||
@onclick="@Select">
|
||||
@if (ChildContent != null || HasChildren)
|
||||
{
|
||||
<span class=@IconClass role="button" tabindex="-1" aria-label="@Text" @onclick="@Toggle" @onclick:stopPropagation></span>
|
||||
<span class=@IconClass aria-hidden="true" @onclick="@Toggle" @onclick:stopPropagation></span>
|
||||
}
|
||||
@if(Tree != null && Tree.AllowCheckBoxes)
|
||||
{
|
||||
@@ -31,7 +31,7 @@
|
||||
@if (ChildContent != null && expanded)
|
||||
{
|
||||
<CascadingValue Value=this>
|
||||
<Expander Expanded=@clientExpanded>
|
||||
<Expander Expanded=@clientExpanded Role="presentation">
|
||||
<ul class="rz-treenode-children" role="group" @onkeydown:stopPropagation="stopKeydownPropagation" @onkeydown="OnGuardKeyDown">
|
||||
@ChildContent
|
||||
</ul>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
ariaAttributes["aria-modal"] = "true";
|
||||
}
|
||||
}
|
||||
<div @ref="dialog" class=@Class role="dialog" style=@Style @attributes="ariaAttributes">
|
||||
<div @ref="dialog" class=@Class role="@(options?.Role ?? "dialog")" style=@Style @attributes="ariaAttributes">
|
||||
@if (showTitle)
|
||||
{
|
||||
<div class="rz-dialog-titlebar">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div role="region" aria-hidden=@Hidden class=@Class @attributes=@Attributes>
|
||||
<div role="@Role" aria-hidden=@Hidden class=@Class @attributes=@Attributes>
|
||||
<div class="rz-expander-content">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@@ -28,6 +28,12 @@ public partial class Expander : ComponentBase
|
||||
[Parameter]
|
||||
public string CssClass { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ARIA role rendered on the expander element.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string Role { get; set; } = "region";
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the content is visible.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,8 +4,17 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.rz-breadcrumb-list {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.rz-breadcrumb-item + .rz-breadcrumb-item::before {
|
||||
content: '»';
|
||||
content: '»' / '';
|
||||
display: inline-block;
|
||||
padding-inline-start: 0.5rem;
|
||||
padding-inline-end: 0.5rem;
|
||||
|
||||
@@ -53,6 +53,10 @@ $listbox-header-icon-margin: 0 !default;
|
||||
.rz-listbox-list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.rz-listbox-item {
|
||||
|
||||
@@ -35,17 +35,15 @@ $pager-button-size: "%button-md" !default;
|
||||
gap: var(--rz-pager-gap);
|
||||
flex-wrap: wrap;
|
||||
|
||||
&:focus {
|
||||
outline: var(--rz-outline-normal);
|
||||
}
|
||||
.rz-pager-element,
|
||||
.rz-pager-page {
|
||||
&:focus {
|
||||
outline: var(--rz-outline-normal);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
.rz-pager-element,
|
||||
.rz-pager-page {
|
||||
&.rz-state-focused {
|
||||
outline: var(--rz-outline-focus);
|
||||
outline-offset: var(--rz-outline-offset);
|
||||
}
|
||||
&:focus-visible {
|
||||
outline: var(--rz-outline-focus);
|
||||
outline-offset: var(--rz-outline-offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ ul.rz-profile-menu {
|
||||
}
|
||||
}
|
||||
|
||||
.rz-navigation-menu:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.rz-navigation-item-icon-children {
|
||||
color: var(--rz-profile-menu-toggle-button-color);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ $selectbar-selected-border: var(--rz-border-primary-lighter) !default;
|
||||
$selectbar-border-radius: var(--rz-border-radius) !default;
|
||||
$selectbar-focus-outline: var(--rz-outline-focus) !default;
|
||||
$selectbar-focus-outline-offset: var(--rz-outline-offset) !default;
|
||||
$selectbar-button-focus-outline: var(--rz-outline-width) solid var(--rz-text-color) !default;
|
||||
$selectbar-button-focus-outline: var(--rz-outline-focus) !default;
|
||||
$selectbar-button-focus-outline-offset: calc(-1 * var(--rz-outline-width)) !default;
|
||||
$selectbar-sizes: xs, sm, md, lg;
|
||||
|
||||
|
||||
@@ -9,15 +9,6 @@ $splitbutton-sizes: xs, sm, md, lg;
|
||||
display: inline-flex;
|
||||
border-radius: var(--rz-button-border-radius);
|
||||
|
||||
&:focus {
|
||||
outline: var(--rz-outline-normal);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--rz-button-focus-outline);
|
||||
outline-offset: var(--rz-button-focus-outline-offset);
|
||||
}
|
||||
|
||||
.rz-button-icon-only {
|
||||
.rz-button-text {
|
||||
display: none;
|
||||
@@ -50,6 +41,10 @@ $splitbutton-sizes: xs, sm, md, lg;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.rz-menuitem {
|
||||
|
||||
@@ -32,26 +32,6 @@ $tabs-transition: var(--rz-transition-all) !default;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
|
||||
&:focus {
|
||||
outline: var(--rz-outline-normal);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--rz-outline-focus);
|
||||
outline-offset: var(--rz-outline-offset);
|
||||
|
||||
.rz-tabview-nav {
|
||||
.rz-state-focused {
|
||||
&:not(.rz-tabview-selected) {
|
||||
&:not(.rz-state-disabled) {
|
||||
outline: var(--rz-tabs-tab-focus-outline);
|
||||
outline-offset: var(--rz-tabs-tab-focus-outline-offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.rz-tabview-top {
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -83,6 +63,24 @@ $tabs-transition: var(--rz-transition-all) !default;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
&:focus {
|
||||
outline: var(--rz-outline-normal);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--rz-outline-focus);
|
||||
outline-offset: var(--rz-outline-offset);
|
||||
|
||||
.rz-state-focused {
|
||||
&:not(.rz-tabview-selected) {
|
||||
&:not(.rz-state-disabled) {
|
||||
outline: var(--rz-tabs-tab-focus-outline);
|
||||
outline-offset: var(--rz-tabs-tab-focus-outline-offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
border: var(--rz-tabs-border);
|
||||
background-color: var(--rz-tabs-tab-background-color);
|
||||
|
||||
@@ -1506,6 +1506,25 @@ window.Radzen = {
|
||||
table.nextSelectedIndex = rows.length - 1;
|
||||
} else if (isVirtual && (key == 'PageUp' || key == 'Home')) {
|
||||
table.nextSelectedIndex = 1;
|
||||
} else if (!isVirtual && (key == 'PageDown' || key == 'PageUp' || key == 'Home' || key == 'End')) {
|
||||
var firstDataIndex = thead && thead.rows && thead.rows.length && cellIndex != null ? thead.rows.length : 1;
|
||||
if (firstDataIndex > rows.length - 1) {
|
||||
firstDataIndex = rows.length - 1;
|
||||
}
|
||||
if (key == 'Home') {
|
||||
table.nextSelectedIndex = firstDataIndex;
|
||||
} else if (key == 'End') {
|
||||
table.nextSelectedIndex = rows.length - 1;
|
||||
} else {
|
||||
var pageFactor = 10;
|
||||
table.nextSelectedIndex = table.nextSelectedIndex + (key == 'PageDown' ? pageFactor : -pageFactor);
|
||||
if (table.nextSelectedIndex > rows.length - 1) {
|
||||
table.nextSelectedIndex = rows.length - 1;
|
||||
}
|
||||
if (table.nextSelectedIndex < firstDataIndex) {
|
||||
table.nextSelectedIndex = firstDataIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isVirtual && (key == 'ArrowDown' || key == 'ArrowUp')) {
|
||||
@@ -1526,20 +1545,10 @@ window.Radzen = {
|
||||
var prev = document.getElementById(activeId);
|
||||
if (prev && prev !== el) {
|
||||
prev.removeAttribute('id');
|
||||
if (prev.hasAttribute('data-rz-active-selected')) {
|
||||
prev.removeAttribute('data-rz-active-selected');
|
||||
if (prev.hasAttribute('aria-selected')) {
|
||||
prev.setAttribute('aria-selected', 'false');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (el && el.id !== activeId) { el.id = activeId; }
|
||||
if (el) {
|
||||
grid.setAttribute('aria-activedescendant', activeId);
|
||||
if (el.tagName === 'TR' && el.hasAttribute('aria-selected')) {
|
||||
el.setAttribute('aria-selected', 'true');
|
||||
el.setAttribute('data-rz-active-selected', '');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1565,7 +1574,7 @@ window.Radzen = {
|
||||
}
|
||||
setActiveDescendant(cell);
|
||||
}
|
||||
} else if (key == 'ArrowDown' || key == 'ArrowUp') {
|
||||
} else if (key == 'ArrowDown' || key == 'ArrowUp' || (!isVirtual && (key == 'PageDown' || key == 'PageUp' || key == 'Home' || key == 'End'))) {
|
||||
var highlighted = table.querySelectorAll('.rz-state-focused');
|
||||
if (highlighted.length) {
|
||||
for (var i = 0; i < highlighted.length; i++) {
|
||||
@@ -2567,7 +2576,25 @@ window.Radzen = {
|
||||
first.focus();
|
||||
}
|
||||
},
|
||||
openSideDialog: function (options) {
|
||||
openSideDialog: function (options, dialogService) {
|
||||
if (dialogService) {
|
||||
Radzen.sideDialogService = dialogService;
|
||||
}
|
||||
if (!Radzen.sideDialogInvokerElement) {
|
||||
var invoker = document.activeElement;
|
||||
if (invoker && invoker !== document.body && !invoker.closest('.rz-dialog-side')) {
|
||||
Radzen.sideDialogInvokerElement = invoker;
|
||||
}
|
||||
}
|
||||
var sideDialog = document.querySelector('.rz-dialog-side');
|
||||
if (sideDialog) {
|
||||
sideDialog.removeEventListener('keydown', Radzen.focusTrap);
|
||||
if (options.showMask) {
|
||||
sideDialog.addEventListener('keydown', Radzen.focusTrap);
|
||||
}
|
||||
sideDialog.removeEventListener('keydown', Radzen.closeSideDialogOnEsc);
|
||||
sideDialog.addEventListener('keydown', Radzen.closeSideDialogOnEsc);
|
||||
}
|
||||
setTimeout(function () {
|
||||
if (options.autoFocusFirstElement) {
|
||||
var dialogs = document.querySelectorAll('.rz-dialog-side-content');
|
||||
@@ -2577,6 +2604,29 @@ window.Radzen = {
|
||||
}
|
||||
}, 500);
|
||||
},
|
||||
closeSideDialog: function () {
|
||||
delete Radzen.sideDialogService;
|
||||
var invoker = Radzen.sideDialogInvokerElement;
|
||||
Radzen.sideDialogInvokerElement = null;
|
||||
if (invoker && typeof invoker.focus === 'function' && document.body.contains(invoker)) {
|
||||
invoker.focus();
|
||||
}
|
||||
},
|
||||
closeSideDialogOnEsc: function (e) {
|
||||
e = e || window.event;
|
||||
var isEscape = "key" in e ? (e.key === "Escape" || e.key === "Esc") : (e.keyCode === 27);
|
||||
if (isEscape && Radzen.sideDialogService) {
|
||||
var popups = document.querySelectorAll('.rz-popup,.rz-overlaypanel');
|
||||
for (var i = 0; i < popups.length; i++) {
|
||||
if (popups[i].style.display != 'none') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
Radzen.sideDialogService.invokeMethodAsync('DialogService.TryCloseSide', null);
|
||||
} catch (ex) { }
|
||||
}
|
||||
},
|
||||
createSideDialogResizer: function(handle, sideDialog, options) {
|
||||
const normalizeDir = (value) => {
|
||||
if (typeof value === 'string' && value.length) {
|
||||
@@ -2666,6 +2716,15 @@ window.Radzen = {
|
||||
document.body.classList.add('no-scroll');
|
||||
}
|
||||
|
||||
var currentDialogs = document.querySelectorAll('.rz-dialog-content');
|
||||
var currentDialog = currentDialogs.length ? currentDialogs[currentDialogs.length - 1] : null;
|
||||
if (currentDialog) {
|
||||
currentDialog.options = options;
|
||||
var dialogRoot = currentDialog.closest('.rz-dialog') || currentDialog;
|
||||
dialogRoot.removeEventListener('keydown', Radzen.focusTrap);
|
||||
dialogRoot.addEventListener('keydown', Radzen.focusTrap);
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
var dialogs = document.querySelectorAll('.rz-dialog-content');
|
||||
if (dialogs.length == 0) return;
|
||||
@@ -2673,8 +2732,6 @@ window.Radzen = {
|
||||
|
||||
if (lastDialog) {
|
||||
lastDialog.options = options;
|
||||
lastDialog.removeEventListener('keydown', Radzen.focusTrap);
|
||||
lastDialog.addEventListener('keydown', Radzen.focusTrap);
|
||||
|
||||
if (options.resizable) {
|
||||
dialog.offsetWidth = lastDialog.parentElement.offsetWidth;
|
||||
@@ -5806,13 +5863,21 @@ Radzen.chatScrollAfterRender = function(selector, delay) {
|
||||
if (container) container.scrollTop = container.scrollHeight;
|
||||
}, delay || 100);
|
||||
};
|
||||
Radzen.createAutoComplete = function(el, popupId, openOnFocus) {
|
||||
Radzen.createAutoComplete = function(el, popupId, openOnFocus, instance, openCallback, closeCallback) {
|
||||
if (!el) return null;
|
||||
var input = el.querySelector('input.rz-autocomplete-input, textarea.rz-autocomplete-input');
|
||||
var list = el.querySelector('.rz-autocomplete-list');
|
||||
if (!input) return null;
|
||||
function onInput() { Radzen.openPopup(input.parentNode, popupId, true); }
|
||||
function onFocus() { Radzen.openPopup(input.parentNode, popupId, true); }
|
||||
function open() {
|
||||
var popup = document.getElementById(popupId);
|
||||
var wasOpen = popup && popup.style.display == 'block';
|
||||
Radzen.openPopup(input.parentNode, popupId, true, null, null, null, instance, closeCallback);
|
||||
if (!wasOpen && instance && openCallback) {
|
||||
try { suppressDisposed(instance.invokeMethodAsync(openCallback)); } catch { }
|
||||
}
|
||||
}
|
||||
function onInput() { open(); }
|
||||
function onFocus() { open(); }
|
||||
function clearActive() { Radzen.activeElement = null; }
|
||||
input.addEventListener('input', onInput);
|
||||
input.addEventListener('blur', clearActive);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<RadzenColumn Size="12" SizeLG="4">
|
||||
<RadzenCard Variant="Variant.Outlined">
|
||||
<RadzenStack Orientation="Orientation.Vertical" Gap="1rem">
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1">Date & Time Options</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P">Date & Time Options</RadzenText>
|
||||
|
||||
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Wrap="FlexWrap.Wrap">
|
||||
<RadzenCheckBox @bind-Value="@showDateSeparator" TValue="bool" Name="showDateSeparator" />
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<RadzenRow>
|
||||
<RadzenColumn Size="12">
|
||||
<RadzenCard Variant="Variant.Outlined">
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1">AI Configuration</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P">AI Configuration</RadzenText>
|
||||
<RadzenStack Orientation="Orientation.Vertical" Gap="0.5rem">
|
||||
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Wrap="FlexWrap.Wrap">
|
||||
<RadzenLabel Style="white-space: nowrap;">Model:</RadzenLabel>
|
||||
@@ -50,7 +50,7 @@
|
||||
</RadzenColumn>
|
||||
<RadzenColumn Size="12">
|
||||
<RadzenCard Variant="Variant.Outlined">
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1">Current Configuration</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P">Current Configuration</RadzenText>
|
||||
<RadzenStack Orientation="Orientation.Vertical" Gap="0.25rem">
|
||||
<RadzenText TextStyle="TextStyle.Body2">
|
||||
<strong>Model:</strong> @selectedModel
|
||||
@@ -63,7 +63,7 @@
|
||||
</RadzenColumn>
|
||||
<RadzenColumn Size="12">
|
||||
<RadzenCard Variant="Variant.Outlined">
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1">Available Models</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P">Available Models</RadzenText>
|
||||
<RadzenStack Orientation="Orientation.Vertical">
|
||||
@foreach (var model in availableModels)
|
||||
{
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
<RadzenRow>
|
||||
<RadzenColumn Size="12" SizeLG="12">
|
||||
<RadzenCard Variant="Variant.Outlined">
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1">Memory Statistics</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P">Memory Statistics</RadzenText>
|
||||
<RadzenRow>
|
||||
<RadzenColumn Size="6">
|
||||
<RadzenText TextStyle="TextStyle.H4">@activeSessionsCount</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.H4" TagName="TagName.P">@activeSessionsCount</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Caption">Active Sessions</RadzenText>
|
||||
</RadzenColumn>
|
||||
<RadzenColumn Size="6">
|
||||
<RadzenText TextStyle="TextStyle.H4">@totalMessagesCount</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.H4" TagName="TagName.P">@totalMessagesCount</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Caption">Total Messages</RadzenText>
|
||||
</RadzenColumn>
|
||||
</RadzenRow>
|
||||
@@ -32,7 +32,7 @@
|
||||
</RadzenColumn>
|
||||
<RadzenColumn Size="12">
|
||||
<RadzenCard Variant="Variant.Outlined">
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1">Session Management</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P">Session Management</RadzenText>
|
||||
<RadzenStack Orientation="Orientation.Vertical">
|
||||
<RadzenStack Orientation="Orientation.Horizontal" Wrap="FlexWrap.Wrap">
|
||||
<RadzenButton Text="New Session" Icon="add" ButtonStyle="ButtonStyle.Primary" Click="@OnNewSession" Variant="Variant.Flat" />
|
||||
@@ -48,7 +48,7 @@
|
||||
</RadzenColumn>
|
||||
<RadzenColumn Size="12">
|
||||
<RadzenCard Variant="Variant.Outlined">
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1">Session History</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P">Session History</RadzenText>
|
||||
<RadzenStack Orientation="Orientation.Vertical">
|
||||
<RadzenDropDown TValue="string" Data="@sessionIds" @bind-Value="@selectedSessionId" Placeholder="Select a session to load" Style="width: 100%;" />
|
||||
<RadzenButton Text="Load Selected Session" Icon="folder_open" ButtonStyle="ButtonStyle.Base" Variant="Variant.Flat"
|
||||
@@ -60,10 +60,10 @@
|
||||
</RadzenColumn>
|
||||
<RadzenColumn Size="12">
|
||||
<RadzenCard Variant="Variant.Outlined">
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1">Memory Features</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P">Memory Features</RadzenText>
|
||||
<RadzenRow>
|
||||
<RadzenColumn Size="12" SizeMD="6">
|
||||
<RadzenText TextStyle="TextStyle.H6">Conversation Memory</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.H6" TagName="TagName.P">Conversation Memory</RadzenText>
|
||||
<ul>
|
||||
<li>The AI remembers all previous messages in the conversation</li>
|
||||
<li>Context is maintained across multiple questions</li>
|
||||
@@ -72,7 +72,7 @@
|
||||
</ul>
|
||||
</RadzenColumn>
|
||||
<RadzenColumn Size="12" SizeMD="6">
|
||||
<RadzenText TextStyle="TextStyle.H6">Session Management</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.H6" TagName="TagName.P">Session Management</RadzenText>
|
||||
<ul>
|
||||
<li>Create new sessions for different conversations</li>
|
||||
<li>Switch between different conversation contexts</li>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<RadzenText Anchor="appearance-toggle#video-radzen-blazor-studio-config" TextStyle="TextStyle.H5" TagName="TagName.H2" class="rz-pt-12">
|
||||
RadzenAppearanceToggle in Radzen Blazor Studio
|
||||
</RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" class="rz-mb-6">
|
||||
<RadzenText TextStyle="TextStyle.Subtitle1" TagName="TagName.P" class="rz-mb-6">
|
||||
Learn how to add and configure this built-in component
|
||||
</RadzenText>
|
||||
<RadzenCard Variant="Variant.Outlined" class="rz-p-7">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<RadzenArcGaugeScaleValue Value=@value ShowValue=@showValue>
|
||||
<Template Context="pointer">
|
||||
<RadzenStack AlignItems="AlignItems.Center" Gap="0" Style="margin-top: -50%;">
|
||||
<RadzenText TextStyle="TextStyle.H5" class="rz-m-0"><strong>@pointer.Value</strong></RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.H5" TagName="TagName.P" class="rz-m-0"><strong>@pointer.Value</strong></RadzenText>
|
||||
<RadzenText TextStyle="TextStyle.Caption">km/h</RadzenText>
|
||||
</RadzenStack>
|
||||
</Template>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user