fix(react): address Doctor findings (#1143)

Accessibility/semantics pass aligned with React Doctor: role-based spans/divs become real buttons, role=status becomes <output>, modals use native <dialog>, author/peer flags render as <img>, and embed/challenge iframes are sandboxed. Includes review follow-ups: correct button chrome/centering/themed dialog colors and focus rings, the missing aria-label i18n keys (all languages), the Yandex image-search URL, clearer .bso setup steps, a keyboard-accessible image-search dropdown, and removal of the post-edit ('comment edited') display (mod edits unchanged).
This commit is contained in:
Tommaso Casaburi
2026-05-29 17:09:07 +07:00
committed by GitHub
parent ac95e58433
commit e082c7b428
132 changed files with 1753 additions and 1224 deletions
+16 -18
View File
@@ -61,8 +61,6 @@ import { getFeedPostHeightEstimate, getReplyHeightEstimates, reportReplyHeightAu
import { getAuthorBadge } from '../../lib/utils/author-display-utils';
import { hasCommentFlagsForDirectory } from '../../lib/comment-flag-selection';
const { addChallenge } = useChallengesStore.getState();
const RepliesFooter = ({ hasMore, loadingString }: { hasMore: boolean; loadingString: string }) =>
hasMore ? (
<div className={styles.stateString}>
@@ -135,7 +133,7 @@ const PostInfoAndMedia = ({
communityAddress: shouldShowPendingApprovalButtons ? communityAddress : undefined,
commentModeration: approvePendingCommentModeration,
onChallenge: async (...args: any) => {
addChallenge([...args, resolvedPost]);
useChallengesStore.getState().addChallenge([...args, resolvedPost]);
},
onChallengeVerification: async (challengeVerification, comment) => {
alertChallengeVerificationFailed(challengeVerification, comment);
@@ -154,7 +152,7 @@ const PostInfoAndMedia = ({
communityAddress: shouldShowPendingApprovalButtons ? communityAddress : undefined,
commentModeration: rejectPendingCommentModeration,
onChallenge: async (...args: any) => {
addChallenge([...args, resolvedPost]);
useChallengesStore.getState().addChallenge([...args, resolvedPost]);
},
onChallengeVerification: async (challengeVerification, comment) => {
alertChallengeVerificationFailed(challengeVerification, comment);
@@ -331,10 +329,10 @@ const PostInfoAndMedia = ({
content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`}
showTooltip={isInPostPageView || postReplyCount < 6}
>
<span
<button
type='button'
title={t('highlight_posts')}
className={styles.userAddress}
role='button'
tabIndex={0}
onClick={() => handleUserAddressClick(userID, postCid)}
onKeyDown={(e) => {
@@ -346,7 +344,7 @@ const PostInfoAndMedia = ({
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
>
{formatUserIDForDisplay(userID)}
</span>
</button>
</Tooltip>
)}
){' '}
@@ -406,10 +404,10 @@ const PostInfoAndMedia = ({
<Link to={threadRoute || '#'} state={threadTopNavigationState} className={styles.linkToPost} title={t('link_to_post')} onClick={onLinkToPostClick}>
No.
</Link>
<span
<button
type='button'
className={styles.replyToPost}
title={t('reply_to_post')}
role='button'
tabIndex={0}
onMouseDown={onReplyModalClick}
onKeyDown={(e) => {
@@ -420,7 +418,7 @@ const PostInfoAndMedia = ({
}}
>
{resolvedPost?.number || '?'}
</span>
</button>
</span>
) : (
<>
@@ -443,10 +441,10 @@ const PostInfoAndMedia = ({
<LoadingEllipsis string={t('publishing')} />
) : (
<>
<button className={`button ${styles.approveButton}`} onClick={handlePendingApprove} disabled={isPublishingPending}>
<button type='button' className={`button ${styles.approveButton}`} onClick={handlePendingApprove} disabled={isPublishingPending}>
{t('approve')}
</button>
<button className={`button ${styles.rejectButton}`} onClick={handlePendingReject} disabled={isPublishingPending}>
<button type='button' className={`button ${styles.rejectButton}`} onClick={handlePendingReject} disabled={isPublishingPending}>
{t('reject')}
</button>
</>
@@ -625,7 +623,7 @@ const PostMobile = ({
const modQueueThreadRouteState = getQueuedCommentRouteState(resolvedPost);
const modQueueErrorMessage = formatErrorForDisplay(modQueueError);
const modQueueRemoveButton = onRemoveFromModQueue ? (
<button className='button' onClick={onRemoveFromModQueue} disabled={isPublishing}>
<button type='button' className='button' onClick={onRemoveFromModQueue} disabled={isPublishing}>
{capitalize(t('modQueue.dismiss'))}
</button>
) : null;
@@ -840,9 +838,9 @@ const PostMobile = ({
<>
<hr className={styles.unhideButtonHr} />
<span className={styles.mobileUnhideButton}>
<span
<button
type='button'
className='button'
role='button'
tabIndex={0}
onClick={unhide}
onKeyDown={(e) => {
@@ -853,7 +851,7 @@ const PostMobile = ({
}}
>
Show Hidden Thread
</span>
</button>
</span>
</>
) : (
@@ -921,10 +919,10 @@ const PostMobile = ({
{t('view_thread')}
</Link>
)}
<button className={`button ${styles.approveButton}`} onClick={onApprove} disabled={isPublishing}>
<button type='button' className={`button ${styles.approveButton}`} onClick={onApprove} disabled={isPublishing}>
{t('approve')}
</button>
<button className={`button ${styles.rejectButton}`} onClick={onReject} disabled={isPublishing}>
<button type='button' className={`button ${styles.rejectButton}`} onClick={onReject} disabled={isPublishing}>
{t('reject')}
</button>
</>