fix(person-mention): name the hover-card region and announce its busy state

Leonie FINDING-02/03 + Elicit NFR concern + Sara #4: role="region" with no
aria-label is an axe-core warning, and the pulsing-bars skeleton carries no
semantics for SR clients.

- Add aria-label to the region root: person displayName when loaded,
  localised "Lade Person…" while loading. Region always has a name.
- Add aria-busy="true" while loading; cleared on loaded/error so the
  state change is announced via aria-live="polite".
- Add role="status" + aria-label on the skeleton so SR clients hear
  "Lade Person" rather than three silent <div>s.
- New Paraglide key person_mention_loading in de/en/es.

Five new tests pin: aria-busy true while loading, aria-busy unset/false
when loaded, aria-label is displayName when loaded, aria-label is the
loading label while loading.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-29 09:00:15 +02:00
parent 3365f5845e
commit 6dd60571e3
5 changed files with 70 additions and 1 deletions

View File

@@ -41,6 +41,17 @@ const notesExcerpt = $derived.by(() => {
if (notes.length <= NOTES_MAX) return notes;
return notes.slice(0, NOTES_MAX) + '…';
});
// Accessible name for the region landmark — required by WCAG 1.3.1.
// Falls back to a localised loading label so axe-core never sees an unnamed
// region (Leonie FINDING-02 / Elicit NFR concern).
const ariaLabel = $derived(
state.status === 'loaded' ? state.person.displayName : m.person_mention_loading()
);
// aria-busy="true" while loading so SR clients know the region's contents
// will change. Cleared on loaded/error so the new content is announced.
const ariaBusy = $derived(state.status === 'loading');
</script>
<div
@@ -49,12 +60,19 @@ const notesExcerpt = $derived.by(() => {
id={cardId}
role="region"
aria-live="polite"
aria-label={ariaLabel}
aria-busy={ariaBusy ? 'true' : undefined}
style:position="absolute"
style:top={`${position.top}px`}
style:left={`${position.left}px`}
>
{#if state.status === 'loading'}
<div data-testid="person-hover-card-skeleton" class="skeleton">
<div
data-testid="person-hover-card-skeleton"
class="skeleton"
role="status"
aria-label={m.person_mention_loading()}
>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>