mirror of https://github.com/laurent22/joplin.git
Desktop: Accessibility: Improve sync wizard accessibility (#11649)
parent
e1b41cff5f
commit
e8e3ef36ed
|
@ -38,6 +38,7 @@ interface Props {
|
|||
fontSize?: number;
|
||||
|
||||
'aria-controls'?: string;
|
||||
'aria-describedby'?: string;
|
||||
'aria-expanded'?: string;
|
||||
}
|
||||
|
||||
|
@ -263,6 +264,7 @@ const Button = React.forwardRef((props: Props, ref: any) => {
|
|||
aria-disabled={props.disabled}
|
||||
aria-expanded={props['aria-expanded']}
|
||||
aria-controls={props['aria-controls']}
|
||||
aria-describedby={props['aria-describedby']}
|
||||
>
|
||||
{renderIcon()}
|
||||
{renderTitle()}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import styled from 'styled-components';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const Root = styled.div<any>`
|
||||
const Root = styled.h1<any>`
|
||||
display: flex;
|
||||
justify-content: ${props => props.justifyContent ? props.justifyContent : 'center'};
|
||||
font-family: ${props => props.theme.fontFamily};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import { useRef, useCallback } from 'react';
|
||||
import { useRef, useCallback, useId } from 'react';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import DialogButtonRow from '../DialogButtonRow';
|
||||
import Dialog from '../Dialog';
|
||||
|
@ -49,7 +49,7 @@ const SyncTargetBoxes = styled.div`
|
|||
justify-content: center;
|
||||
`;
|
||||
|
||||
const SyncTargetTitle = styled.p`
|
||||
const SyncTargetTitle = styled.h2`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-weight: bold;
|
||||
|
@ -78,8 +78,11 @@ const SyncTargetBox = styled.div`
|
|||
opacity: 1;
|
||||
`;
|
||||
|
||||
const FeatureList = styled.div`
|
||||
const FeatureList = styled.ul`
|
||||
margin-bottom: 1em;
|
||||
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
`;
|
||||
|
||||
const FeatureIcon = styled.i`
|
||||
|
@ -90,7 +93,7 @@ const FeatureIcon = styled.i`
|
|||
position: absolute;
|
||||
`;
|
||||
|
||||
const FeatureLine = styled.div<{ enabled: boolean }>`
|
||||
const FeatureLine = styled.li<{ enabled: boolean }>`
|
||||
margin-bottom: .5em;
|
||||
opacity: ${props => props.enabled ? 1 : 0.5};
|
||||
position: relative;
|
||||
|
@ -156,7 +159,10 @@ export default function(props: Props) {
|
|||
function renderFeature(enabled: boolean, label: string) {
|
||||
const className = enabled ? 'fas fa-check' : 'fas fa-times';
|
||||
return (
|
||||
<FeatureLine enabled={enabled} key={label}><FeatureIcon className={className}></FeatureIcon> <FeatureLabel>{label}</FeatureLabel></FeatureLine>
|
||||
<FeatureLine enabled={enabled} key={label}>
|
||||
<FeatureIcon className={className} role='img' aria-label={enabled ? _('Check') : _('Not checked')}/>
|
||||
<FeatureLabel>{label}</FeatureLabel>
|
||||
</FeatureLine>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -190,13 +196,16 @@ export default function(props: Props) {
|
|||
});
|
||||
}, [props.dispatch, closeDialog]);
|
||||
|
||||
function renderSelectArea(info: SyncTargetInfo) {
|
||||
const baseId = useId();
|
||||
|
||||
function renderSelectArea(info: SyncTargetInfo, describedById: string) {
|
||||
return (
|
||||
<SelectButton
|
||||
level={ButtonLevel.Primary}
|
||||
title={_('Select')}
|
||||
onClick={() => onSelectButtonClick(info.name as SyncTargetInfoName)}
|
||||
disabled={false}
|
||||
aria-describedby={describedById}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -207,8 +216,14 @@ export default function(props: Props) {
|
|||
|
||||
const logoImageName = logosImageNames[info.name];
|
||||
const logoImageSrc = logoImageName ? `${bridge().buildDir()}/images/${logoImageName}` : '';
|
||||
const logo = logoImageSrc ? <SyncTargetLogo src={logoImageSrc}/> : null;
|
||||
const descriptionComp = <SyncTargetDescription height={height} ref={info.name === 'joplinCloud' ? joplinCloudDescriptionRef : null}>{info.description}</SyncTargetDescription>;
|
||||
const logo = logoImageSrc ? <SyncTargetLogo src={logoImageSrc} aria-hidden={true}/> : null;
|
||||
|
||||
const descriptionComp = (
|
||||
<SyncTargetDescription
|
||||
height={height}
|
||||
ref={info.name === 'joplinCloud' ? joplinCloudDescriptionRef : null}
|
||||
>{info.description}</SyncTargetDescription>
|
||||
);
|
||||
const featuresComp = renderFeatures(info.name);
|
||||
|
||||
const renderSlowSyncWarning = () => {
|
||||
|
@ -216,12 +231,13 @@ export default function(props: Props) {
|
|||
return <SlowSyncWarning>{`⚠️ ${_('%s is not optimised for synchronising many small files so your initial synchronisation will be slow.', info.label)}`}</SlowSyncWarning>;
|
||||
};
|
||||
|
||||
const headerId = `${baseId}-${info.id}`;
|
||||
return (
|
||||
<SyncTargetBox id={key} key={key}>
|
||||
<SyncTargetTitle>{logo}{info.label}</SyncTargetTitle>
|
||||
<SyncTargetTitle id={headerId}>{logo}{info.label}</SyncTargetTitle>
|
||||
{descriptionComp}
|
||||
{featuresComp}
|
||||
{renderSelectArea(info)}
|
||||
{renderSelectArea(info, headerId)}
|
||||
{renderSlowSyncWarning()}
|
||||
</SyncTargetBox>
|
||||
);
|
||||
|
@ -249,7 +265,26 @@ export default function(props: Props) {
|
|||
boxes.push(renderSyncTarget(info));
|
||||
}
|
||||
|
||||
const selfHostingMessage = <SelfHostingMessage>Self-hosting? Joplin also supports various self-hosting options such as Nextcloud, WebDAV, AWS S3 and Joplin Server. <a href="#" onClick={onSelfHostingClick}>Click here to select one</a>.</SelfHostingMessage>;
|
||||
const selfHostingLabelId = `${baseId}-selfHosting`;
|
||||
const selfHostingLinkId = `${baseId}-selfHostingLink`;
|
||||
const selfHostingMessage = <SelfHostingMessage>
|
||||
<span id={selfHostingLabelId}>
|
||||
Self-hosting? Joplin also supports various self-hosting options such as Nextcloud, WebDAV, AWS S3 and Joplin Server.
|
||||
</span>
|
||||
{' '}
|
||||
<a
|
||||
href="#"
|
||||
onClick={onSelfHostingClick}
|
||||
|
||||
// Include the link ID in aria-labelledby to include the link text in the
|
||||
// description. See
|
||||
// https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA7
|
||||
id={selfHostingLinkId}
|
||||
aria-labelledby={`${selfHostingLabelId} ${selfHostingLinkId}`}
|
||||
>
|
||||
Click here to select one
|
||||
</a>.
|
||||
</SelfHostingMessage>;
|
||||
|
||||
return (
|
||||
<ContentRoot>
|
||||
|
|
Loading…
Reference in New Issue