fix(web): objects-table a11y — real-link rows, pill focus ring, announced load/error (#62)

This commit is contained in:
2026-06-08 19:07:00 +02:00
parent 0def81ab42
commit da3e078fbc
2 changed files with 70 additions and 12 deletions
+17 -10
View File
@@ -6,6 +6,7 @@ import { ChevronDown, ChevronUp, ChevronsUpDown } from "lucide-react";
import type { components } from "../api/schema";
import { useObjectsPage } from "../api/queries";
import { useDebouncedValue } from "../lib/use-debounced-value";
import { focusRing } from "../lib/focus-ring";
import { useConfig } from "../config/config-context";
import { VisibilityBadge } from "./visibility-badge";
import { Button, buttonVariants } from "@/components/ui/button";
@@ -170,7 +171,7 @@ export function ObjectsTable() {
type="button"
aria-pressed={active}
onClick={() => setVisibility(value)}
className={`rounded-md px-2 py-1 ${active ? "bg-primary text-primary-foreground" : "border"}`}
className={`${focusRing} rounded-md px-2 py-1 ${active ? "bg-primary text-primary-foreground" : "border"}`}
>
{value === "all" ? t("search.all") : t(`visibility.${value}`)}
</button>
@@ -220,7 +221,7 @@ export function ObjectsTable() {
body = (
<tbody>
<tr>
<td colSpan={6} className="px-3 py-6 text-center text-sm text-destructive">
<td colSpan={6} role="alert" className="px-3 py-6 text-center text-sm text-destructive">
{t("objects.loadError")}
</td>
</tr>
@@ -246,18 +247,21 @@ export function ObjectsTable() {
return (
<tr
key={object.id}
role="link"
tabIndex={0}
aria-selected={selected}
onClick={() => navigate(`/objects/${object.id}?${params}`)}
onKeyDown={(event) => {
if (event.key === "Enter") navigate(`/objects/${object.id}?${params}`);
}}
className={`cursor-pointer border-b text-sm ${
selected ? "bg-primary/10" : "hover:bg-muted"
}`}
>
<td className="px-3 py-2 text-muted-foreground">{object.object_number}</td>
<td className="px-3 py-2 text-muted-foreground">
<Link
to={`/objects/${object.id}?${params}`}
aria-current={selected ? "page" : undefined}
onClick={(event) => event.stopPropagation()}
className={`${focusRing} rounded-sm hover:underline`}
>
{object.object_number}
</Link>
</td>
<td className="px-3 py-2 font-medium">{object.object_name}</td>
<td className="px-3 py-2">
<VisibilityBadge visibility={object.visibility} />
@@ -276,7 +280,10 @@ export function ObjectsTable() {
<div className="flex h-full flex-col">
{toolbar}
<div className="flex-1 overflow-auto">
<table className="w-full border-collapse">
<table className="w-full border-collapse" aria-busy={isLoading || undefined}>
<caption className="sr-only" aria-live="polite">
{isLoading ? t("common.loading") : t("objects.tableLabel")}
</caption>
{columns}
{body}
</table>