[MM-61598]: Fix ARIA roles, states, and properties are valid in user profile image and @user buttons (#29692)

* [MA-26]: Fix ARIA roles, states, and properties are valid in user profile image and @user buttons

* [MA-26]: Remove irrelevant e2e tests

* [MA-26]: Remove nested interactive elements

* [MA-26]: Updated mention-link styles

* Minor change

---------

Co-authored-by: ayush-chauhan233 <ayush.chauhan@brightscout.com>
Этот коммит содержится в:
Saurabh Sharma
2025-02-03 00:20:01 +05:30
коммит произвёл GitHub
родитель 8fdb9ad358
Коммит 28dbc3cabb
11 изменённых файлов: 333 добавлений и 348 удалений

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

@@ -8,26 +8,23 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match d
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/1234/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/1234/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>
@@ -69,26 +66,23 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match s
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/1234/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/1234/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>
@@ -125,26 +119,23 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match s
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/1234/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/1234/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>
@@ -179,26 +170,23 @@ exports[`components/admin_console/admin_user_card/admin_user_card should match s
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/1234/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/1234/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>

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

@@ -28,26 +28,23 @@ exports[`SystemUserDetail should match default snapshot 1`] = `
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>
@@ -240,26 +237,23 @@ exports[`SystemUserDetail should match snapshot if MFA is enabled 1`] = `
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>
@@ -452,26 +446,23 @@ exports[`SystemUserDetail should not show manage user settings button when user
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>
@@ -664,26 +655,23 @@ exports[`SystemUserDetail should show manage user settings button as activated 1
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>
@@ -881,26 +869,23 @@ exports[`SystemUserDetail should show manage user settings button as disabled wh
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>
@@ -1093,26 +1078,23 @@ exports[`SystemUserDetail should show the activate user button as disabled when
<div
class="AdminUserCard__header"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
class="status-wrapper admin-user-card"
class="status-wrapper style--none admin-user-card"
style="border-radius: 50%; width: 128px; height: 128px;"
>
<button
class="RoundButton-dvlhqG gnYSKj style--none"
<span
class="profile-icon "
>
<span
class="profile-icon "
>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
</span>
<img
alt="user profile image"
class="Avatar Avatar-xxl"
loading="lazy"
src="/api/v4/users/user_id/image"
/>
</span>
</button>
<div
class="AdminUserCard__user-info"
>

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

@@ -96,16 +96,15 @@ exports[`components/AtMention should match snapshot when mentioning current user
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc1/image"
triggerComponentClass="mention--highlight"
triggerComponentAs="button"
triggerComponentClass="style--none mention--highlight"
userId="abc1"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@First Last
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;
@@ -115,16 +114,15 @@ exports[`components/AtMention should match snapshot when mentioning user 1`] = `
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc2/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc2"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Nick
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;
@@ -134,16 +132,15 @@ exports[`components/AtMention should match snapshot when mentioning user contain
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc3/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc3"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Dot Matrix
</a>
</span>
</ProfilePopoverController>
.
</Fragment>
@@ -154,16 +151,15 @@ exports[`components/AtMention should match snapshot when mentioning user contain
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc3/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc3"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Dot Matrix
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;
@@ -173,16 +169,15 @@ exports[`components/AtMention should match snapshot when mentioning user followe
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc2/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc2"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Nick
</a>
</span>
</ProfilePopoverController>
...
</Fragment>
@@ -193,16 +188,15 @@ exports[`components/AtMention should match snapshot when mentioning user with di
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc2/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc2"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@user1
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;
@@ -212,16 +206,15 @@ exports[`components/AtMention should match snapshot when mentioning user with mi
<ProfilePopoverController
returnFocus={[Function]}
src="/api/v4/users/abc2/image"
triggerComponentClass=""
triggerComponentAs="button"
triggerComponentClass="style--none"
userId="abc2"
>
<a
<span
className="mention-link"
role="button"
tabIndex={0}
>
@Nick
</a>
</span>
</ProfilePopoverController>
</Fragment>
`;

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

@@ -60,20 +60,19 @@ const AtMention = (props: Props) => {
return (
<>
<ProfilePopover
triggerComponentClass={classNames({'mention--highlight': highlightMention})}
triggerComponentClass={classNames('style--none', {'mention--highlight': highlightMention})}
userId={user.id}
src={Client4.getProfilePictureUrl(user.id, user.last_picture_update)}
channelId={props.channelId}
returnFocus={returnFocus}
triggerComponentAs='button'
>
<a
<span
ref={ref}
className='mention-link'
role='button'
tabIndex={0}
>
{'@' + userDisplayName}
</a>
</span>
</ProfilePopover>
{userMentionNameSuffix}
</>

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

@@ -40,47 +40,52 @@ exports[`components/drafts/panel/panel_body should have called handleFormattedTe
<ProfilePopoverController
channelId="channel_id"
src="/api/v4/users/user_id/image?_=0"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="user_id"
username="username"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
className="status-wrapper"
className="status-wrapper style--none"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onPointerDown={[Function]}
style={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
>
<RoundButton
className="style--none"
size="md"
<span
className="profile-icon "
>
<button
className="RoundButton-dvlhqG gfRzmz style--none"
<Avatar
size="md"
url="/api/v4/users/user_id/image?_=0"
username="username"
>
<span
className="profile-icon "
>
<Avatar
size="md"
url="/api/v4/users/user_id/image?_=0"
username="username"
>
<img
alt="username profile image"
className="Avatar Avatar-md"
loading="lazy"
onError={[Function]}
src="/api/v4/users/user_id/image?_=0"
/>
</Avatar>
</span>
</button>
</RoundButton>
<img
alt="username profile image"
className="Avatar Avatar-md"
loading="lazy"
onError={[Function]}
src="/api/v4/users/user_id/image?_=0"
/>
</Avatar>
</span>
<Memo(StatusIcon)
status="status"
>
@@ -113,7 +118,7 @@ exports[`components/drafts/panel/panel_body should have called handleFormattedTe
</span>
</StatusOfflineIcon>
</Memo(StatusIcon)>
</span>
</button>
</ProfilePopoverController>
</ProfilePicture>
</div>
@@ -267,47 +272,52 @@ exports[`components/drafts/panel/panel_body should match snapshot 1`] = `
<ProfilePopoverController
channelId="channel_id"
src="/api/v4/users/user_id/image?_=0"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="user_id"
username="username"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
className="status-wrapper"
className="status-wrapper style--none"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onPointerDown={[Function]}
style={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
>
<RoundButton
className="style--none"
size="md"
<span
className="profile-icon "
>
<button
className="RoundButton-dvlhqG gfRzmz style--none"
<Avatar
size="md"
url="/api/v4/users/user_id/image?_=0"
username="username"
>
<span
className="profile-icon "
>
<Avatar
size="md"
url="/api/v4/users/user_id/image?_=0"
username="username"
>
<img
alt="username profile image"
className="Avatar Avatar-md"
loading="lazy"
onError={[Function]}
src="/api/v4/users/user_id/image?_=0"
/>
</Avatar>
</span>
</button>
</RoundButton>
<img
alt="username profile image"
className="Avatar Avatar-md"
loading="lazy"
onError={[Function]}
src="/api/v4/users/user_id/image?_=0"
/>
</Avatar>
</span>
<Memo(StatusIcon)
status="status"
>
@@ -340,7 +350,7 @@ exports[`components/drafts/panel/panel_body should match snapshot 1`] = `
</span>
</StatusOfflineIcon>
</Memo(StatusIcon)>
</span>
</button>
</ProfilePopoverController>
</ProfilePicture>
</div>
@@ -500,47 +510,52 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1
<ProfilePopoverController
channelId="channel_id"
src="/api/v4/users/user_id/image?_=0"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="user_id"
username="username"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
className="status-wrapper"
className="status-wrapper style--none"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onPointerDown={[Function]}
style={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
>
<RoundButton
className="style--none"
size="md"
<span
className="profile-icon "
>
<button
className="RoundButton-dvlhqG gfRzmz style--none"
<Avatar
size="md"
url="/api/v4/users/user_id/image?_=0"
username="username"
>
<span
className="profile-icon "
>
<Avatar
size="md"
url="/api/v4/users/user_id/image?_=0"
username="username"
>
<img
alt="username profile image"
className="Avatar Avatar-md"
loading="lazy"
onError={[Function]}
src="/api/v4/users/user_id/image?_=0"
/>
</Avatar>
</span>
</button>
</RoundButton>
<img
alt="username profile image"
className="Avatar Avatar-md"
loading="lazy"
onError={[Function]}
src="/api/v4/users/user_id/image?_=0"
/>
</Avatar>
</span>
<Memo(StatusIcon)
status="status"
>
@@ -573,7 +588,7 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1
</span>
</StatusOfflineIcon>
</Memo(StatusIcon)>
</span>
</button>
</ProfilePopoverController>
</ProfilePicture>
</div>
@@ -790,47 +805,52 @@ exports[`components/drafts/panel/panel_body should match snapshot for requested_
<ProfilePopoverController
channelId="channel_id"
src="/api/v4/users/user_id/image?_=0"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="user_id"
username="username"
>
<span
<button
aria-expanded="false"
aria-haspopup="dialog"
className="status-wrapper"
className="status-wrapper style--none"
onClick={[Function]}
onKeyDown={[Function]}
onKeyUp={[Function]}
onMouseDown={[Function]}
onPointerDown={[Function]}
style={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
>
<RoundButton
className="style--none"
size="md"
<span
className="profile-icon "
>
<button
className="RoundButton-dvlhqG gfRzmz style--none"
<Avatar
size="md"
url="/api/v4/users/user_id/image?_=0"
username="username"
>
<span
className="profile-icon "
>
<Avatar
size="md"
url="/api/v4/users/user_id/image?_=0"
username="username"
>
<img
alt="username profile image"
className="Avatar Avatar-md"
loading="lazy"
onError={[Function]}
src="/api/v4/users/user_id/image?_=0"
/>
</Avatar>
</span>
</button>
</RoundButton>
<img
alt="username profile image"
className="Avatar Avatar-md"
loading="lazy"
onError={[Function]}
src="/api/v4/users/user_id/image?_=0"
/>
</Avatar>
</span>
<Memo(StatusIcon)
status="status"
>
@@ -863,7 +883,7 @@ exports[`components/drafts/panel/panel_body should match snapshot for requested_
</span>
</StatusOfflineIcon>
</Memo(StatusIcon)>
</span>
</button>
</ProfilePopoverController>
</ProfilePicture>
</div>

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

@@ -566,7 +566,6 @@ function PostComponent(props: Props) {
channelId={post.channel_id}
/>
<div
role='application'
className={`post__content ${props.center ? 'center' : ''}`}
data-testid='postContent'
>

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

@@ -39,21 +39,24 @@ exports[`components/ProfilePicture should match snapshot, no user specified, ove
exports[`components/ProfilePicture should match snapshot, profile and src, default props 1`] = `
<ProfilePopoverController
src="http://example.com/image.png"
triggerComponentClass="status-wrapper"
triggerComponentAs="button"
triggerComponentClass="status-wrapper style--none"
triggerComponentStyle={
Object {
"borderRadius": "50%",
"height": "32px",
"width": "32px",
}
}
userId="uid"
>
<RoundButton
className="style--none"
size="md"
<span
className="profile-icon "
>
<span
className="profile-icon "
>
<Memo(Avatar)
url="http://example.com/emoji.png"
/>
</span>
</RoundButton>
<Memo(Avatar)
url="http://example.com/emoji.png"
/>
</span>
<Memo(StatusIcon)
status="away"
/>

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

@@ -3,7 +3,6 @@
import classNames from 'classnames';
import React from 'react';
import styled from 'styled-components';
import ProfilePopover from 'components/profile_popover';
import StatusIcon from 'components/status_icon';
@@ -42,7 +41,7 @@ function ProfilePicture(props: Props) {
if (props.userId) {
return (
<ProfilePopover
triggerComponentClass={classNames('status-wrapper', props.wrapperClass)}
triggerComponentClass={classNames('status-wrapper style--none', props.wrapperClass)}
userId={props.userId}
src={profileSrc}
username={props.username}
@@ -51,20 +50,21 @@ function ProfilePicture(props: Props) {
overwriteIcon={props.overwriteIcon}
overwriteName={props.overwriteName}
fromWebhook={props.fromWebhook}
triggerComponentAs='button'
triggerComponentStyle={{
borderRadius: '50%',
width: `${getAvatarWidth(props?.size ?? 'md')}px`,
height: `${getAvatarWidth(props?.size ?? 'md')}px`,
}}
>
<>
<RoundButton
className='style--none'
size={props?.size ?? 'md'}
>
<span className={profileIconClass}>
<Avatar
username={props.username}
size={props.size}
url={props.src}
/>
</span>
</RoundButton>
<span className={profileIconClass}>
<Avatar
username={props.username}
size={props.size}
url={props.src}
/>
</span>
<StatusIcon status={props.status}/>
</>
</ProfilePopover>
@@ -93,10 +93,4 @@ function ProfilePicture(props: Props) {
);
}
const RoundButton = styled.button<{size: TAvatarSizeToken}>`
border-radius: 50%;
width: ${(p) => getAvatarWidth(p.size)}px;
height: ${(p) => getAvatarWidth(p.size)}px;
`;
export default ProfilePicture;

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

@@ -21,6 +21,15 @@ del .group-mention-link:focus {
color: variables.$white;
}
.mention-link {
color: var(--link-color);
&:hover,
&:focus {
text-decoration: underline;
}
}
.badge {
display: inline-block;
min-width: 10px;