mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-13 02:36:36 -05:00
Composer redesign: Fixes bug with new post button (#40166)
This commit is contained in:
@@ -6,20 +6,27 @@ import { closeModal } from '@/mastodon/actions/modal';
|
||||
import { Button } from '@/mastodon/components/button/redesign';
|
||||
import {
|
||||
focusComposerTextarea,
|
||||
openNewComposer,
|
||||
resetComposer,
|
||||
} from '@/mastodon/reducers/slices/composer';
|
||||
import { useAppDispatch } from '@/mastodon/store';
|
||||
|
||||
import classes from './modals.module.scss';
|
||||
|
||||
const ComposerCancelConfirmModal: React.FC = () => {
|
||||
const ComposerCancelConfirmModal: React.FC<{ openNew?: boolean }> = ({
|
||||
openNew,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const handleDelete = useCallback(() => {
|
||||
dispatch(resetComposer());
|
||||
if (openNew) {
|
||||
dispatch(openNewComposer({ force: true }));
|
||||
} else {
|
||||
dispatch(resetComposer());
|
||||
}
|
||||
dispatch(
|
||||
closeModal({ modalType: 'COMPOSER_DRAFT_DELETE', ignoreFocus: false }),
|
||||
);
|
||||
}, [dispatch]);
|
||||
}, [dispatch, openNew]);
|
||||
const handleContinue = useCallback(() => {
|
||||
dispatch(
|
||||
closeModal({ modalType: 'COMPOSER_DRAFT_DELETE', ignoreFocus: false }),
|
||||
|
||||
@@ -6,7 +6,7 @@ import { ArrowsOutSimpleIcon, MinusIcon, XIcon } from '@phosphor-icons/react';
|
||||
|
||||
import { IconButton } from '@/mastodon/components/button/redesign';
|
||||
import {
|
||||
hideComposer,
|
||||
closeComposer,
|
||||
minimizeComposerToggle,
|
||||
selectIsMinimized,
|
||||
} from '@/mastodon/reducers/slices/composer';
|
||||
@@ -63,7 +63,7 @@ export const ComposeFormHeader: React.FC<{
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const onClose = useCallback(() => {
|
||||
dispatch(hideComposer());
|
||||
dispatch(closeComposer());
|
||||
}, [dispatch]);
|
||||
const onMinimize = useCallback(() => {
|
||||
dispatch(minimizeComposerToggle());
|
||||
|
||||
@@ -65,6 +65,27 @@ const composerSlice = createSlice({
|
||||
export const composer = composerSlice.reducer;
|
||||
export const { minimizeComposerToggle } = composerSlice.actions;
|
||||
|
||||
export const selectComposerIsChanged = createAppSelector(
|
||||
[
|
||||
(state) => state.compose.get('text') as string,
|
||||
(state) => state.compose.get('spoiler_text') as string,
|
||||
(state) => !!state.compose.get('poll'),
|
||||
(state) => !!state.compose.get('quoted_status_id'),
|
||||
(state) =>
|
||||
state.compose.get(
|
||||
'media_attachments',
|
||||
) as unknown as Immutable.List<unknown>,
|
||||
(state) => Number(state.compose.get('pending_media_attachments')),
|
||||
],
|
||||
(text, spoilerText, hasPoll, hasQuote, attachments, pendingAttachmentsNum) =>
|
||||
text.trim().length > 0 ||
|
||||
spoilerText.trim().length > 0 ||
|
||||
hasPoll ||
|
||||
hasQuote ||
|
||||
attachments.size > 0 ||
|
||||
pendingAttachmentsNum > 0,
|
||||
);
|
||||
|
||||
interface ComposeNewPost {
|
||||
type?: 'post';
|
||||
}
|
||||
@@ -76,10 +97,26 @@ interface ComposeNewMessage {
|
||||
type: 'message';
|
||||
toAccountId?: string;
|
||||
}
|
||||
type ComposeNewPayload = ComposeNewPost | ComposeNewReply | ComposeNewMessage;
|
||||
type ComposeNewPayload = (
|
||||
| ComposeNewPost
|
||||
| ComposeNewReply
|
||||
| ComposeNewMessage
|
||||
) & { force?: boolean };
|
||||
|
||||
export const openNewComposer = createAppThunk(
|
||||
(payload: ComposeNewPayload, { dispatch, getState }) => {
|
||||
if (!payload.force && selectComposerIsChanged(getState())) {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'COMPOSER_DRAFT_DELETE',
|
||||
modalProps: {
|
||||
openNew: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(resetCompose());
|
||||
if (payload.type === 'message') {
|
||||
const account =
|
||||
@@ -93,6 +130,11 @@ export const openNewComposer = createAppThunk(
|
||||
dispatch(replyComposeById(payload.toStatusId));
|
||||
}
|
||||
dispatch(composerSlice.actions.showComposer());
|
||||
|
||||
// Delay for a frame to ensure the DOM has updated.
|
||||
requestAnimationFrame(() => {
|
||||
focusComposerTextarea();
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -101,15 +143,23 @@ export const resetComposer = createAppThunk((_arg, { dispatch }) => {
|
||||
dispatch(resetCompose());
|
||||
});
|
||||
|
||||
export const hideComposer = createAppThunk((_arg, { getState, dispatch }) => {
|
||||
const compose = getState().compose;
|
||||
const isChanged =
|
||||
!!compose.get('text') ||
|
||||
!!compose.get('spoiler_text') ||
|
||||
!!compose.get('poll') ||
|
||||
(compose.get('media_attachments') as unknown as Immutable.List<unknown>)
|
||||
.size > 0 ||
|
||||
Number(compose.get('pending_media_attachments')) > 0;
|
||||
export const closeComposer = createAppThunk((_arg, { getState, dispatch }) => {
|
||||
const isChanged = selectComposerIsChanged(getState());
|
||||
|
||||
if (!isChanged) {
|
||||
dispatch(resetComposer());
|
||||
} else {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'COMPOSER_DRAFT_DELETE',
|
||||
modalProps: {},
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export const newComposer = createAppThunk((_arg, { getState, dispatch }) => {
|
||||
const isChanged = selectComposerIsChanged(getState());
|
||||
|
||||
if (!isChanged) {
|
||||
dispatch(resetComposer());
|
||||
|
||||
Reference in New Issue
Block a user