Accessibility: Add landmark regions to Web UI (#39133)
This commit is contained in:
parent
9fe97e1ad6
commit
e1aa4e3a8c
@ -248,7 +248,15 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
const { intl, onPaste, onDrop, autoFocus, withoutNavigation, maxChars, isSubmitting } = this.props;
|
const { intl, onPaste, onDrop, autoFocus, withoutNavigation, maxChars, isSubmitting } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className='compose-form' onSubmit={this.handleSubmit}>
|
<form
|
||||||
|
className='compose-form'
|
||||||
|
role='region'
|
||||||
|
aria-label={intl.formatMessage({
|
||||||
|
id: 'tabs_bar.publish',
|
||||||
|
defaultMessage: 'New Post'
|
||||||
|
})}
|
||||||
|
onSubmit={this.handleSubmit}
|
||||||
|
>
|
||||||
<ReplyIndicator />
|
<ReplyIndicator />
|
||||||
{!withoutNavigation && <NavigationBar />}
|
{!withoutNavigation && <NavigationBar />}
|
||||||
<Warning />
|
<Warning />
|
||||||
|
|||||||
@ -547,11 +547,15 @@ export const Search: React.FC<{
|
|||||||
const searchOptionsHeading = useId();
|
const searchOptionsHeading = useId();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form ref={formRef} className={classNames('search', { active: expanded })}>
|
<form
|
||||||
|
role='search'
|
||||||
|
ref={formRef}
|
||||||
|
className={classNames('search', { active: expanded })}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
ref={searchInputRef}
|
ref={searchInputRef}
|
||||||
className='search__input'
|
className='search__input'
|
||||||
type='text'
|
type='search'
|
||||||
placeholder={intl.formatMessage(
|
placeholder={intl.formatMessage(
|
||||||
signedIn ? messages.placeholderSignedIn : messages.placeholder,
|
signedIn ? messages.placeholderSignedIn : messages.placeholder,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -87,12 +87,11 @@ const Compose: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
|||||||
|
|
||||||
if (multiColumn) {
|
if (multiColumn) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div className='drawer'>
|
||||||
className='drawer'
|
<nav
|
||||||
role='region'
|
className='drawer__header'
|
||||||
aria-label={intl.formatMessage(navbarMessages.publish)}
|
aria-label={intl.formatMessage(navbarMessages.advancedUiQuickLinks)}
|
||||||
>
|
>
|
||||||
<nav className='drawer__header'>
|
|
||||||
<Link
|
<Link
|
||||||
to='/getting-started'
|
to='/getting-started'
|
||||||
className='drawer__tab'
|
className='drawer__tab'
|
||||||
@ -163,7 +162,11 @@ const Compose: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
|||||||
|
|
||||||
<Search singleColumn={false} />
|
<Search singleColumn={false} />
|
||||||
|
|
||||||
<div className='drawer__pager'>
|
<div
|
||||||
|
className='drawer__pager'
|
||||||
|
role='region'
|
||||||
|
aria-label={intl.formatMessage(navbarMessages.publish)}
|
||||||
|
>
|
||||||
<div className='drawer__inner'>
|
<div className='drawer__inner'>
|
||||||
<ComposeFormContainer />
|
<ComposeFormContainer />
|
||||||
|
|
||||||
|
|||||||
@ -4,14 +4,16 @@ import { Helmet } from '@unhead/react/helmet';
|
|||||||
|
|
||||||
import { Column } from 'mastodon/components/column';
|
import { Column } from 'mastodon/components/column';
|
||||||
|
|
||||||
import { NavigationPanel } from '../navigation_panel';
|
import { NavigationPanel, messages } from '../navigation_panel';
|
||||||
import { LinkFooter } from '../ui/components/link_footer';
|
import { LinkFooter } from '../ui/components/link_footer';
|
||||||
|
|
||||||
const GettingStarted: React.FC = () => {
|
const GettingStarted: React.FC = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
return (
|
return (
|
||||||
<Column>
|
<Column>
|
||||||
<NavigationPanel multiColumn />
|
<nav aria-label={intl.formatMessage(messages.main)}>
|
||||||
|
<NavigationPanel multiColumn />
|
||||||
|
</nav>
|
||||||
|
|
||||||
<LinkFooter context='multi-column' />
|
<LinkFooter context='multi-column' />
|
||||||
|
|
||||||
|
|||||||
@ -60,7 +60,7 @@ import { MoreLink } from './components/more_link';
|
|||||||
import { SignInBanner } from './components/sign_in_banner';
|
import { SignInBanner } from './components/sign_in_banner';
|
||||||
import { Trends } from './components/trends';
|
import { Trends } from './components/trends';
|
||||||
|
|
||||||
const messages = defineMessages({
|
export const messages = defineMessages({
|
||||||
home: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
home: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
||||||
notifications: {
|
notifications: {
|
||||||
id: 'tabs_bar.notifications',
|
id: 'tabs_bar.notifications',
|
||||||
@ -72,6 +72,12 @@ const messages = defineMessages({
|
|||||||
id: 'column.firehose_singular',
|
id: 'column.firehose_singular',
|
||||||
defaultMessage: 'Live feed',
|
defaultMessage: 'Live feed',
|
||||||
},
|
},
|
||||||
|
main: {
|
||||||
|
id: 'navigation_bar.main',
|
||||||
|
defaultMessage: 'Main',
|
||||||
|
description:
|
||||||
|
'Label for the main navigation; should not contain the word "navigation".',
|
||||||
|
},
|
||||||
direct: { id: 'navigation_bar.direct', defaultMessage: 'Private mentions' },
|
direct: { id: 'navigation_bar.direct', defaultMessage: 'Private mentions' },
|
||||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' },
|
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' },
|
||||||
bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
|
bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
|
||||||
@ -419,6 +425,7 @@ export const NavigationPanel: React.FC<{ multiColumn?: boolean }> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const CollapsibleNavigationPanel: React.FC = () => {
|
export const CollapsibleNavigationPanel: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
const open = useAppSelector((state) => state.navigation.open);
|
const open = useAppSelector((state) => state.navigation.open);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const openable = useBreakpoint('openable');
|
const openable = useBreakpoint('openable');
|
||||||
@ -527,7 +534,8 @@ export const CollapsibleNavigationPanel: React.FC = () => {
|
|||||||
const showOverlay = openable && open;
|
const showOverlay = openable && open;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<nav
|
||||||
|
aria-label={intl.formatMessage(messages.main)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'columns-area__panels__pane columns-area__panels__pane--start columns-area__panels__pane--navigational',
|
'columns-area__panels__pane columns-area__panels__pane--start columns-area__panels__pane--navigational',
|
||||||
{ 'columns-area__panels__pane--overlay': showOverlay },
|
{ 'columns-area__panels__pane--overlay': showOverlay },
|
||||||
@ -541,6 +549,6 @@ export const CollapsibleNavigationPanel: React.FC = () => {
|
|||||||
>
|
>
|
||||||
<NavigationPanel />
|
<NavigationPanel />
|
||||||
</animated.div>
|
</animated.div>
|
||||||
</div>
|
</nav>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -108,12 +108,12 @@ export const ColumnsArea = forwardRef<
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='columns-area__panels__main'>
|
<main className='columns-area__panels__main'>
|
||||||
<div className='tabs-bar__wrapper'>
|
<div className='tabs-bar__wrapper'>
|
||||||
<TabsBarPortal />
|
<TabsBarPortal />
|
||||||
</div>
|
</div>
|
||||||
<div className='columns-area columns-area--mobile'>{children}</div>
|
<div className='columns-area columns-area--mobile'>{children}</div>
|
||||||
</div>
|
</main>
|
||||||
|
|
||||||
<CollapsibleNavigationPanel />
|
<CollapsibleNavigationPanel />
|
||||||
</div>
|
</div>
|
||||||
@ -121,7 +121,7 @@ export const ColumnsArea = forwardRef<
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<main
|
||||||
className={classNames('columns-area', { unscrollable: isModalOpen })}
|
className={classNames('columns-area', { unscrollable: isModalOpen })}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
tabIndex={isModalOpen ? undefined : 0}
|
tabIndex={isModalOpen ? undefined : 0}
|
||||||
@ -160,7 +160,7 @@ export const ColumnsArea = forwardRef<
|
|||||||
cloneElement(child, { multiColumn: true }),
|
cloneElement(child, { multiColumn: true }),
|
||||||
)}
|
)}
|
||||||
</ColumnIndexContext.Provider>
|
</ColumnIndexContext.Provider>
|
||||||
</div>
|
</main>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,10 @@ export const messages = defineMessages({
|
|||||||
defaultMessage: 'Notifications',
|
defaultMessage: 'Notifications',
|
||||||
},
|
},
|
||||||
menu: { id: 'tabs_bar.menu', defaultMessage: 'Menu' },
|
menu: { id: 'tabs_bar.menu', defaultMessage: 'Menu' },
|
||||||
|
advancedUiQuickLinks: {
|
||||||
|
id: 'tabs_bar.quick_links',
|
||||||
|
defaultMessage: 'Quick links',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const IconLabelButton: React.FC<{
|
const IconLabelButton: React.FC<{
|
||||||
|
|||||||
@ -908,6 +908,7 @@
|
|||||||
"navigation_bar.live_feed_local": "Live feed (local)",
|
"navigation_bar.live_feed_local": "Live feed (local)",
|
||||||
"navigation_bar.live_feed_public": "Live feed (public)",
|
"navigation_bar.live_feed_public": "Live feed (public)",
|
||||||
"navigation_bar.logout": "Logout",
|
"navigation_bar.logout": "Logout",
|
||||||
|
"navigation_bar.main": "Main",
|
||||||
"navigation_bar.moderation": "Moderation",
|
"navigation_bar.moderation": "Moderation",
|
||||||
"navigation_bar.more": "More",
|
"navigation_bar.more": "More",
|
||||||
"navigation_bar.mutes": "Muted users",
|
"navigation_bar.mutes": "Muted users",
|
||||||
@ -1305,6 +1306,7 @@
|
|||||||
"tabs_bar.menu": "Menu",
|
"tabs_bar.menu": "Menu",
|
||||||
"tabs_bar.notifications": "Notifications",
|
"tabs_bar.notifications": "Notifications",
|
||||||
"tabs_bar.publish": "New Post",
|
"tabs_bar.publish": "New Post",
|
||||||
|
"tabs_bar.quick_links": "Quick links",
|
||||||
"tabs_bar.search": "Search",
|
"tabs_bar.search": "Search",
|
||||||
"tag.remove": "Remove",
|
"tag.remove": "Remove",
|
||||||
"terms_of_service.effective_as_of": "Effective as of {date}",
|
"terms_of_service.effective_as_of": "Effective as of {date}",
|
||||||
|
|||||||
@ -411,7 +411,7 @@ $content-width: 840px;
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > ul {
|
& > nav > ul {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
&.visible {
|
&.visible {
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
- content_for :content do
|
- content_for :content do
|
||||||
%a.navigation-skip-link{ href: '#content' }= t('admin.skip_to_content')
|
%a.navigation-skip-link{ href: '#content' }= t('admin.skip_to_content')
|
||||||
.admin-wrapper
|
.admin-wrapper
|
||||||
%nav.sidebar-wrapper
|
%header.sidebar-wrapper
|
||||||
.sidebar-wrapper__inner
|
.sidebar-wrapper__inner
|
||||||
.sidebar
|
.sidebar
|
||||||
= link_to root_path do
|
= link_to root_path do
|
||||||
@ -23,7 +23,8 @@
|
|||||||
= material_symbol 'menu'
|
= material_symbol 'menu'
|
||||||
= material_symbol 'close'
|
= material_symbol 'close'
|
||||||
|
|
||||||
= render_navigation
|
%nav
|
||||||
|
= render_navigation
|
||||||
|
|
||||||
%main.content-wrapper#content
|
%main.content-wrapper#content
|
||||||
.content
|
.content
|
||||||
|
|||||||
@ -12,6 +12,6 @@ RSpec.describe 'UnloggedBrowsing', :js, :streaming do
|
|||||||
it 'loads the home page' do
|
it 'loads the home page' do
|
||||||
expect(subject).to have_css('div.app-holder')
|
expect(subject).to have_css('div.app-holder')
|
||||||
|
|
||||||
expect(subject).to have_css('div.columns-area__panels__main')
|
expect(subject).to have_css('main.columns-area__panels__main')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user