Skip to content

Commit

Permalink
a11y: UILD-454: Improve WCAG 2.1 AA compliance for Edit page (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
s3fs authored Dec 13, 2024
1 parent 3d76d20 commit 253452e
Show file tree
Hide file tree
Showing 15 changed files with 79 additions and 32 deletions.
3 changes: 2 additions & 1 deletion src/components/ComplexLookupField/ComplexLookupField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface Props {
}

export const ComplexLookupField: FC<Props> = ({ value = undefined, id, entry, onChange }) => {
const { layout } = entry;
const { layout, htmlId } = entry;
const lookupConfig = COMPLEX_LOOKUPS_CONFIG[layout?.api as string];
const buttonConfigLabel = lookupConfig?.labels?.button;

Expand Down Expand Up @@ -86,6 +86,7 @@ export const ComplexLookupField: FC<Props> = ({ value = undefined, id, entry, on
value={localValue?.map(({ label }) => label).join(VALUE_DIVIDER) ?? ''}
disabled={true}
data-testid="complex-lookup-input"
ariaLabelledBy={htmlId}
/>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { FC } from 'react';
import { useRecoilValue } from 'recoil';
import { FormattedDate, FormattedMessage } from 'react-intl';
import { FormattedDate, FormattedMessage, useIntl } from 'react-intl';
import { useSearchContext } from '@common/hooks/useSearchContext';
import { SearchControlPane } from '@components/SearchControlPane';
import { MarcContent } from '@components/MarcContent';
Expand All @@ -15,6 +15,7 @@ type MarcPreviewComplexLookupProps = {

export const MarcPreviewComplexLookup: FC<MarcPreviewComplexLookupProps> = ({ onClose }) => {
const { onAssignRecord } = useSearchContext();
const { formatMessage } = useIntl();
const isMarcPreviewOpen = useRecoilValue(state.ui.isMarcPreviewOpen);
const marcPreviewData = useRecoilValue(state.data.marcPreviewData);
const marcPreviewMetadata = useRecoilValue(state.data.marcPreviewMetadata);
Expand Down Expand Up @@ -52,7 +53,11 @@ export const MarcPreviewComplexLookup: FC<MarcPreviewComplexLookupProps> = ({ on
renderCloseButton={renderCloseButton}
>
<div>
<Button type={ButtonType.Highlighted} onClick={onClickAssignButton}>
<Button
type={ButtonType.Highlighted}
onClick={onClickAssignButton}
ariaLabel={formatMessage({ id: 'ld.aria.marcAuthorityPreview.close' })}
>
<FormattedMessage id="ld.assign" />
</Button>
</div>
Expand Down
3 changes: 3 additions & 0 deletions src/components/DropdownField/DropdownField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface IDropdownField {
onChange: (value: ReactSelectOption, fieldId: string, isDynamicField?: boolean) => void;
value?: ReactSelectOption;
isDisabled?: boolean;
htmlId?: string;
id?: string;
'data-testid'?: string;
}
Expand All @@ -15,6 +16,7 @@ export const DropdownField: FC<IDropdownField> = ({
options,
uuid,
id,
htmlId,
onChange,
value,
isDisabled = false,
Expand All @@ -40,6 +42,7 @@ export const DropdownField: FC<IDropdownField> = ({
disabled={isDisabled}
className="edit-section-field-input dropdown-field"
data-testid={testId}
ariaLabelledby={htmlId}
/>
);
};
41 changes: 24 additions & 17 deletions src/components/DuplicateGroup/DuplicateGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Trash16 from '@src/assets/trash-16.svg?react';
import { getHtmlIdForSchemaControl } from '@common/helpers/schema.helper';
import { SchemaControlType } from '@common/constants/uiControls.constants';
import './DuplicateGroup.scss';
import { useIntl } from 'react-intl';

interface Props {
onClickDuplicate?: VoidFunction;
Expand All @@ -17,25 +18,31 @@ interface Props {
}

export const DuplicateGroup: FC<Props> = memo(
({ onClickDuplicate, onClickDelete, hasDeleteButton = true, className, htmlId, deleteDisabled = true }) => (
<div className={classNames(['duplicate-group', className])}>
<Button
data-testid={getHtmlIdForSchemaControl(SchemaControlType.Duplicate, htmlId)}
type={ButtonType.Icon}
onClick={onClickDuplicate}
>
<Plus16 />
</Button>
{hasDeleteButton && (
({ onClickDuplicate, onClickDelete, hasDeleteButton = true, className, htmlId, deleteDisabled = true }) => {
const { formatMessage } = useIntl();

return (
<div className={classNames(['duplicate-group', className])}>
<Button
data-testid={getHtmlIdForSchemaControl(SchemaControlType.RemoveDuplicate, htmlId)}
data-testid={getHtmlIdForSchemaControl(SchemaControlType.Duplicate, htmlId)}
type={ButtonType.Icon}
disabled={deleteDisabled}
onClick={onClickDelete}
onClick={onClickDuplicate}
ariaLabel={formatMessage({ id: 'ld.aria.edit.duplicateComponent' })}
>
<Trash16 />
<Plus16 />
</Button>
)}
</div>
),
{hasDeleteButton && (
<Button
data-testid={getHtmlIdForSchemaControl(SchemaControlType.RemoveDuplicate, htmlId)}
type={ButtonType.Icon}
disabled={deleteDisabled}
onClick={onClickDelete}
ariaLabel={formatMessage({ id: 'ld.aria.edit.deleteComponent' })}
>
<Trash16 />
</Button>
)}
</div>
);
},
);
4 changes: 3 additions & 1 deletion src/components/EditControlPane/EditControlPane.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, useIntl } from 'react-intl';
import { Dropdown } from '@components/Dropdown';
import { DropdownItemType } from '@common/constants/uiElements.constants';
import { RESOURCE_CREATE_URLS } from '@common/constants/routes.constants';
Expand Down Expand Up @@ -31,6 +31,7 @@ export const EditControlPane = () => {
const { navigateAsDuplicate } = useNavigateToEditPage();
const [queryParams] = useSearchParams();
const { fetchMarcData } = useMarcData(state.data.marcPreview);
const { formatMessage } = useIntl();

const handleFetchMarcData = async () => fetchMarcData(resourceId);

Expand Down Expand Up @@ -85,6 +86,7 @@ export const EditControlPane = () => {
navigate(searchResultsUri);
}}
className="nav-close"
ariaLabel={formatMessage({ id: 'ld.aria.edit.close' })}
>
<Times16 />
</Button>
Expand Down
5 changes: 4 additions & 1 deletion src/components/EditSection/DrawComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const DrawComponent: FC<IDrawComponent & EditSectionDataProps> = ({
onChange,
handleGroupsCollapseExpand,
}) => {
const { uuid, displayName = '', type, children, constraints } = entry;
const { uuid, displayName = '', type, children, constraints, htmlId } = entry;
const isDisabled = !!disabledFields?.get(uuid);
const displayNameWithAltValue = EDIT_ALT_DISPLAY_LABELS[displayName] || displayName;
const selectedUserValue = userValues[uuid];
Expand Down Expand Up @@ -77,6 +77,7 @@ export const DrawComponent: FC<IDrawComponent & EditSectionDataProps> = ({
<FieldWithMetadataAndControls entry={entry} level={level} isCompact={isCompact}>
<LiteralField
uuid={uuid}
htmlId={htmlId}
value={selectedUserValue?.contents[0].label}
onChange={onChange}
isDisabled={isDisabled}
Expand Down Expand Up @@ -108,6 +109,7 @@ export const DrawComponent: FC<IDrawComponent & EditSectionDataProps> = ({
<DropdownField
options={options}
uuid={uuid}
htmlId={htmlId}
onChange={handleChange}
value={selectedOption}
isDisabled={isDisabled || entry?.layout?.readOnly}
Expand All @@ -129,6 +131,7 @@ export const DrawComponent: FC<IDrawComponent & EditSectionDataProps> = ({
<SimpleLookupField
uri={constraints?.useValuesFrom[0] ?? ''}
uuid={uuid}
htmlId={htmlId}
onChange={onChange}
parentUri={constraints?.valueDataType?.dataTypeURI}
value={selectedUserValue?.contents}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ export const CompactLayout: FC<ICompactLayout> = memo(
}) => {
return (
<>
{displayName && showLabel && <div className={classNames('label', labelContainerClassName)}>{displayName}</div>}
{displayName && showLabel && (
<div id={htmlId} className={classNames('label', labelContainerClassName)}>
{displayName}
</div>
)}
<div className="children-container" data-testid={htmlId}>
{children}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const ExtendedLayout: FC<IExtendedLayout> = memo(
}) => {
return (
<>
<div className={classNames({ 'extended-layout-meta': hasDuplicateGroupButton })}>
<div id={htmlId} className={classNames({ 'extended-layout-meta': hasDuplicateGroupButton })}>
{displayName && showLabel && (
<div className={classNames('label', labelContainerClassName)}>{displayName}</div>
)}
Expand Down
3 changes: 3 additions & 0 deletions src/components/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type InputProps = {
onPressEnter?: VoidFunction;
type?: HTMLInputTypeAttribute;
ariaLabel?: string;
ariaLabelledBy?: string;
role?: string;
[x: string]: any;
};
Expand All @@ -26,6 +27,7 @@ export const Input: FC<InputProps> = ({
onPressEnter,
type = 'text',
ariaLabel,
ariaLabelledBy,
role = 'textbox',
...restProps
}) => {
Expand All @@ -46,6 +48,7 @@ export const Input: FC<InputProps> = ({
}}
type={type}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
role={role}
{...restProps}
/>
Expand Down
3 changes: 3 additions & 0 deletions src/components/LiteralField/LiteralField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Input } from '@components/Input';

interface ILiteralField {
uuid: string;
htmlId?: string;
value?: string;
isDisabled?: boolean;
id?: string;
Expand All @@ -12,6 +13,7 @@ interface ILiteralField {

export const LiteralField: FC<ILiteralField> = ({
uuid,
htmlId,
value = '',
id,
isDisabled = false,
Expand All @@ -34,6 +36,7 @@ export const LiteralField: FC<ILiteralField> = ({
onChange={handleOnChange}
value={localValue}
disabled={isDisabled}
ariaLabelledBy={htmlId}
/>
);
};
14 changes: 9 additions & 5 deletions src/components/Preview/TitledPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button, ButtonType } from '@components/Button';
import { Preview } from './Preview';
import { PreviewActionsDropdown } from '@components/PreviewActionsDropdown';
import Times16 from '@src/assets/times-16.svg?react';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, useIntl } from 'react-intl';
import { ResourceType } from '@common/constants/record.constants';
import { useNavigateToEditPage } from '@common/hooks/useNavigateToEditPage';
import { generateEditResourceUrl } from '@common/helpers/navigation.helper';
Expand All @@ -25,21 +25,25 @@ export const TitledPreview = ({
previewContent,
onClickClose,
}: ITitledPreview) => {
const { formatMessage } = useIntl();
const { navigateToEditPage } = useNavigateToEditPage();
const { title, id, base, initKey, userValues } = previewContent ?? {};
const selectedOwnId = id ?? ownId;
const withPreviewContent = (
<>
{showCloseCtl ? (
<Button data-testid="nav-close-button" type={ButtonType.Icon} onClick={onClickClose}>
<Button
data-testid="nav-close-button"
type={ButtonType.Icon}
onClick={onClickClose}
ariaLabel={formatMessage({ id: 'ld.aria.resourcePreview.close' })}
>
<Times16 />
</Button>
) : (
<span className="empty-block" />
)}
<div className="details">
{title && <h5>{title}</h5>}
</div>
<div className="details">{title && <h5>{title}</h5>}</div>
</>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { useRecoilValue } from 'recoil';
import state from '@state';
import { getRecordTitle } from '@common/helpers/record.helper';
import { useContainerEvents } from '@common/hooks/useContainerEvents';
import { useIntl } from 'react-intl';

export const PreviewExternalResourcePane = () => {
const record = useRecoilValue(state.inputs.record);
const { dispatchNavigateToOriginEventWithFallback } = useContainerEvents();
const { formatMessage } = useIntl();

return (
<div className="nav-block nav-block-fixed-height">
Expand All @@ -17,13 +19,12 @@ export const PreviewExternalResourcePane = () => {
type={ButtonType.Icon}
onClick={dispatchNavigateToOriginEventWithFallback}
className="nav-close"
ariaLabel={formatMessage({ id: 'ld.aria.externalResourcePreview.close' })}
>
<Times16 />
</Button>
</nav>
<div className="heading">
{record && getRecordTitle(record)}
</div>
<div className="heading">{record && getRecordTitle(record)}</div>
<span className="empty-block" />
</div>
);
Expand Down
3 changes: 3 additions & 0 deletions src/components/SimpleLookupField/SimpleLookupField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface Props {
uri: string;
uuid: string;
value?: UserValueContents[];
htmlId?: string;
parentUri?: string;
isDisabled?: boolean;
id?: string;
Expand All @@ -35,6 +36,7 @@ export const SimpleLookupField: FC<Props> = ({
uuid,
id,
value,
htmlId,
onChange,
parentUri,
isDisabled = false,
Expand Down Expand Up @@ -96,6 +98,7 @@ export const SimpleLookupField: FC<Props> = ({
return (
<CreatableSelect
id={id}
aria-labelledby={htmlId}
ref={simpleLookupRef}
className="edit-section-field-input simple-lookup"
classNamePrefix="simple-lookup"
Expand Down
1 change: 1 addition & 0 deletions src/components/ViewMarcControlPane/ViewMarcControlPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const ViewMarcControlPane = () => {
type={ButtonType.Icon}
onClick={resetMarcPreviewData}
className="nav-close"
ariaLabel={formatMessage({ id: 'ld.aria.marcPreview.close' })}
>
<Times16 />
</Button>
Expand Down
7 changes: 7 additions & 0 deletions translations/ui-linked-data/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@
"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.edit.close": "Close edit page",
"ld.aria.edit.deleteComponent": "Delete component",
"ld.aria.edit.duplicateComponent": "Duplicate component",
"ld.aria.resourcePreview.close": "Close resource preview pane",
"ld.aria.externalResourcePreview.close": "Close external resource preview page",
"ld.aria.marcAuthorityPreview.close": "Close MARC authority preview",
"ld.aria.marcPreview.close": "Close MARC preview modal",
"ld.aria.filters.textbox": "Search query textbox",
"ld.aria.table.selectRow": "Select table row",
"ld.aria.sections.openResourcePreview": "Open resource preview section",
Expand Down

0 comments on commit 253452e

Please sign in to comment.