fix(accessibility): tab support at login, reset and signup pages, buttons at ATE and app bar (#24214)

Этот коммит содержится в:
Saturnino Abril
2023-08-10 08:53:13 -04:00
коммит произвёл GitHub
родитель 45a14e23a9
Коммит ecf7cdbdea
26 изменённых файлов: 441 добавлений и 87 удалений

Просмотреть файл

@@ -71,6 +71,7 @@ export const IconContainer = styled.button`
`;
interface FormattingIconProps {
id?: string;
mode: MarkdownMode;
onClick?: () => void;
className?: string;
@@ -129,7 +130,7 @@ const FormattingIcon = (props: FormattingIconProps): JSX.Element => {
const bodyAction = (
<IconContainer
type='button'
id={`FormattingControl_${mode}`}
id={props.id || `FormattingControl_${mode}`}
onClick={onClick}
aria-label={buttonAriaLabel}
{...otherProps}

Просмотреть файл

@@ -50,6 +50,7 @@ const AlertBanner = ({
children,
}: AlertBannerProps) => {
const {formatMessage} = useIntl();
const closeText = formatMessage({id: 'alert_banner.tooltipCloseBtn', defaultMessage: 'Close'});
const [tooltipId] = useState(`alert_banner_close_btn_tooltip_${Math.random()}`);
const bannerIcon = useCallback(() => {
@@ -110,12 +111,11 @@ const AlertBanner = ({
delayShow={Constants.OVERLAY_TIME_DELAY}
placement='left'
overlay={closeBtnTooltip || (
<Tooltip id={tooltipId}>
{formatMessage({id: 'alert_banner.tooltipCloseBtn', defaultMessage: 'Close'})}
</Tooltip>
<Tooltip id={tooltipId}>{closeText}</Tooltip>
)}
>
<button
aria-label={closeText}
className='AlertBanner__closeButton'
onClick={onDismiss}
>

Просмотреть файл

@@ -76,6 +76,8 @@ exports[`components/app_bar/app_bar should match snapshot on mount 1`] = `
>
<div
className="app-bar__old-icon app-bar__icon-inner app-bar__icon-inner--centered"
role="button"
tabIndex={0}
>
fallback_component
</div>
@@ -241,6 +243,8 @@ exports[`components/app_bar/app_bar should match snapshot on mount when App Bar
>
<div
className="app-bar__old-icon app-bar__icon-inner app-bar__icon-inner--centered"
role="button"
tabIndex={0}
>
fallback_component
</div>

Просмотреть файл

@@ -64,7 +64,11 @@ const AppBarPluginComponent = (props: PluginComponentProps) => {
const iconUrl = component.iconUrl;
let content: React.ReactNode = (
<div className='app-bar__icon-inner'>
<div
role='button'
tabIndex={0}
className='app-bar__icon-inner'
>
<img
src={iconUrl}
onLoad={onImageLoadComplete}
@@ -77,7 +81,11 @@ const AppBarPluginComponent = (props: PluginComponentProps) => {
if (!iconUrl) {
content = (
<div className={classNames('app-bar__old-icon app-bar__icon-inner app-bar__icon-inner--centered', {'app-bar__old-icon--active': isButtonActive})}>
<div
role='button'
tabIndex={0}
className={classNames('app-bar__old-icon app-bar__icon-inner app-bar__icon-inner--centered', {'app-bar__old-icon--active': isButtonActive})}
>
{component.icon}
</div>
);

Просмотреть файл

@@ -25,11 +25,9 @@ const BackButton = ({url, className, onClick}: Props): JSX.Element => {
const {formatMessage} = useIntl();
return (
<div
id='back_button'
className={classNames('signup-header', className)}
>
<div className={classNames('signup-header', className)}>
<Link
data-testid='back_button'
onClick={onClick}
to={url}
>

Просмотреть файл

@@ -43,10 +43,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with about link 1
key="about_link"
location="header_footer_template"
>
<MemoizedFormattedMessage
defaultMessage="About"
id="web.footer.about"
/>
About
</ExternalLink>
</span>
</div>
@@ -98,10 +95,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with all links 1`
key="about_link"
location="header_footer_template"
>
<MemoizedFormattedMessage
defaultMessage="About"
id="web.footer.about"
/>
About
</ExternalLink>
<ExternalLink
className="footer-link"
@@ -110,10 +104,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with all links 1`
key="privacy_link"
location="header_footer_template"
>
<MemoizedFormattedMessage
defaultMessage="Privacy Policy"
id="web.footer.privacy"
/>
Privacy Policy
</ExternalLink>
<ExternalLink
className="footer-link"
@@ -122,10 +113,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with all links 1`
key="terms_link"
location="header_footer_template"
>
<MemoizedFormattedMessage
defaultMessage="Terms"
id="web.footer.terms"
/>
Terms
</ExternalLink>
<ExternalLink
className="footer-link"
@@ -134,10 +122,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with all links 1`
key="help_link"
location="header_footer_template"
>
<MemoizedFormattedMessage
defaultMessage="Help"
id="web.footer.help"
/>
Help
</ExternalLink>
</span>
</div>
@@ -235,10 +220,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with help link 1`
key="help_link"
location="header_footer_template"
>
<MemoizedFormattedMessage
defaultMessage="Help"
id="web.footer.help"
/>
Help
</ExternalLink>
</span>
</div>
@@ -290,10 +272,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with privacy poli
key="privacy_link"
location="header_footer_template"
>
<MemoizedFormattedMessage
defaultMessage="Privacy Policy"
id="web.footer.privacy"
/>
Privacy Policy
</ExternalLink>
</span>
</div>
@@ -345,10 +324,7 @@ exports[`components/HeaderFooterTemplate should match snapshot with term of serv
key="terms_link"
location="header_footer_template"
>
<MemoizedFormattedMessage
defaultMessage="Terms"
id="web.footer.terms"
/>
Terms
</ExternalLink>
</span>
</div>

Просмотреть файл

@@ -3,10 +3,10 @@
import PropTypes from 'prop-types';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {ClientConfig} from '@mattermost/types/config';
import ExternalLink from 'components/external_link';
import {localizeMessage} from 'utils/utils';
type Props = {
config: Partial<ClientConfig> | undefined;
@@ -57,10 +57,7 @@ export default class NotLoggedIn extends React.PureComponent<Props> {
location='header_footer_template'
href={this.props.config.AboutLink}
>
<FormattedMessage
id='web.footer.about'
defaultMessage='About'
/>
{localizeMessage('web.footer.about', 'About')}
</ExternalLink>,
);
}
@@ -74,10 +71,7 @@ export default class NotLoggedIn extends React.PureComponent<Props> {
location='header_footer_template'
href={this.props.config.PrivacyPolicyLink}
>
<FormattedMessage
id='web.footer.privacy'
defaultMessage='Privacy Policy'
/>
{localizeMessage('web.footer.privacy', 'Privacy Policy')}
</ExternalLink>,
);
}
@@ -91,10 +85,7 @@ export default class NotLoggedIn extends React.PureComponent<Props> {
location='header_footer_template'
href={this.props.config.TermsOfServiceLink}
>
<FormattedMessage
id='web.footer.terms'
defaultMessage='Terms'
/>
{localizeMessage('web.footer.terms', 'Terms')}
</ExternalLink>,
);
}
@@ -108,10 +99,7 @@ export default class NotLoggedIn extends React.PureComponent<Props> {
location='header_footer_template'
href={this.props.config.HelpLink}
>
<FormattedMessage
id='web.footer.help'
defaultMessage='Help'
/>
{localizeMessage('web.footer.help', 'Help')}
</ExternalLink>,
);
}

Просмотреть файл

@@ -363,8 +363,6 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
const onWindowFocus = useCallback(() => {
if (extraParam === Constants.SIGNIN_VERIFIED && emailParam) {
passwordInput.current?.focus();
} else {
loginIdInput.current?.focus();
}
}, [emailParam, extraParam]);

Просмотреть файл

@@ -97,6 +97,7 @@ function PostPriorityPickerOverlay({
{...getTooltipReferenceProps()}
>
<IconContainer
id='messagePriority'
ref={pickerRef}
className={classNames({control: true, active: pickerOpen})}
disabled={disabled}

Просмотреть файл

@@ -594,6 +594,7 @@ const Signup = ({onCustomizeHeader}: SignupProps) => {
return (
<CheckInput
id='signup-body-card-form-check-newsletter'
ariaLabel={formatMessage({id: 'newsletter_optin.checkmark.box', defaultMessage: 'newsletter checkbox'})}
name='newsletter'
onChange={() => setSubscribeToSecurityNewsletter(!subscribeToSecurityNewsletter)}
text={

Просмотреть файл

@@ -6,6 +6,7 @@ import './check.scss';
type Props = {
id: string;
ariaLabel: string;
name: string;
text: ReactNode;
onChange: () => void;
@@ -13,14 +14,17 @@ type Props = {
}
function CheckInput(props: Props) {
const {id, ariaLabel, text, ...rest} = props;
return (
<div className='check-input'>
<input
{...props}
data-testid={props.id}
{...rest}
aria-label={ariaLabel}
data-testid={id}
type='checkbox'
/>
<span className='text'>{props.text}</span>
<span className='text'>{text}</span>
</div>
);
}

Просмотреть файл

@@ -66,7 +66,7 @@ const PasswordInput = React.forwardRef((
<button
id='password_toggle'
type='button'
aria-label={placeHolder}
aria-label={formatMessage({id: 'widget.passwordInput.passwordToggle', defaultMessage: 'Show or hide password'})}
className='password-input-toggle'
onClick={toggleShowPassword}
disabled={disabled}

Просмотреть файл

@@ -4100,6 +4100,7 @@
"navbar.viewPinnedPosts": "View Pinned Posts",
"newChannelWithBoard.tutorialTip.description": "The board you just created can be quickly accessed by clicking on the Boards icon in the App bar. You can view the boards that are linked to this channel in the right-hand sidebar and open one in full view.",
"newChannelWithBoard.tutorialTip.title": "Access linked boards from the App Bar",
"newsletter_optin.checkmark.box": "newsletter checkbox",
"newsletter_optin.checkmark.text": "<span>I would like to receive Mattermost security updates via newsletter.</span> By subscribing, I consent to receive emails from Mattermost with product updates, promotions, and company news. I have read the <a>Privacy Policy</a> and understand that I can <aa>unsubscribe</aa> at any time",
"newsletter_optin.desc": "Sign up at <a>{link}</a>.",
"newsletter_optin.title": "Interested in receiving Mattermost security, product, promotions, and company updates updates via newsletter?",
@@ -5589,6 +5590,7 @@
"widget.input.required": "This field is required",
"widget.passwordInput.createPassword": "Choose a Password",
"widget.passwordInput.password": "Password",
"widget.passwordInput.passwordToggle": "Show or hide password",
"widgets.channels_input.empty": "No channels found",
"widgets.channels_input.loading": "Loading",
"widgets.users_emails_input.loading": "Loading",