From 63574bd275edfb7b6e277abef2df8223550f271d Mon Sep 17 00:00:00 2001
From: Echo
Date: Tue, 29 Sep 2026 15:28:34 +0000
Subject: [PATCH] Composer redesign: Sensitive field prevent from submitting
and change label (#40749)
---
.../features/compose/redesign/index.tsx | 44 ++-----------
.../features/compose/redesign/sensitive.tsx | 63 +++++++++++++++++++
app/javascript/mastodon/locales/en.json | 2 +-
3 files changed, 69 insertions(+), 40 deletions(-)
create mode 100644 app/javascript/mastodon/features/compose/redesign/sensitive.tsx
diff --git a/app/javascript/mastodon/features/compose/redesign/index.tsx b/app/javascript/mastodon/features/compose/redesign/index.tsx
index 628c9f18084..9cef2cecb09 100644
--- a/app/javascript/mastodon/features/compose/redesign/index.tsx
+++ b/app/javascript/mastodon/features/compose/redesign/index.tsx
@@ -1,7 +1,7 @@
import type React from 'react';
import { useCallback, useEffect, useId } from 'react';
-import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
+import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
@@ -9,17 +9,14 @@ import { FlagIcon, LockSimpleOpenIcon } from '@phosphor-icons/react';
import {
changeComposeSpoilerness,
- changeComposeSpoilerText,
insertEmojiCompose,
} from '@/mastodon/actions/compose';
import { ToggleButton } from '@/mastodon/components/button/redesign';
-import { TextInputField } from '@/mastodon/components/form_fields/redesign';
import { normalizeKey } from '@/mastodon/components/hotkeys/utils';
import { Icon, useIconWeight } from '@/mastodon/components/icon';
import {
closeComposer,
getComposerTextarea,
- requestComposerFocus,
submitComposer,
} from '@/mastodon/reducers/slices/composer';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
@@ -36,17 +33,11 @@ import {
selectComposeSensitive,
selectComposeType,
} from './selectors';
+import { ComposeSensitiveField } from './sensitive';
import classes from './styles.module.scss';
import { ComposeTextarea } from './textarea';
import { ComposeVisibility } from './visibility';
-const messages = defineMessages({
- sensitiveText: {
- id: 'compose.sensitive.text',
- defaultMessage: 'Sensitive content description',
- },
-});
-
interface RedesignComposeFormProps {
autoFocus?: boolean;
className?: string;
@@ -58,12 +49,11 @@ export const RedesignComposeForm: React.FC<
RedesignComposeFormProps & React.ComponentPropsWithRef<'form'>
> = ({ autoFocus, className, noMinimize, redirectOnSuccess, ...props }) => {
const type = useAppSelector(selectComposeType);
- const { sensitive, sensitiveText } = useAppSelector(selectComposeSensitive);
+ const { sensitive } = useAppSelector(selectComposeSensitive);
- const { onSensitiveChange, onSensitiveTextChange, onEmojiPick, onSubmit } =
+ const { onSensitiveChange, onEmojiPick, onSubmit } =
useComposeHandlers(redirectOnSuccess);
- const intl = useIntl();
const titleId = useId();
const sensitiveIcon = useIconWeight(FlagIcon, sensitive && 'fill');
@@ -110,15 +100,7 @@ export const RedesignComposeForm: React.FC<
)}
- {sensitive && (
-
- )}
+
!!state.compose.get('spoiler'));
- useEffect(() => {
- if (!isSensitive) {
- dispatch(requestComposerFocus());
- }
- }, [isSensitive, dispatch]);
-
const onSensitiveChange = useCallback(() => {
dispatch(changeComposeSpoilerness());
}, [dispatch]);
- const onSensitiveTextChange: React.ChangeEventHandler =
- useCallback(
- (event) => {
- dispatch(changeComposeSpoilerText(event.target.value));
- },
- [dispatch],
- );
const onEmojiPick: OnEmojiPick = useCallback(
(emoji) => {
@@ -219,6 +186,5 @@ function useComposeHandlers(redirectOnSuccess?: boolean) {
onSubmit,
onEmojiPick,
onSensitiveChange,
- onSensitiveTextChange,
};
}
diff --git a/app/javascript/mastodon/features/compose/redesign/sensitive.tsx b/app/javascript/mastodon/features/compose/redesign/sensitive.tsx
new file mode 100644
index 00000000000..2971089ca61
--- /dev/null
+++ b/app/javascript/mastodon/features/compose/redesign/sensitive.tsx
@@ -0,0 +1,63 @@
+import { useCallback, useEffect } from 'react';
+
+import { defineMessages, useIntl } from 'react-intl';
+
+import { changeComposeSpoilerText } from '@/mastodon/actions/compose';
+import { TextInputField } from '@/mastodon/components/form_fields';
+import { normalizeKey } from '@/mastodon/components/hotkeys/utils';
+import { requestComposerFocus } from '@/mastodon/reducers/slices/composer';
+import { useAppDispatch, useAppSelector } from '@/mastodon/store';
+
+import { selectComposeSensitive } from './selectors';
+
+const messages = defineMessages({
+ sensitiveText: {
+ id: 'compose.sensitive.text',
+ defaultMessage: 'Content warning',
+ },
+});
+
+export const ComposeSensitiveField: React.FC = () => {
+ const { sensitive, sensitiveText } = useAppSelector(selectComposeSensitive);
+
+ const intl = useIntl();
+ const dispatch = useAppDispatch();
+ const isSensitive = useAppSelector((state) => !!state.compose.get('spoiler'));
+ useEffect(() => {
+ if (!isSensitive) {
+ dispatch(requestComposerFocus());
+ }
+ }, [isSensitive, dispatch]);
+
+ const onChange: React.ChangeEventHandler = useCallback(
+ (event) => {
+ dispatch(changeComposeSpoilerText(event.target.value));
+ },
+ [dispatch],
+ );
+ const onKeyDown: React.KeyboardEventHandler = useCallback(
+ (event) => {
+ const key = normalizeKey(event.key);
+ if (key === 'enter') {
+ event.preventDefault();
+ dispatch(requestComposerFocus());
+ return false;
+ }
+ return;
+ },
+ [dispatch],
+ );
+ if (!sensitive) {
+ return null;
+ }
+ return (
+
+ );
+};
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 823cd8d6ca3..25d05f9237c 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -574,7 +574,7 @@
"compose.reply_private.title.new": "New private reply",
"compose.saved.body": "Post saved.",
"compose.sensitive": "Sensitive",
- "compose.sensitive.text": "Sensitive content description",
+ "compose.sensitive.text": "Content warning",
"compose.switch_modal.back": "Back",
"compose.switch_modal.body": "Your message has limited visibility. If you convert to a post, it will switch to your default post visibility.",
"compose.switch_modal.continue": "Continue",