refactor(ui): unify semantic presentation and table hierarchy

This commit is contained in:
Joseph Doherty
2026-11-13 19:06:18 -05:00
parent 2d30323ae8
commit 0c41b613ac
97 changed files with 13829 additions and 167 deletions
@@ -23,6 +23,39 @@ public class DataTablePagerTests : BunitContext
.Add(p => p.RowContent, (RenderFragment<int>)(item => b => b.AddMarkupContent(0, $"<tr><td>{item}</td></tr>"))));
}
/// <summary>True empty results show no contradictory one-to-zero range.</summary>
[Fact]
public void EmptyTable_ShowsZeroItems()
{
var cut = RenderTable(0);
Assert.Equal("0 items", cut.Find(".text-muted.small").TextContent.Trim());
}
/// <summary>Filtering to zero and clearing preserves the correct range and paging state.</summary>
[Fact]
public void FilterToEmpty_ThenClear_RestoresRealCount()
{
var cut = RenderTable(60);
cut.Render(p => p.Add(c => c.ShowSearch, true).Add(c => c.SearchFilter, (item, search) => item.ToString().Contains(search)));
cut.Find("input").Input("no-match");
Assert.Equal("0 items", cut.Find(".text-muted.small").TextContent.Trim());
cut.Find("button[aria-label='Clear search']").Click();
Assert.Contains("1–25 of 60 items", cut.Find(".text-muted.small").TextContent);
}
/// <summary>The reusable table has one named keyboard-accessible overflow region.</summary>
[Fact]
public void Table_HasNamedKeyboardScrollRegion()
{
var cut = RenderTable(4);
var region = cut.Find("[role=region]");
Assert.Equal("Data table", region.GetAttribute("aria-label"));
Assert.Equal("0", region.GetAttribute("tabindex"));
Assert.Single(region.QuerySelectorAll("table"));
cut.Render(p => p.Add(c => c.TableLabel, "Synthetic records"));
Assert.Equal("Synthetic records", cut.Find("[role=region]").GetAttribute("aria-label"));
}
private static int NumberedPageButtons(IRenderedComponent<DataTable<int>> cut)
=> cut.FindAll("ul.pagination li.page-item button")
.Count(b => int.TryParse(b.TextContent.Trim(), out _));