Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to
- ♿(frontend) improve ARIA in doc grid and editor for a11y #1519
- ♿(frontend) improve accessibility and styling of summary table #1528
- ♿(frontend) add focus trap and enter key support to remove doc modal #1531
- ♿(frontend) improve screen reader support in DocShare modal #1628
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During rebase, this part will have to go under Unrelease

- 🐛(docx) fix image overflow by limiting width to 600px during export #1525
- 🐛(frontend) preserve @ character when esc is pressed after typing it #1512
- 🐛(frontend) make summary button fixed to remain visible during scroll #1581
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ test.describe('Doc Header', () => {
await expect(
invitationCard.getByText('[email protected]').first(),
).toBeVisible();
const invitationRole = invitationCard.getByLabel('doc-role-dropdown');
const invitationRole = invitationCard.getByTestId('doc-role-dropdown');
await expect(invitationRole).toBeVisible();

await invitationRole.click();
Expand All @@ -217,7 +217,7 @@ test.describe('Doc Header', () => {
await expect(invitationCard).toBeHidden();

const memberCard = shareModal.getByLabel('List members card');
const roles = memberCard.getByLabel('doc-role-dropdown');
const roles = memberCard.getByTestId('doc-role-dropdown');
await expect(memberCard).toBeVisible();
await expect(
memberCard.getByText('[email protected]').first(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ test.describe('Document create member', () => {
await expect(list.getByText(email)).toBeVisible();

// Check roles are displayed
await list.getByLabel('doc-role-dropdown').click();
await list.getByTestId('doc-role-dropdown').click();
await expect(page.getByRole('menuitem', { name: 'Reader' })).toBeVisible();
await expect(page.getByRole('menuitem', { name: 'Editor' })).toBeVisible();
await expect(page.getByRole('menuitem', { name: 'Owner' })).toBeVisible();
Expand Down Expand Up @@ -128,7 +128,7 @@ test.describe('Document create member', () => {

// Choose a role
const container = page.getByTestId('doc-share-add-member-list');
await container.getByLabel('doc-role-dropdown').click();
await container.getByTestId('doc-role-dropdown').click();
await page.getByRole('menuitem', { name: 'Owner' }).click();

const responsePromiseCreateInvitation = page.waitForResponse(
Expand All @@ -146,7 +146,7 @@ test.describe('Document create member', () => {
await page.getByTestId(`search-user-row-${email}`).click();

// Choose a role
await container.getByLabel('doc-role-dropdown').click();
await container.getByTestId('doc-role-dropdown').click();
await page.getByRole('menuitem', { name: 'Owner' }).click();

const responsePromiseCreateInvitationFail = page.waitForResponse(
Expand Down Expand Up @@ -183,7 +183,7 @@ test.describe('Document create member', () => {

// Choose a role
const container = page.getByTestId('doc-share-add-member-list');
await container.getByLabel('doc-role-dropdown').click();
await container.getByTestId('doc-role-dropdown').click();
await page.getByRole('menuitem', { name: 'Administrator' }).click();

const responsePromiseCreateInvitation = page.waitForResponse(
Expand All @@ -210,7 +210,7 @@ test.describe('Document create member', () => {
response.request().method() === 'PATCH',
);

await userInvitation.getByLabel('doc-role-dropdown').click();
await userInvitation.getByTestId('doc-role-dropdown').click();
await page.getByRole('menuitem', { name: 'Reader' }).click();

const responsePatchInvitation = await responsePromisePatchInvitation;
Expand Down Expand Up @@ -272,7 +272,7 @@ test.describe('Document create member', () => {
const container = page.getByTestId(
`doc-share-access-request-row-${emailRequest}`,
);
await container.getByLabel('doc-role-dropdown').click();
await container.getByTestId('doc-role-dropdown').click();
await page.getByRole('menuitem', { name: 'Administrator' }).click();
await container.getByRole('button', { name: 'Approve' }).click();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ test.describe('Document list members', () => {
const currentUser = list.getByTestId(
`doc-share-member-row-user.test@${browserName}.test`,
);
const currentUserRole = currentUser.getByLabel('doc-role-dropdown');
const currentUserRole = currentUser.getByTestId('doc-role-dropdown');
await expect(currentUser).toBeVisible();
await expect(currentUserRole).toBeVisible();
await currentUserRole.click();
Expand All @@ -169,7 +169,7 @@ test.describe('Document list members', () => {
});
const newUserEmail = await addNewMember(page, 0, 'Owner');
const newUser = list.getByTestId(`doc-share-member-row-${newUserEmail}`);
const newUserRoles = newUser.getByLabel('doc-role-dropdown');
const newUserRoles = newUser.getByTestId('doc-role-dropdown');

await expect(newUser).toBeVisible();

Expand Down Expand Up @@ -214,9 +214,7 @@ test.describe('Document list members', () => {

const emailMyself = `user.test@${browserName}.test`;
const mySelf = list.getByTestId(`doc-share-member-row-${emailMyself}`);
const mySelfRole = mySelf.getByRole('button', {
name: 'doc-role-dropdown',
});
const mySelfRole = mySelf.getByTestId('doc-role-dropdown');

const userOwnerEmail = await addNewMember(page, 0, 'Owner');
const userOwner = list.getByTestId(
Expand All @@ -231,9 +229,7 @@ test.describe('Document list members', () => {
const userReader = list.getByTestId(
`doc-share-member-row-${userReaderEmail}`,
);
const userReaderRole = userReader.getByRole('button', {
name: 'doc-role-dropdown',
});
const userReaderRole = userReader.getByTestId('doc-role-dropdown');

await expect(mySelf).toBeVisible();
await expect(userOwner).toBeVisible();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ test.describe('Doc Tree', () => {
const currentUser = list.getByTestId(
`doc-share-member-row-user.test@${browserName}.test`,
);
const currentUserRole = currentUser.getByLabel('doc-role-dropdown');
const currentUserRole = currentUser.getByTestId('doc-role-dropdown');
await currentUserRole.click();
await page.getByRole('menuitem', { name: 'Administrator' }).click();
await list.click();
Expand Down
6 changes: 3 additions & 3 deletions src/frontend/apps/e2e/__tests__/app-impress/utils-share.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ export const addNewMember = async (
await page.getByRole('option', { name: users[index].email }).click();

// Choose a role
await page.getByLabel('doc-role-dropdown').click();
await page.getByTestId('doc-role-dropdown').click();
await page.getByRole('menuitem', { name: role }).click();
await page.getByRole('button', { name: 'Invite' }).click();
await page.getByTestId('doc-share-invite-button').click();

return users[index].email;
};
Expand Down Expand Up @@ -74,7 +74,7 @@ export const updateRoleUser = async (
const list = page.getByTestId('doc-share-quick-search');

const currentUser = list.getByTestId(`doc-share-member-row-${email}`);
const currentUserRole = currentUser.getByLabel('doc-role-dropdown');
const currentUserRole = currentUser.getByTestId('doc-role-dropdown');
await currentUserRole.click();
await page.getByRole('menuitem', { name: role }).click();
await list.click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const QuickSearch = ({
label={label}
shouldFilter={false}
ref={ref}
tabIndex={0}
tabIndex={-1}
value={selectedValue}
onValueChange={handleValueChange}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type DocRoleDropdownProps = {
onSelectRole: (role: Role) => void;
rolesAllowed?: Role[];
isLastOwner?: boolean;
ariaLabel?: string;
};

export const DocRoleDropdown = ({
Expand All @@ -29,6 +30,7 @@ export const DocRoleDropdown = ({
rolesAllowed,
access,
isLastOwner = false,
ariaLabel,
}: DocRoleDropdownProps) => {
const { t } = useTranslation();
const { transRole, translatedRoles } = useTrans();
Expand Down Expand Up @@ -113,11 +115,15 @@ export const DocRoleDropdown = ({
return (
<DropdownMenu
topMessage={topMessage}
label="doc-role-dropdown"
label={t('{{action}}, current role: {{role}}', {
action: ariaLabel,
role: transRole(currentRole),
})}
showArrow={true}
arrowCss={css`
color: var(--c--theme--colors--primary-800) !important;
`}
testId="doc-role-dropdown"
options={[
...roles,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ const DocShareAccessRequestItem = ({ doc, accessRequest }: Props) => {
onSelectRole={setRole}
canUpdate={doc.abilities.accesses_manage}
rolesAllowed={accessRequest.abilities.set_role_to}
ariaLabel={t('Change role for {{name}}', {
name: accessRequest.user.full_name || accessRequest.user.email,
})}
/>
<Button
color="tertiary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ export const DocShareAddMemberList = ({
currentRole={invitationRole}
onSelectRole={setInvitationRole}
/>
<Button onClick={() => void onInvite()} disabled={isLoading}>
<Button
onClick={() => void onInvite()}
disabled={isLoading}
data-testid="doc-share-invite-button"
>
{t('Invite')}
</Button>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ export const DocShareInvitationItem = ({
canUpdate={canUpdate}
doc={doc}
access={invitation}
ariaLabel={t('Change role for {{email}}', {
email: invitation.email,
})}
/>

{canUpdate && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ export const DocShareMemberItem = ({
rolesAllowed={access.abilities.set_role_to}
access={access}
doc={doc}
ariaLabel={t('Change role for {{name}}', {
name: access.user.full_name || access.user.email,
})}
/>
</Box>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
const [selectedUsers, setSelectedUsers] = useState<User[]>([]);
const [userQuery, setUserQuery] = useState('');
const [inputValue, setInputValue] = useState('');
const [liveAnnouncement, setLiveAnnouncement] = useState('');

const [listHeight, setListHeight] = useState<string>('400px');
const canShare = doc.abilities.accesses_manage && isRootDoc;
Expand All @@ -88,6 +89,19 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
setSelectedUsers((prev) => [...prev, user]);
setUserQuery('');
setInputValue('');

// Announce to screen readers
const userName = user.full_name || user.email;
setLiveAnnouncement(
t(
'{{name}} added to invite list. Add more members or press Tab to select role and invite.',
{
name: userName,
},
),
);
// Clear announcement after it's been read
setTimeout(() => setLiveAnnouncement(''), 100);
};
Comment on lines +93 to 105
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find a bit strange to do the announcement, we have a notification system, but I think we decided to not display a notification for that, because the invitation list will display the user that you just add, it is already like a announcement.


const { data: membersQuery } = useDocAccesses({
Expand All @@ -114,6 +128,16 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
}
const newArray = [...prevState];
newArray.splice(index, 1);

// Announce to screen readers
const userName = row.full_name || row.email;
setLiveAnnouncement(
t('{{name}} removed from invite list', {
name: userName,
}),
);
setTimeout(() => setLiveAnnouncement(''), 100);

return newArray;
});
};
Expand Down Expand Up @@ -175,12 +199,29 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
<ButtonCloseModal
aria-label={t('Close the share modal')}
onClick={onClose}
tabIndex={-1}
/>
</Box>
}
hideCloseButton
>
<ShareModalStyle />
{/* Screen reader announcements */}
<div
role="status"
aria-live="polite"
aria-atomic="true"
className="sr-only"
style={{
position: 'absolute',
left: '-10000px',
width: '1px',
height: '1px',
overflow: 'hidden',
}}
>
Comment on lines +215 to +222
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The style attach with sr-only is not enough ?

{liveAnnouncement}
</div>
<Box
$height="auto"
$maxHeight={canViewAccesses ? modalContentHeight : 'none'}
Expand Down
Loading