fix(ui): Tabs is an ARIA tab list with roving focus and a wired panel

The rail was a row of aria-pressed toggles: every tab a Tab stop, no arrows,
nothing tying a tab to its content. tablist/tab/aria-selected, one Tab stop,
arrows on either axis, Home/End, and useTabPanel for aria-controls/labelledby.
This commit is contained in:
2026-09-27 14:22:37 +02:00
parent a975ab627a
commit 922d589b09
14 changed files with 311 additions and 139 deletions
+9 -2
View File
@@ -9,6 +9,7 @@ import Tooltip from "./ui/Tooltip";
import InlineNotice from "./ui/InlineNotice";
import { useMe } from "../lib/useMe";
import Tabs from "./ui/Tabs";
import { useTabPanel } from "./ui/tabPanel";
import { LoadingState, StateMessage } from "./ui/QueryState";
import { PageToolbar } from "./ui/PageShell";
import { Switch } from "./ui/form";
@@ -30,6 +31,7 @@ import { SURFACE } from "./ui/surfaces";
export default function ConfigPanel() {
const { t } = useTranslation();
const panel = useTabPanel();
const qc = useQueryClient();
const me = useMe();
const q = useQuery({ queryKey: qk.adminConfig(), queryFn: api.adminConfig });
@@ -191,13 +193,18 @@ export default function ConfigPanel() {
took three lines of a short window for text read once. */}
<PageToolbar>
<div className="px-4 pt-3 max-w-3xl w-full mx-auto">
<Tabs tabs={groupTabs} active={activeGroup ?? ""} onChange={setTab} />
<Tabs
idBase={panel.idBase}
tabs={groupTabs}
active={activeGroup ?? ""}
onChange={setTab}
/>
</div>
</PageToolbar>
<div className="px-4 pb-24 pt-1 max-w-3xl w-full mx-auto">
<p className="text-xs text-muted mb-3 leading-relaxed">{t("config.intro")}</p>
{activeGroup && (
<div className={`${SURFACE.panel} p-4 mb-4`}>
<div {...panel.panelProps(activeGroup ?? "")} className={`${SURFACE.panel} p-4 mb-4`}>
<div className="divide-y divide-border/60">
{(data.groups[activeGroup] ?? []).map((item) => (
<Field