fix(a11y): names that carry what they show; the unused-key check stops covering whole files

- The palette launcher's name replaced its visible "Jump to…" (and the key cap's its "Ctrl K"):
  a voice-control "click Jump to" matched nothing (WCAG 2.5.3). Each name contains its text now.
- SegmentedToggle's `title` was only a tooltip on a non-focusable box — the live search's "how
  many per batch" hint reached no keyboard or screen-reader user. It is the group's accessible
  description, standalone and captioned alike.
- The unused-key contract let a template like `card.${status}` cover its whole namespace, which hid
  five dead keys (deleted). Dynamic keys are matched by shape (`editor.*.hint`); a bare namespace
  shape covers nothing, and the audit/quota namespaces are now held both ways by backendIds.
- CLAUDE.md's "FE control" row matches the lint rule it cites; each no-restricted-syntax entry has
  its reason directly above it.
This commit is contained in:
2026-09-19 19:19:43 +02:00
parent fa4f823fc8
commit cf0c55ba80
13 changed files with 128 additions and 39 deletions
+6 -2
View File
@@ -20,6 +20,10 @@ function useCap(): string {
});
}
// Each accessible name CONTAINS what the control shows (WCAG 2.5.3, Label in Name): a voice-control
// user says what they see — "click Jump to", "click Ctrl K" — and a name that replaced the visible
// words matched nothing.
/** The key cap at the end of a search field. A button, so the pointer and a screen reader reach it
* too; left out of a phone's narrow header, where there is no keyboard to press it on. */
export function PaletteKeycap() {
@@ -29,7 +33,7 @@ export function PaletteKeycap() {
<button
type="button"
onClick={openPalette}
aria-label={t("palette.open")}
aria-label={`${t("palette.open")} (${cap})`}
title={t("palette.open")}
className="shrink-0 rounded-md border border-border px-1.5 py-0.5 font-mono text-3xs text-muted transition hover:border-accent/50 hover:text-fg @max-[640px]/appmain:hidden"
>
@@ -46,7 +50,7 @@ export function PaletteLauncher() {
<button
type="button"
onClick={openPalette}
aria-label={t("palette.open")}
title={t("palette.open")}
className="pointer-events-auto glass-menu flex h-11 items-center gap-2 rounded-2xl px-3 text-sm text-muted transition hover:text-fg"
>
<Command className="h-4 w-4 shrink-0" aria-hidden="true" />