From 20ae85f8791d491f342e743f002c9a58771073bd Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 21 Apr 2026 13:32:04 +0200 Subject: [PATCH] feat(comment): expose comment id + focus ring on CommentMessage wrapper Notification deep-link scroll targets #comment-{id}. Add the id to the article wrapper along with tabindex="-1" so scrollIntoView + .focus({preventScroll:true}) can land screen-reader and keyboard focus on the specific comment. A focus-visible ring appears only for keyboard users so mouse clicks don't trigger a visible outline. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/lib/components/CommentMessage.svelte | 7 ++++++- .../components/CommentMessage.svelte.spec.ts | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/components/CommentMessage.svelte b/frontend/src/lib/components/CommentMessage.svelte index f1171448..f66c508c 100644 --- a/frontend/src/lib/components/CommentMessage.svelte +++ b/frontend/src/lib/components/CommentMessage.svelte @@ -32,7 +32,12 @@ const wasEdited = $derived(message.updatedAt > message.createdAt); const parsed = $derived(extractQuote(message.content)); -
+
{ await expect.element(textarea).toBeInTheDocument(); await expect.element(textarea).toHaveValue('current edit text'); }); + + it('exposes id="comment-{message.id}" on the article wrapper for deep-link scroll', async () => { + render(CommentMessage, defaultProps()); + const article = page.getByRole('article').element(); + expect(article.getAttribute('id')).toBe('comment-msg-1'); + }); + + it('is focusable but not in tab order (tabindex="-1")', async () => { + render(CommentMessage, defaultProps()); + const article = page.getByRole('article').element(); + expect(article.getAttribute('tabindex')).toBe('-1'); + }); + + it('shows a focus-visible ring when focused via keyboard', async () => { + render(CommentMessage, defaultProps()); + const article = page.getByRole('article').element(); + const classes = article.className; + expect(classes).toMatch(/focus-visible:ring-2/); + expect(classes).toMatch(/focus-visible:ring-brand-navy/); + expect(classes).toMatch(/outline-none/); + }); });