Wrap page headings with NavigationFocusTarget

This commit is contained in:
diondiondion
2026-06-09 19:48:20 +02:00
parent 261bce90de
commit a56db5e350
9 changed files with 47 additions and 18 deletions

View File

@@ -19,6 +19,7 @@ import { useIdentity } from 'mastodon/identity_context';
import { useColumnIndexContext } from '../features/ui/components/columns_area';
import { getColumnSkipLinkId } from '../features/ui/components/skip_links';
import { NavigationFocusTarget } from './navigation_focus_target';
import { useAppHistory } from './router';
export const messages = defineMessages({
@@ -285,7 +286,10 @@ export const ColumnHeader: React.FC<Props> = ({
<div className={headingClassName}>
{backButton}
{hasTitle && (
<h1 className='column-header__title-wrapper'>
<NavigationFocusTarget
as='h1'
className='column-header__title-wrapper'
>
{onClick ? (
<button
onClick={handleTitleClick}
@@ -304,7 +308,7 @@ export const ColumnHeader: React.FC<Props> = ({
{titleContents}
</span>
)}
</h1>
</NavigationFocusTarget>
)}
<div className='column-header__buttons'>

View File

@@ -8,10 +8,13 @@ import { Helmet } from '@unhead/react/helmet';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { domain } from 'mastodon/initial_state';
import { injectIntl } from '@/mastodon/components/intl';
import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'mastodon/actions/server';
import { Account } from 'mastodon/components/account';
import Column from 'mastodon/components/column';
import { NavigationFocusTarget } from 'mastodon/components/navigation_focus_target';
import { ServerHeroImage } from 'mastodon/components/server_hero_image';
import { Skeleton } from 'mastodon/components/skeleton';
import { LinkFooter} from 'mastodon/features/ui/components/link_footer';
@@ -91,7 +94,9 @@ class About extends PureComponent {
srcSet={Object.keys(server.item?.thumbnail.versions ?? {}).map((key) => `${server.item?.thumbnail.versions && server.item.thumbnail.versions[key]} ${key.replace('@', '')}`).join(', ')}
className='about__header__hero'
/>
<h1>{isLoading ? <Skeleton width='10ch' /> : server.domain}</h1>
<NavigationFocusTarget as='h1'>
{isLoading ? <Skeleton width='10ch' /> : domain}
</NavigationFocusTarget>
<p><FormattedMessage id='about.powered_by' defaultMessage='Decentralized social media powered by {mastodon}' values={{ mastodon: <a href='https://joinmastodon.org' className='about__mail' target='_blank' rel='noopener'>Mastodon</a> }} /></p>
</div>

View File

@@ -10,6 +10,7 @@ import {
ModalShellActions,
ModalShellBody,
} from '@/mastodon/components/modal_shell';
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
import { useFieldHtml } from '../hooks/useFieldHtml';
@@ -24,12 +25,14 @@ export const AccountFieldModal: FC<{
return (
<ModalShell>
<ModalShellBody>
<EmojiHTML
as='h2'
htmlString={field.name_emojified}
onElement={handleLabelElement}
className={classes.fieldName}
/>
<NavigationFocusTarget as='h1'>
<EmojiHTML
as='span'
htmlString={field.name_emojified}
onElement={handleLabelElement}
className={classes.fieldName}
/>
</NavigationFocusTarget>
<EmojiHTML
as='p'
htmlString={field.value_emojified}

View File

@@ -5,6 +5,7 @@ import { connect } from 'react-redux';
import { fetchServer } from 'mastodon/actions/server';
import { domain } from 'mastodon/initial_state';
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
const mapStateToProps = state => ({
message: state.getIn(['server', 'server', 'item', 'registrations', 'message']),
@@ -42,7 +43,9 @@ class ClosedRegistrationsModal extends ImmutablePureComponent {
return (
<div className='modal-root__modal interaction-modal'>
<div className='interaction-modal__lead'>
<h3><FormattedMessage id='closed_registrations_modal.title' defaultMessage='Signing up on Mastodon' /></h3>
<NavigationFocusTarget as='h1'>
<FormattedMessage id='closed_registrations_modal.title' defaultMessage='Signing up on Mastodon' />
</NavigationFocusTarget>
<p>
<FormattedMessage
id='closed_registrations_modal.preamble'
@@ -53,12 +56,12 @@ class ClosedRegistrationsModal extends ImmutablePureComponent {
<div className='interaction-modal__choices'>
<div className='interaction-modal__choices__choice'>
<h3><FormattedMessage id='interaction_modal.on_this_server' defaultMessage='On this server' /></h3>
<h2><FormattedMessage id='interaction_modal.on_this_server' defaultMessage='On this server' /></h2>
{closedRegistrationsMessage}
</div>
<div className='interaction-modal__choices__choice'>
<h3><FormattedMessage id='interaction_modal.on_another_server' defaultMessage='On a different server' /></h3>
<h2><FormattedMessage id='interaction_modal.on_another_server' defaultMessage='On a different server' /></h2>
<p className='prose'>
<FormattedMessage
id='closed_registrations.other_server_instructions'

View File

@@ -4,6 +4,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { useLocation } from 'react-router';
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
import { me } from '@/mastodon/initial_state';
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
import { changeCompose, focusCompose } from 'mastodon/actions/compose';
@@ -66,7 +67,7 @@ export const CollectionShareModal: React.FC<{
return (
<ModalShell>
<ModalShellBody>
<h1 className={classes.heading}>
<NavigationFocusTarget as='h1' className={classes.heading}>
{isNew ? (
<FormattedMessage
id='collection.share_modal.title_new'
@@ -78,7 +79,7 @@ export const CollectionShareModal: React.FC<{
defaultMessage='Share collection'
/>
)}
</h1>
</NavigationFocusTarget>
<IconButton
title={intl.formatMessage({

View File

@@ -4,6 +4,7 @@ import { Route, Switch, useRouteMatch } from 'react-router-dom';
import { Helmet } from '@unhead/react/helmet';
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
import { Column } from 'mastodon/components/column';
import { ColumnHeader } from 'mastodon/components/column_header';
import { DisplayNameSimple } from 'mastodon/components/display_name/simple';
@@ -71,7 +72,9 @@ export const Collections: React.FC<{
<Scrollable>
<header className={classes.header}>
<h1 className={classes.heading}>{pageTitleHtml}</h1>
<NavigationFocusTarget as='h1' className={classes.heading}>
{pageTitleHtml}
</NavigationFocusTarget>
<TabList plain>
<TabLink exact to={`/@${account?.acct}/collections`}>
{intl.formatMessage(createdByTabMessage, {

View File

@@ -8,6 +8,7 @@ import { escapeRegExp } from 'lodash';
import { useDebouncedCallback } from 'use-debounce';
import { DisplayName } from '@/mastodon/components/display_name';
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
import { openModal, closeModal } from 'mastodon/actions/modal';
import { apiRequest } from 'mastodon/api';
import { Button } from 'mastodon/components/button';
@@ -474,12 +475,12 @@ const InteractionModal: React.FC<{
return (
<div className='modal-root__modal interaction-modal'>
<div className='interaction-modal__lead'>
<h3>
<NavigationFocusTarget as='h1'>
<FormattedMessage
id='interaction_modal.title'
defaultMessage='Sign in to continue'
/>
</h3>
</NavigationFocusTarget>
<p>
{intent === 'follow' ? (
<FormattedMessage

View File

@@ -2,6 +2,7 @@ import { useCallback } from 'react';
import { FormattedMessage } from 'react-intl';
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
import { Button } from 'mastodon/components/button';
import {
ModalShell,
@@ -67,7 +68,9 @@ export const ConfirmationModal: React.FC<
return (
<ModalShell onSubmit={handleClick}>
<ModalShellBody className={className}>
<h1 id={titleId}>{title}</h1>
<NavigationFocusTarget as='h1' id={titleId}>
{title}
</NavigationFocusTarget>
{message && <p>{message}</p>}
{extraContent ?? children}

View File

@@ -9141,6 +9141,8 @@ noscript {
padding-bottom: 32px;
}
h1,
h2,
h3 {
font-size: 22px;
line-height: 33px;
@@ -9171,6 +9173,8 @@ noscript {
&__lead {
margin-bottom: 20px;
h1,
h2,
h3 {
margin-bottom: 15px;
}
@@ -9246,6 +9250,8 @@ noscript {
flex: 1;
box-sizing: border-box;
h1,
h2,
h3 {
margin-bottom: 20px;
}