85 lines
2.8 KiB
Plaintext
85 lines
2.8 KiB
Plaintext
<div class="@BuildCssClass()" role="tablist" aria-label="@AriaLabel">
|
|
@foreach (var item in Items)
|
|
{
|
|
var isSelected = string.Equals(item.Value, SelectedValue, StringComparison.Ordinal);
|
|
var tabIndex = isSelected || (!HasSelectedValue && string.Equals(item.Value, FirstEnabledValue, StringComparison.Ordinal)) ? 0 : -1;
|
|
|
|
<button
|
|
type="button"
|
|
class="segmented-tabs-button @(isSelected ? "is-selected" : null)"
|
|
role="tab"
|
|
aria-selected="@isSelected"
|
|
tabindex="@tabIndex"
|
|
disabled="@item.IsDisabled"
|
|
@onclick="() => SelectAsync(item.Value)"
|
|
@onkeydown="args => HandleKeyDownAsync(args, item.Value)">
|
|
<span>@item.Label</span>
|
|
@if (!string.IsNullOrWhiteSpace(item.Badge))
|
|
{
|
|
<span class="segmented-tabs-badge">@item.Badge</span>
|
|
}
|
|
</button>
|
|
}
|
|
</div>
|
|
|
|
@code {
|
|
|
|
[Parameter]
|
|
public IReadOnlyList<SegmentedTabItem> Items { get; set; } = [];
|
|
|
|
[Parameter]
|
|
public string? SelectedValue { get; set; }
|
|
|
|
[Parameter]
|
|
public EventCallback<string> SelectedValueChanged { get; set; }
|
|
|
|
[Parameter]
|
|
public string AriaLabel { get; set; } = "Options";
|
|
|
|
[Parameter]
|
|
public string? CssClass { get; set; }
|
|
|
|
private bool HasSelectedValue =>
|
|
!string.IsNullOrWhiteSpace(SelectedValue) && Items.Any(item => !item.IsDisabled && string.Equals(item.Value, SelectedValue, StringComparison.Ordinal));
|
|
|
|
private string? FirstEnabledValue =>
|
|
Items.FirstOrDefault(item => !item.IsDisabled)?.Value;
|
|
|
|
private string BuildCssClass() =>
|
|
string.IsNullOrWhiteSpace(CssClass) ? "segmented-tabs" : $"segmented-tabs {CssClass}";
|
|
|
|
private Task SelectAsync(string value) =>
|
|
SelectedValueChanged.InvokeAsync(value);
|
|
|
|
private async Task HandleKeyDownAsync(KeyboardEventArgs args, string currentValue)
|
|
{
|
|
var enabledItems = Items.Where(item => !item.IsDisabled).ToList();
|
|
if (enabledItems.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var currentIndex = enabledItems.FindIndex(item => string.Equals(item.Value, currentValue, StringComparison.Ordinal));
|
|
if (currentIndex < 0)
|
|
{
|
|
currentIndex = 0;
|
|
}
|
|
|
|
var nextValue = args.Key switch
|
|
{
|
|
"ArrowRight" or "ArrowDown" => enabledItems[Math.Min(currentIndex + 1, enabledItems.Count - 1)].Value,
|
|
"ArrowLeft" or "ArrowUp" => enabledItems[Math.Max(currentIndex - 1, 0)].Value,
|
|
"Home" => enabledItems[0].Value,
|
|
"End" => enabledItems[^1].Value,
|
|
_ => null
|
|
};
|
|
|
|
if (string.IsNullOrWhiteSpace(nextValue))
|
|
{
|
|
return;
|
|
}
|
|
|
|
await SelectAsync(nextValue);
|
|
}
|
|
|
|
} |