[MM-61641]: Ensure implicit list markup is avoided (#29787)
* MM-61641: Update post options to use semantic list elements * MM-61641: Fix lint * Apply suggestions from code review --------- Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: Harrison Healey <harrisonmhealey@gmail.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
3b69d36643
Коммит
a672aa5be5
@@ -59,7 +59,7 @@ type Props = {
|
||||
};
|
||||
|
||||
const PostOptions = (props: Props): JSX.Element => {
|
||||
const dotMenuRef = useRef<HTMLDivElement>(null);
|
||||
const dotMenuRef = useRef<HTMLUListElement>(null);
|
||||
|
||||
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
||||
const [showDotMenu, setShowDotMenu] = useState(false);
|
||||
@@ -120,12 +120,14 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
let commentIcon;
|
||||
if (showCommentIcon) {
|
||||
commentIcon = (
|
||||
<CommentIcon
|
||||
handleCommentClick={props.handleCommentClick}
|
||||
postId={post.id}
|
||||
extraClass={commentIconExtraClass}
|
||||
commentCount={props.collapsedThreadsEnabled ? 0 : props.replyCount}
|
||||
/>
|
||||
<li>
|
||||
<CommentIcon
|
||||
handleCommentClick={props.handleCommentClick}
|
||||
postId={post.id}
|
||||
extraClass={commentIconExtraClass}
|
||||
commentCount={props.collapsedThreadsEnabled ? 0 : props.replyCount}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -152,38 +154,44 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
let postReaction;
|
||||
if (showReactionIcon) {
|
||||
postReaction = (
|
||||
<PostReaction
|
||||
channelId={post.channel_id}
|
||||
location={props.location}
|
||||
postId={post.id}
|
||||
teamId={props.teamId}
|
||||
getDotMenuRef={getDotMenuRef}
|
||||
showEmojiPicker={showEmojiPicker}
|
||||
toggleEmojiPicker={toggleEmojiPicker}
|
||||
/>
|
||||
<li>
|
||||
<PostReaction
|
||||
channelId={post.channel_id}
|
||||
location={props.location}
|
||||
postId={post.id}
|
||||
teamId={props.teamId}
|
||||
getDotMenuRef={getDotMenuRef}
|
||||
showEmojiPicker={showEmojiPicker}
|
||||
toggleEmojiPicker={toggleEmojiPicker}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
let flagIcon: ReactNode = null;
|
||||
if (!isMobileView && (!isEphemeral && !post.failed && !systemMessage)) {
|
||||
flagIcon = (
|
||||
<PostFlagIcon
|
||||
location={props.location}
|
||||
postId={post.id}
|
||||
isFlagged={props.isFlagged}
|
||||
/>
|
||||
<li>
|
||||
<PostFlagIcon
|
||||
location={props.location}
|
||||
postId={post.id}
|
||||
isFlagged={props.isFlagged}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
// Action menus
|
||||
const showActionsMenuIcon = props.shouldShowActionsMenu && (isMobileView || hoverLocal);
|
||||
const actionsMenu = showActionsMenuIcon && (
|
||||
<ActionsMenu
|
||||
post={post}
|
||||
location={props.location}
|
||||
handleDropdownOpened={handleActionsMenuOpened}
|
||||
isMenuOpen={showActionsMenu}
|
||||
/>
|
||||
<li>
|
||||
<ActionsMenu
|
||||
post={post}
|
||||
location={props.location}
|
||||
handleDropdownOpened={handleActionsMenuOpened}
|
||||
isMenuOpen={showActionsMenu}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
|
||||
let pluginItems: ReactNode = null;
|
||||
@@ -193,10 +201,11 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
if (item.component) {
|
||||
const Component = item.component;
|
||||
return (
|
||||
<Component
|
||||
post={props.post}
|
||||
key={item.id}
|
||||
/>
|
||||
<li key={item.id}>
|
||||
<Component
|
||||
post={props.post}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@@ -204,17 +213,19 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
}
|
||||
|
||||
const dotMenu = (
|
||||
<DotMenu
|
||||
post={props.post}
|
||||
location={props.location}
|
||||
isFlagged={props.isFlagged}
|
||||
handleDropdownOpened={handleDotMenuOpened}
|
||||
handleCommentClick={props.handleCommentClick}
|
||||
handleAddReactionClick={toggleEmojiPicker}
|
||||
isReadOnly={isReadOnly || channelIsArchived}
|
||||
isMenuOpen={showDotMenu}
|
||||
enableEmojiPicker={props.enableEmojiPicker}
|
||||
/>
|
||||
<li>
|
||||
<DotMenu
|
||||
post={props.post}
|
||||
location={props.location}
|
||||
isFlagged={props.isFlagged}
|
||||
handleDropdownOpened={handleDotMenuOpened}
|
||||
handleCommentClick={props.handleCommentClick}
|
||||
handleAddReactionClick={toggleEmojiPicker}
|
||||
isReadOnly={isReadOnly || channelIsArchived}
|
||||
isMenuOpen={showDotMenu}
|
||||
enableEmojiPicker={props.enableEmojiPicker}
|
||||
/>
|
||||
</li>
|
||||
);
|
||||
|
||||
// Build post options
|
||||
@@ -235,10 +246,11 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
} else if (props.location === Locations.SEARCH) {
|
||||
const hasCRTFooter = props.collapsedThreadsEnabled && !post.root_id && (post.reply_count > 0 || post.is_following);
|
||||
options = (
|
||||
<div className='col__controls post-menu'>
|
||||
<ul className='col__controls post-menu'>
|
||||
{dotMenu}
|
||||
{flagIcon}
|
||||
{props.canReply && !hasCRTFooter &&
|
||||
<li>
|
||||
<CommentIcon
|
||||
location={props.location}
|
||||
handleCommentClick={props.handleCommentClick}
|
||||
@@ -247,22 +259,25 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
searchStyle={'search-item__comment'}
|
||||
extraClass={props.replyCount ? 'icon--visible' : ''}
|
||||
/>
|
||||
</li>
|
||||
}
|
||||
<a
|
||||
href='#'
|
||||
onClick={props.handleJumpClick}
|
||||
className='search-item__jump'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='search_item.jump'
|
||||
defaultMessage='Jump'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<li>
|
||||
<a
|
||||
href='#'
|
||||
onClick={props.handleJumpClick}
|
||||
className='search-item__jump'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='search_item.jump'
|
||||
defaultMessage='Jump'
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
} else if (!props.isPostBeingEdited) {
|
||||
options = (
|
||||
<div
|
||||
<ul
|
||||
ref={dotMenuRef}
|
||||
data-testid={`post-menu-${props.post.id}`}
|
||||
className={classnames('col post-menu', {'post-menu--position': !hoverLocal && showCommentIcon})}
|
||||
@@ -275,7 +290,7 @@ const PostOptions = (props: Props): JSX.Element => {
|
||||
{actionsMenu}
|
||||
{commentIcon}
|
||||
{(collapsedThreadsEnabled || showRecentlyUsedReactions) && dotMenu}
|
||||
</div>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export type Props = WrappedComponentProps & {
|
||||
channelId?: string;
|
||||
postId: string;
|
||||
teamId: string;
|
||||
getDotMenuRef: () => HTMLDivElement | null;
|
||||
getDotMenuRef: () => HTMLUListElement | null;
|
||||
location?: keyof typeof Locations;
|
||||
showEmojiPicker: boolean;
|
||||
toggleEmojiPicker: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
|
||||
@@ -96,13 +96,13 @@ export default class PostRecentReactions extends React.PureComponent<Props, Stat
|
||||
emoji={getEmojiName(emoji)}
|
||||
isEmojiLarge={true}
|
||||
>
|
||||
<div>
|
||||
<li>
|
||||
<EmojiItem
|
||||
emoji={emoji}
|
||||
onItemClick={this.handleToggleEmoji}
|
||||
order={n}
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
</WithTooltip>
|
||||
</ChannelPermissionGate>
|
||||
),
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
padding: 4px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
list-style: none;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user