Composer redesign: Standalone pages (#40826)

This commit is contained in:
Echo
2026-10-02 11:36:43 +00:00
committed by GitHub
parent f0c2c18ddd
commit a4abbce9c2
17 changed files with 100 additions and 45 deletions

View File

@@ -71,7 +71,6 @@ export const BioModal: FC<BaseConfirmationModalProps> = ({ onClose }) => {
maxLength={maxLength}
className={classes.bioField}
{...textAreaProps}
// eslint-disable-next-line jsx-a11y/no-autofocus -- This is a modal, it's fine.
autoFocus
/>
</ConfirmationModal>

View File

@@ -282,11 +282,7 @@ const StepUpload: FC<{
}}
tagName='p'
/>
<Button
onClick={handleUploadClick}
// eslint-disable-next-line jsx-a11y/no-autofocus -- This is the main input, so auto-focus on it.
autoFocus
>
<Button onClick={handleUploadClick} autoFocus>
<FormattedMessage
id='account_edit.upload_modal.step_upload.button'
defaultMessage='Browse files'

View File

@@ -63,7 +63,6 @@ export const NameModal: FC<BaseConfirmationModalProps> = ({ onClose }) => {
aria-labelledby={titleId}
counterMax={maxLength}
label=''
// eslint-disable-next-line jsx-a11y/no-autofocus -- This is a modal, it's fine.
autoFocus
/>
</ConfirmationModal>

View File

@@ -146,7 +146,6 @@ const InnerNodeModal: FC<{
? { variant: 'error', message: errorText }
: undefined
}
// eslint-disable-next-line jsx-a11y/no-autofocus -- We want to focus here as it's a modal.
autoFocus
/>
</>

View File

@@ -1,4 +1,4 @@
import { useEffect, useCallback } from 'react';
import { useEffect, useCallback, Suspense, lazy } from 'react';
import { useIntl, defineMessages } from 'react-intl';
@@ -12,6 +12,7 @@ import elephantUIPlane from '@/images/elephant_ui_plane.svg';
import { Column } from '@/mastodon/components/column';
import { ColumnHeader as LegacyColumnHeader } from '@/mastodon/components/column/header';
import { ColumnHeader } from '@/mastodon/components/column_header';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
import { isRedesignEnabled } from '@/mastodon/utils/environment';
import EditIcon from '@/material-icons/400-24px/edit_square.svg?react';
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
@@ -206,12 +207,14 @@ const Compose: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
/>
)}
<div className='scrollable'>
<ComposeFormContainer
// This is fine on this single-purpose view
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
/>
<div className='scrollable scrollable--flex'>
{isRedesignEnabled() ? (
<Suspense fallback={<LoadingIndicator />}>
<ComposeLazyForm autoFocus headless />
</Suspense>
) : (
<ComposeFormContainer autoFocus />
)}
</div>
<Helmet>
@@ -221,5 +224,11 @@ const Compose: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
);
};
const ComposeLazyForm = lazy(() =>
import('./redesign/index').then(({ RedesignComposeForm }) => ({
default: RedesignComposeForm,
})),
);
// eslint-disable-next-line import/no-default-export
export default Compose;

View File

@@ -195,7 +195,6 @@ const ComposeEmojiDropdown: React.FC<
showSkinTones={false}
// We need to cast as unknown as this requires a legacy class component.
notFound={NotFound as unknown as () => React.Component}
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
emojiTooltip
/>

View File

@@ -28,6 +28,7 @@ import { ComposeVisibility } from './visibility';
interface RedesignComposeFormProps {
autoFocus?: boolean;
headless?: boolean;
className?: string;
noMinimize?: boolean;
redirectOnSuccess?: boolean;
@@ -35,7 +36,14 @@ interface RedesignComposeFormProps {
export const RedesignComposeForm: React.FC<
RedesignComposeFormProps & React.ComponentPropsWithRef<'form'>
> = ({ autoFocus, className, noMinimize, redirectOnSuccess, ...props }) => {
> = ({
autoFocus,
headless,
className,
noMinimize,
redirectOnSuccess,
...props
}) => {
const type = useAppSelector(selectComposeType);
const { onEmojiPick, onSubmit } = useComposeHandlers(redirectOnSuccess);
@@ -48,13 +56,17 @@ export const RedesignComposeForm: React.FC<
role='dialog'
onSubmit={onSubmit}
aria-labelledby={titleId}
className={classNames(className, classes.root)}
className={classNames(
className,
classes.root,
headless && classes.headless,
)}
>
{(type === 'message' || type === 'replyPrivate') && (
<div className={classes.background} />
)}
<ComposeFormHeader id={titleId} noMinimize={noMinimize} />
{!headless && <ComposeFormHeader id={titleId} noMinimize={noMinimize} />}
<ComposeReply />
@@ -68,10 +80,7 @@ export const RedesignComposeForm: React.FC<
<ComposeSensitiveField />
<ComposeTextarea
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus={autoFocus}
>
<ComposeTextarea autoFocus={autoFocus}>
<ComposeAttachments className={classes.attachments} />
</ComposeTextarea>

View File

@@ -254,7 +254,6 @@ const ComposePollOption: React.FC<{
number: index + 1,
})}
maxLength={50}
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus={index === 0}
data-index={index}
spellCheck

View File

@@ -56,7 +56,6 @@ export const ComposeSensitiveField: React.FC = () => {
value={sensitiveText}
onChange={onChange}
onKeyDown={onKeyDown}
// eslint-disable-next-line jsx-a11y/no-autofocus -- Focuses on open
autoFocus
/>
);

View File

@@ -18,6 +18,23 @@
}
}
.headless {
border: 0;
box-shadow: none;
flex-grow: 1;
border-radius: 0;
padding-block-start: 0;
}
:global(.compose-standalone) .headless {
min-height: 200px;
// 138px = header, 235px = footer, 8px padding
height: calc(100vh - (138px + 235px + var(--space-2)));
max-width: 400px;
margin-inline: auto;
}
.background {
mask-repeat: repeat;
mask-image: url('@/images/composer_message.svg');

View File

@@ -1,4 +1,3 @@
/* eslint-disable jsx-a11y/no-autofocus */
import { lazy, Suspense, useCallback, useEffect, useState } from 'react';
import { FormattedMessage } from 'react-intl';

View File

@@ -364,7 +364,6 @@ const LoginForm: React.FC<{
aria-label={intl.formatMessage(messages.loginPrompt, {
example: EXAMPLE_VALUE,
})}
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
onChange={handleChange}
onFocus={handleFocus}

View File

@@ -1,15 +0,0 @@
import { AlertsController } from 'mastodon/components/alerts_controller';
import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';
import LoadingBarContainer from 'mastodon/features/ui/containers/loading_bar_container';
import ModalContainer from 'mastodon/features/ui/containers/modal_container';
const Compose = () => (
<>
<ComposeFormContainer autoFocus withoutNavigation redirectOnSuccess />
<AlertsController />
<ModalContainer />
<LoadingBarContainer className='loading-bar' />
</>
);
export default Compose;

View File

@@ -0,0 +1,49 @@
import { lazy, Suspense, useEffect } from 'react';
import { AlertsController } from '@/mastodon/components/alerts_controller';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
import ComposeFormContainer from '@/mastodon/features/compose/containers/compose_form_container';
import LoadingBarContainer from '@/mastodon/features/ui/containers/loading_bar_container';
import ModalContainer from '@/mastodon/features/ui/containers/modal_container';
import { isRedesignEnabled } from '@/mastodon/utils/environment';
const ComposeLazyForm = lazy(() =>
import('@/mastodon/features/compose/redesign/index').then(
({ RedesignComposeForm }) => ({
default: RedesignComposeForm,
}),
),
);
export const Compose: React.FC = () => {
return (
<>
{isRedesignEnabled() ? (
<RedesignCompose />
) : (
<ComposeFormContainer autoFocus withoutNavigation redirectOnSuccess />
)}
<AlertsController />
<ModalContainer />
<LoadingBarContainer className='loading-bar' />
</>
);
};
const RedesignCompose: React.FC = () => {
useEffect(() => {
document.documentElement.dataset.redesign = 'true';
return () => {
document.documentElement.dataset.redesign = 'false';
};
}, []);
return (
<Suspense fallback={<LoadingIndicator />}>
<ComposeLazyForm autoFocus headless redirectOnSuccess />
</Suspense>
);
};
// eslint-disable-next-line import/no-default-export
export default Compose;

View File

@@ -123,7 +123,6 @@ export const BoostModal: React.FC<{
? messages.cancel_reblog
: messages.reblog,
)}
/* eslint-disable-next-line jsx-a11y/no-autofocus -- We are in the modal */
autoFocus
/>
</div>

View File

@@ -109,7 +109,6 @@ export const ConfirmationModal: React.FC<
</>
)}
{/* eslint-disable jsx-a11y/no-autofocus -- we are in a modal and thus autofocusing is justified */}
<Button
type='submit'
loading={updating}
@@ -118,7 +117,6 @@ export const ConfirmationModal: React.FC<
>
{confirm}
</Button>
{/* eslint-enable */}
</ModalShellActions>
</ModalShell>
);