Unverified Commit 2364c416 authored by Lyza Gardner's avatar Lyza Gardner Committed by GitHub

Merge pull request #1782 from hypothesis/annotation-header-a11y

Replace link with `Button` in `AnnotationHeader` (A11y)
parents 857cde8e 0d338deb
import { createElement } from 'preact';
import propTypes from 'prop-types';
import { isHighlight } from '../util/annotation-metadata';
import { isHighlight, isReply } from '../util/annotation-metadata';
import AnnotationDocumentInfo from './annotation-document-info';
import AnnotationShareInfo from './annotation-share-info';
import AnnotationUser from './annotation-user';
import Button from './button';
import SvgIcon from './svg-icon';
import Timestamp from './timestamp';
......@@ -20,6 +21,7 @@ export default function AnnotationHeader({
onReplyCountClick,
replyCount,
showDocumentInfo,
threadIsCollapsed,
}) {
const annotationLink = annotation.links ? annotation.links.html : '';
const replyPluralized = !replyCount || replyCount > 1 ? 'replies' : 'reply';
......@@ -27,17 +29,21 @@ export default function AnnotationHeader({
const hasBeenEdited =
annotation.updated && annotation.created !== annotation.updated;
const showReplyButton = threadIsCollapsed && isReply(annotation);
const replyButtonText = `${replyCount} ${replyPluralized}`;
return (
<header className="annotation-header">
<div className="annotation-header__row">
<AnnotationUser annotation={annotation} />
<div className="annotation-collapsed-replies">
{/* FIXME-A11Y */}
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events, jsx-a11y/anchor-is-valid */}
<a className="annotation-link" onClick={onReplyCountClick}>
{replyCount} {replyPluralized}
</a>
</div>
{showReplyButton && (
<Button
className="annotation-header__reply-toggle"
buttonText={replyButtonText}
onClick={onReplyCountClick}
title="Expand replies"
/>
)}
{!isEditing && annotation.created && (
<div className="annotation-header__timestamp">
{hasBeenEdited && (
......@@ -93,4 +99,8 @@ AnnotationHeader.propTypes = {
* annotation and stream views
*/
showDocumentInfo: propTypes.bool,
/**
* Is this thread currently collapsed?
*/
threadIsCollapsed: propTypes.bool.isRequired,
};
......@@ -102,6 +102,7 @@ function AnnotationOmega({
onReplyCountClick={onReplyCountClick}
replyCount={replyCount}
showDocumentInfo={showDocumentInfo}
threadIsCollapsed={threadIsCollapsed}
/>
{hasQuote && <AnnotationQuote annotation={annotation} />}
<AnnotationBody
......
......@@ -10,6 +10,7 @@ import mockImportedComponents from '../../../test-util/mock-imported-components'
describe('AnnotationHeader', () => {
let fakeIsHighlight;
let fakeIsReply;
const createAnnotationHeader = props => {
return mount(
......@@ -19,6 +20,7 @@ describe('AnnotationHeader', () => {
onReplyCountClick={sinon.stub()}
replyCount={0}
showDocumentInfo={false}
threadIsCollapsed={false}
{...props}
/>
);
......@@ -26,11 +28,13 @@ describe('AnnotationHeader', () => {
beforeEach(() => {
fakeIsHighlight = sinon.stub().returns(false);
fakeIsReply = sinon.stub().returns(false);
$imports.$mock(mockImportedComponents());
$imports.$mock({
'../util/annotation-metadata': {
isHighlight: fakeIsHighlight,
isReply: fakeIsReply,
},
});
});
......@@ -40,13 +44,38 @@ describe('AnnotationHeader', () => {
});
describe('collapsed replies', () => {
it('should have a callback', () => {
const fakeCallback = sinon.stub();
const findReplyButton = wrapper =>
wrapper.find('Button').filter('.annotation-header__reply-toggle');
it('should render if annotation is a reply and thread is collapsed', () => {
let fakeCallback = sinon.stub();
fakeIsReply.returns(true);
const wrapper = createAnnotationHeader({
onReplyCountClick: fakeCallback,
threadIsCollapsed: true,
});
const btn = findReplyButton(wrapper);
assert.isTrue(btn.exists());
assert.equal(btn.props().onClick, fakeCallback);
});
it('should not render if annotation is not a reply', () => {
fakeIsReply.returns(false);
const wrapper = createAnnotationHeader({
threadIsCollapsed: true,
});
const btn = findReplyButton(wrapper);
assert.isFalse(btn.exists());
});
it('should not render if thread is not collapsed', () => {
fakeIsReply.returns(true);
const wrapper = createAnnotationHeader({
threadIsCollapsed: false,
});
const replyCollapseLink = wrapper.find('.annotation-link');
assert.equal(replyCollapseLink.prop('onClick'), fakeCallback);
const btn = findReplyButton(wrapper);
assert.isFalse(btn.exists());
});
[
......@@ -63,12 +92,14 @@ describe('AnnotationHeader', () => {
expected: '2 replies',
},
].forEach(testCase => {
it(`it should render the annotation reply count (${testCase.replyCount})`, () => {
it(`it should render the annotation reply count button (${testCase.replyCount})`, () => {
fakeIsReply.returns(true);
const wrapper = createAnnotationHeader({
replyCount: testCase.replyCount,
threadIsCollapsed: true,
});
const replyCollapseLink = wrapper.find('.annotation-link');
assert.equal(replyCollapseLink.text(), testCase.expected);
const replyCollapseButton = findReplyButton(wrapper);
assert.equal(replyCollapseButton.props().buttonText, testCase.expected);
});
});
});
......
......@@ -8,7 +8,8 @@
is-editing="vm.editing()"
on-reply-count-click="vm.onReplyCountClick()"
reply-count="vm.replyCount"
show-document-info="vm.showDocumentInfo">
show-document-info="vm.showDocumentInfo"
thread-is-collapsed="vm.isCollapsed">
</annotation-header>
<annotation-quote annotation="vm.annotation" ng-if="vm.quote()">
......
......@@ -13,6 +13,16 @@
align-items: baseline;
}
&__reply-toggle.button {
padding: 0 0.5em;
font-weight: 400;
background-color: transparent;
&:hover {
background-color: transparent;
color: var.$link-color-hover;
}
}
// Timestamps are right aligned in a flex row
&__timestamp {
margin-left: auto;
......
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