Skip to content

Commit

Permalink
a11y: UILD-453: Improve WCAG 2.1 AA compliance for Search page (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
s3fs authored Dec 11, 2024
1 parent 3d6e798 commit 3b16dc5
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/common/constants/uiElements.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@ export enum DropdownItemType {
customComponent = 'customComponent',
}

export enum AriaModalKind {
Basic = 'Basic',
AdvancedSearch = 'Advanced search',
}

export const MAX_SEARCH_BAR_WIDTH = 30;
6 changes: 6 additions & 0 deletions src/components/AdvancedSearchModal/AdvancedSearchModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { formatRawQuery, generateSearchParamsState } from '@common/helpers/search.helper';
import { Select } from '@components/Select';
import state from '@state';
import { AriaModalKind } from '@common/constants/uiElements.constants';
import './AdvancedSearchModal.scss';

enum AdvancedSearchInputs {
Expand Down Expand Up @@ -70,6 +71,7 @@ export const AdvancedSearchModal: FC<Props> = memo(({ clearValues }) => {
onCancel={closeModal}
shouldCloseOnEsc
submitButtonDisabled={submitButtonDisabled}
ariaModalKind={AriaModalKind.AdvancedSearch}
>
<div className="advanced-search-container">
{rawQuery.map(({ query, rowIndex, operator, qualifier, index }) => (
Expand All @@ -85,6 +87,7 @@ export const AdvancedSearchModal: FC<Props> = memo(({ clearValues }) => {
options={SELECT_OPERATORS}
className="cell-operator"
onChange={({ value }) => onChangeInput(value, AdvancedSearchInputs.Operator, rowIndex)}
ariaLabel={formatMessage({ id: 'ld.aria.advancedSearch.operator' })}
data-testid={`select-operators-${rowIndex}`}
/>
)}
Expand All @@ -93,13 +96,15 @@ export const AdvancedSearchModal: FC<Props> = memo(({ clearValues }) => {
data-testid={`text-input-${rowIndex}`}
value={query ?? ''}
onChange={({ target: { value } }) => onChangeInput(value, AdvancedSearchInputs.Query, rowIndex)}
ariaLabel={formatMessage({ id: 'ld.aria.advancedSearch.queryInput' })}
/>
<Select
withIntl
value={qualifier}
options={SELECT_QUALIFIERS}
className="cell-qualifier"
onChange={({ value }) => onChangeInput(value, AdvancedSearchInputs.Qualifier, rowIndex)}
ariaLabel={formatMessage({ id: 'ld.aria.advancedSearch.qualifier' })}
data-testid={`select-qualifiers-${rowIndex}`}
/>
in
Expand All @@ -109,6 +114,7 @@ export const AdvancedSearchModal: FC<Props> = memo(({ clearValues }) => {
options={SELECT_IDENTIFIERS}
className="cell-identifier"
onChange={({ value }) => onChangeInput(value, AdvancedSearchInputs.Index, rowIndex)}
ariaLabel={formatMessage({ id: 'ld.aria.advancedSearch.identifier' })}
data-testid={`select-identifiers-${rowIndex}`}
/>
</div>
Expand Down
10 changes: 8 additions & 2 deletions src/components/FullDisplay/PreviewContent.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useRecoilState } from 'recoil';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, useIntl } from 'react-intl';
import { RESOURCE_TEMPLATE_IDS } from '@common/constants/bibframe.constants';
import { generateEditResourceUrl } from '@common/helpers/navigation.helper';
import { useNavigateToEditPage } from '@common/hooks/useNavigateToEditPage';
Expand All @@ -11,6 +11,7 @@ import './FullDisplay.scss';

export const PreviewContent = () => {
const [previewContent, setPreviewContent] = useRecoilState(state.inputs.previewContent);
const { formatMessage } = useIntl();
const { navigateToEditPage } = useNavigateToEditPage();

return previewContent.map(({ id, base, userValues, initKey, title, entities }) => {
Expand All @@ -21,7 +22,12 @@ export const PreviewContent = () => {
return (
<div key={id}>
<div className="full-display-control-panel">
<Button className="close" data-testid="preview-remove" onClick={handleButtonClick}>
<Button
className="close"
data-testid="preview-remove"
onClick={handleButtonClick}
ariaLabel={formatMessage({ id: 'ld.aria.sections.closeResourcePreview' })}
>
<Times16 />
</Button>
<div className="info">
Expand Down
12 changes: 10 additions & 2 deletions src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { FC, ReactNode, memo, useEffect } from 'react';
import { createPortal } from 'react-dom';
import classNames from 'classnames';
import { MODAL_CONTAINER_ID } from '@common/constants/uiElements.constants';
import { AriaModalKind, MODAL_CONTAINER_ID } from '@common/constants/uiElements.constants';
import Times16 from '@src/assets/times-16.svg?react';
import { Button, ButtonType } from '@components/Button';
import './Modal.scss';
import { useIntl } from 'react-intl';
// TODO: UILD-147 - Uncomment for using with Shadow DOM
// import { WEB_COMPONENT_NAME } from '@common/constants/web-component';

Expand All @@ -26,6 +27,7 @@ interface Props {
showModalControls?: boolean;
titleClassName?: string;
alignTitleCenter?: boolean;
ariaModalKind?: string;
}

const Modal: FC<Props> = ({
Expand All @@ -46,7 +48,9 @@ const Modal: FC<Props> = ({
showModalControls = true,
titleClassName,
alignTitleCenter = false,
ariaModalKind = AriaModalKind.Basic,
}) => {
const { formatMessage } = useIntl();
const portalElement = document.getElementById(MODAL_CONTAINER_ID) as Element;
// TODO: UILD-147 - uncomment for using with Shadow DOM
// || (document.querySelector(WEB_COMPONENT_NAME)?.shadowRoot?.getElementById(MODAL_CONTAINER_ID) as Element)
Expand All @@ -70,7 +74,11 @@ const Modal: FC<Props> = ({
<div className={classNames(['modal', className])} role="dialog" data-testid="modal">
<div className={classNames(['modal-header', classNameHeader])}>
{showCloseIconButton && (
<button onClick={onClose} className="close-button">
<button
onClick={onClose}
className="close-button"
aria-label={formatMessage({ id: 'ld.aria.modal.close' }, { modalKind: ariaModalKind })}
>
<Times16 />
</button>
)}
Expand Down
11 changes: 9 additions & 2 deletions src/components/SearchResultEntry/SearchResultEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FC, useState } from 'react';
import { Link } from 'react-router-dom';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import classNames from 'classnames';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, useIntl } from 'react-intl';
import { WorkDetailsCard } from '@components/WorkDetailsCard';
import { Row, Table } from '@components/Table';
import { Button, ButtonType } from '@components/Button';
Expand Down Expand Up @@ -57,6 +57,7 @@ const instancesListHeader: Row = {
};

export const SearchResultEntry: FC<SearchResultEntry> = ({ instances, ...restOfWork }) => {
const { formatMessage } = useIntl();
const { navigateToEditPage } = useNavigateToEditPage();
const navigationState = useRecoilValue(state.search.navigationState);
const [isOpen, setIsOpen] = useState(true);
Expand Down Expand Up @@ -89,6 +90,7 @@ export const SearchResultEntry: FC<SearchResultEntry> = ({ instances, ...restOfW
type={ButtonType.Link}
onClick={() => handleOpenPreview(row?.__meta?.id)}
data-testid={`preview-button__${row.__meta.id}`}
ariaLabel={formatMessage({ id: 'ld.aria.sections.openResourcePreview' })}
>
{row.title.label}
</Button>
Expand All @@ -109,7 +111,12 @@ export const SearchResultEntry: FC<SearchResultEntry> = ({ instances, ...restOfW
selectCtl: {
children: (
<div className="row-select-container">
<input id={`row-select-ctl-${row.__meta?.key}`} type="checkbox" disabled={IS_DISABLED_FOR_ALPHA} />
<input
id={`row-select-ctl-${row.__meta?.key}`}
type="checkbox"
disabled={IS_DISABLED_FOR_ALPHA}
aria-label={formatMessage({ id: 'ld.aria.table.selectRow' })}
/>
</div>
),
},
Expand Down
6 changes: 3 additions & 3 deletions src/components/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Select = {
withIntl?: boolean;
className?: string;
ariaLabel?: string;
ariaLabelledby?: string;
ariaLabelledBy?: string;
[x: string]: any;
};

Expand All @@ -30,7 +30,7 @@ export const Select: FC<Select> = ({
withIntl = false,
className,
ariaLabel,
ariaLabelledby,
ariaLabelledBy,
...restProps
}) => {
const selectedValue = typeof value === 'string' ? value : value?.value;
Expand All @@ -48,7 +48,7 @@ export const Select: FC<Select> = ({
role="combobox"
aria-expanded="false"
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
aria-labelledby={ariaLabelledBy}
{...restProps}
>
{options.map(id => {
Expand Down
10 changes: 8 additions & 2 deletions src/components/WorkDetailsCard/WorkDetailsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FC } from 'react';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, useIntl } from 'react-intl';
import { generateEditResourceUrl } from '@common/helpers/navigation.helper';
import { useNavigateToEditPage } from '@common/hooks/useNavigateToEditPage';
import { Button, ButtonType } from '@components/Button';
Expand All @@ -28,6 +28,7 @@ export const WorkDetailsCard: FC<WorkDetailsCard> = ({
handleOpenPreview,
titles,
}) => {
const { formatMessage } = useIntl();
const { navigateToEditPage } = useNavigateToEditPage();
const title = getTitle(titles);
const creatorName = contributors?.find(({ isCreator }) => isCreator)?.name;
Expand All @@ -39,7 +40,12 @@ export const WorkDetailsCard: FC<WorkDetailsCard> = ({
return (
<div className="work-details-card">
<div className="heading">
<Button type={ButtonType.Ghost} onClick={toggleIsOpen} data-testid="work-details-card-toggle">
<Button
type={ButtonType.Ghost}
onClick={toggleIsOpen}
data-testid="work-details-card-toggle"
ariaLabel={formatMessage({ id: isOpen ? 'ld.aria.listEntry.close' : 'ld.aria.listEntry.open' })}
>
<CaretDown className={classNames({ ['icon-collapsed']: !isOpen }, 'toggle-icon')} />
</Button>
<div className="title">
Expand Down
10 changes: 10 additions & 0 deletions translations/ui-linked-data/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,18 @@
"ld.selectBrowseOption": "Select a browse option",
"ld.searchQueryWouldBeHere": "{query} would be here",
"ld.continue": "Continue",
"ld.aria.modal.close": "Close {modalKind} modal",
"ld.aria.advancedSearch.queryInput": "Advanced search row query input",
"ld.aria.advancedSearch.operator": "Advanced search row operator",
"ld.aria.advancedSearch.qualifier": "Advanced search row qualifier",
"ld.aria.advancedSearch.identifier": "Advanced search row identifier",
"ld.aria.filters.select": "Select search identifiers",
"ld.aria.listEntry.open": "Open collapsible list entry",
"ld.aria.listEntry.close": "Close collapsible list entry",
"ld.aria.filters.textbox": "Search query textbox",
"ld.aria.table.selectRow": "Select table row",
"ld.aria.sections.openResourcePreview": "Open resource preview section",
"ld.aria.sections.closeResourcePreview": "Close resource preview section",
"ld.aria.filters.reset": "Reset filters button",
"ld.aria.filters.reset.announce": "Search field and filters are reset",
"ld.duplicateImportWarn": "Duplicate import warning",
Expand Down

0 comments on commit 3b16dc5

Please sign in to comment.