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
@@ -220,7 +220,7 @@ describe('BoardsBar', () => {
await renderBoardsBar('/mu');
await act(async () => {
findExactText('search')?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
findExactText('Search')?.dispatchEvent(new MouseEvent('click', { bubbles: true }));
});
const inputs = container.querySelectorAll<HTMLInputElement>('input[type="text"]');
@@ -5,13 +5,30 @@
position: relative;
}
.boardNavDesktop button, .boardNavMobile button {
appearance: none;
background: transparent;
border: 0;
color: inherit;
display: inline;
font: inherit;
line-height: inherit;
margin: 0;
padding: 0;
}
.boardNavDesktop button:focus-visible, .boardNavMobile button:focus-visible {
outline: 1px dotted currentcolor;
outline-offset: 1px;
}
.checkingSubscriptions {
font-size: var(--boardsbar-font-size);
color: var(--boardsbar-desktop-link-text-color);
text-transform: lowercase;
}
.boardNavDesktop a, .navTopRight span {
.boardNavDesktop a, .navTopRight span, .navTopRight button {
color: var(--boardsbar-desktop-link-text-color);
text-decoration: var(--boardsbar-desktop-link-text-decoration);
}
@@ -20,13 +37,13 @@
padding: 0 1px;
}
.boardNavDesktop a:hover, .navTopRight span:hover {
.boardNavDesktop a:hover, .navTopRight span:hover, .navTopRight button:hover {
color: var(--boardsbar-desktop-link-text-color-hover);
text-decoration: var(--boardsbar-desktop-link-text-decoration-hover);
cursor: pointer;
}
.placeholder {
.boardNavDesktop .placeholder {
color: var(--boardsbar-separator-color);
}
@@ -45,13 +62,17 @@
margin-right: -7px;
}
.temporaryButton {
.boardNavDesktop .temporaryButton {
color: var(--boardsbar-desktop-link-text-color);
text-decoration: var(--boardsbar-desktop-link-text-decoration);
text-transform: capitalize;
}
.temporaryButton:hover {
.navTopRight button {
text-transform: capitalize;
}
.boardNavDesktop .temporaryButton:hover {
color: var(--boardsbar-desktop-link-text-color-hover);
text-decoration: var(--boardsbar-desktop-link-text-decoration-hover);
cursor: pointer;
@@ -80,7 +101,7 @@
justify-content: space-around;
}
.boardNavMobile .pageJump a, .boardNavMobile .pageJump span {
.boardNavMobile .pageJump a, .boardNavMobile .pageJump span, .boardNavMobile .pageJump button {
color: var(--boardsbar-mobile-button-text-color);
text-decoration: var(--button-text-decoration-mobile);
}
@@ -108,7 +129,7 @@
padding: 3px 5px 0 0;
}
.pageJump a, .pageJump span {
.pageJump a, .pageJump span, .pageJump button {
padding-right: 5px;
text-decoration: var(--homepage-box-link-text-decoration);
cursor: pointer;
+31 -22
View File
@@ -70,7 +70,16 @@ const SearchBar = ({ setShowSearchBar }: { setShowSearchBar: (show: boolean) =>
return (
<div className={styles.searchBar} ref={searchBarRef}>
<form onSubmit={handleSearchSubmit}>
<input type='text' autoCorrect='off' autoComplete='off' spellCheck='false' autoCapitalize='off' placeholder={placeholder} ref={searchInputRef} />
<input
type='text'
aria-label={placeholder}
autoCorrect='off'
autoComplete='off'
spellCheck='false'
autoCapitalize='off'
placeholder={placeholder}
ref={searchInputRef}
/>
</form>
</div>
);
@@ -154,9 +163,9 @@ const BoardsBarDesktop = () => {
const linkContent = (
<>
{isPlaceholder ? (
<span
<button
type='button'
className={styles.placeholder}
role='button'
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
@@ -168,7 +177,7 @@ const BoardsBarDesktop = () => {
style={{ cursor: 'pointer' }}
>
{code}
</span>
</button>
) : (
<Link to={`/${code}${catalogSuffix}`} onClick={openDirectoryForPlaceholder}>
{code}
@@ -209,19 +218,19 @@ const BoardsBarDesktop = () => {
</>
)}
]{' '}
{BOARD_CODE_GROUPS.map((group, groupIndex) => {
{BOARD_CODE_GROUPS.map((group) => {
const visibleCodes = group.filter((code) => directoriesToShow.has(code));
if (visibleCodes.length === 0) return null;
return <span key={groupIndex}>[{visibleCodes.map((code, codeIndex) => renderBoardCode(code, codeIndex === visibleCodes.length - 1))}] </span>;
return <span key={group.join('|')}>[{visibleCodes.map((code, codeIndex) => renderBoardCode(code, codeIndex === visibleCodes.length - 1))}] </span>;
})}
{hasHiddenDirectories && !showAllTemporarily && (
<>
{' '}
[
<span
<button
type='button'
className={styles.temporaryButton}
role='button'
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
@@ -234,7 +243,7 @@ const BoardsBarDesktop = () => {
title='Show all'
>
...
</span>
</button>
]{' '}
</>
)}
@@ -242,9 +251,9 @@ const BoardsBarDesktop = () => {
<>[{visibleSubscriptionAddresses.map((address: string, index: number) => renderSubscription(address, index, visibleSubscriptionAddresses.length))}] </>
)}
[
<span
<button
type='button'
className={styles.temporaryButton}
role='button'
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
@@ -256,11 +265,11 @@ const BoardsBarDesktop = () => {
style={{ cursor: 'pointer' }}
>
{capitalize(t('edit'))}
</span>
</button>
] [
<span
<button
type='button'
className={styles.temporaryButton}
role='button'
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
@@ -272,13 +281,13 @@ const BoardsBarDesktop = () => {
style={{ cursor: 'pointer' }}
>
{t('create_board')}
</span>
</button>
]
</span>
<span className={styles.navTopRight}>
[<Link to={!location.pathname.endsWith('settings') ? location.pathname.replace(/\/$/, '') + '/settings' : location.pathname}>{t('settings')}</Link>] [
<span
role='button'
<button
type='button'
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
@@ -288,8 +297,8 @@ const BoardsBarDesktop = () => {
}}
onClick={() => setShowSearchBar(!showSearchBar)}
>
{t('search')}
</span>
{capitalize(t('search'))}
</button>
] [<Link to='/'>{t('home')}</Link>]
</span>
{showSearchBar && <SearchBar setShowSearchBar={setShowSearchBar} />}
@@ -387,8 +396,8 @@ const BoardsBarMobile = ({ communityAddress }: { communityAddress?: string }) =>
</div>
<div className={styles.pageJump}>
<Link to={location.pathname.replace(/\/$/, '') + '/settings'}>{t('settings')}</Link>
<span
role='button'
<button
type='button'
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
@@ -399,7 +408,7 @@ const BoardsBarMobile = ({ communityAddress }: { communityAddress?: string }) =>
onClick={() => setShowSearchBar(!showSearchBar)}
>
{capitalize(t('search'))}
</span>
</button>
<Link to='/'>{t('home')}</Link>
{showSearchBar && <SearchBar setShowSearchBar={setShowSearchBar} />}
</div>