Commit b3b450c3 authored by Alejandro Celaya's avatar Alejandro Celaya Committed by Alejandro Celaya

Make ThreadCard more accessible by allowing focus and adding label for screen readers

parent c193ceeb
......@@ -63,13 +63,14 @@ function ThreadCard({ frameSync, thread }: ThreadCardProps) {
}, [focusRequest, store, thread.id]);
return (
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
<Card
active={isHovered}
classes="cursor-pointer focus-visible-ring theme-clean:border-none"
data-testid="thread-card"
elementRef={cardRef}
tabIndex={-1}
tabIndex={0}
role="button"
aria-label="Press Enter to scroll annotation into view"
onClick={e => {
// Prevent click events intended for another action from
// triggering a page scroll.
......@@ -79,6 +80,13 @@ function ThreadCard({ frameSync, thread }: ThreadCardProps) {
}}
onMouseEnter={() => setThreadHovered(thread.annotation ?? null)}
onMouseLeave={() => setThreadHovered(null)}
onKeyDown={e => {
// Simulate default button behavior, where `Enter` and `Space` trigger
// click action
if (['Enter', ' '].includes(e.key) && thread.annotation) {
scrollToAnnotation(thread.annotation);
}
}}
key={thread.id}
>
<CardContent>{threadContent}</CardContent>
......
......@@ -114,6 +114,39 @@ describe('ThreadCard', () => {
});
});
describe('keyboard events', () => {
['Enter', ' '].forEach(key => {
it('scrolls to annotation when `Enter` or `Space` are pressed', () => {
const wrapper = createComponent();
wrapper.find(threadCardSelector).simulate('keydown', { key });
assert.calledWith(
fakeFrameSync.scrollToAnnotation,
fakeThread.annotation
);
});
it('does not scroll to annotation when it is not set', () => {
const wrapper = createComponent({ thread: {} });
wrapper.find(threadCardSelector).simulate('keypress', { key });
assert.notCalled(fakeFrameSync.scrollToAnnotation);
});
});
['a', 'b', 'Escape', 'ArrowDown'].forEach(key => {
it('does not scroll to annotation when key other than `Enter` or `Space` is pressed', () => {
const wrapper = createComponent();
wrapper.find(threadCardSelector).simulate('keypress', { key });
assert.notCalled(fakeFrameSync.scrollToAnnotation);
});
});
});
describe('keyboard focus request handling', () => {
[null, 'other-annotation'].forEach(focusRequest => {
it('does not focus thread if there is no matching focus request', () => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment