Status interaction action (#39681)

This commit is contained in:
Echo authored and GitHub committed 2026-07-02 13:12:13 +00:00
1 parent 72085f7d52
commit eb167fdc3b
9 files changed
+414 -79

No files matched your search

@@ -16,19 +16,9 @@ import {
import type { AttachmentArgs } from './testing';
import { attachmentArgTypes, attachmentFactory } from './testing';
import type { StatusContextType } from './types';
import { TypedStatus } from './types';
type ContextTypes =
| 'account'
| 'bookmarks'
| 'detailed'
| 'favourites'
| 'home'
| 'notifications'
| 'public'
| 'search'
| 'thread';
interface StatusStoryProps extends AttachmentArgs {
// Contents
text: string;
@@ -51,7 +41,7 @@ interface StatusStoryProps extends AttachmentArgs {
// Display
showThread?: boolean;
contextType?: ContextTypes;
contextType?: StatusContextType;
showCounters?: boolean;
favouriteCount?: number;
reblogCount?: number;
@@ -319,6 +309,7 @@ const meta = {
options: [
'account',
'bookmarks',
'composer',
'detailed',
'favourites',
'home',
@@ -326,7 +317,7 @@ const meta = {
'public',
'search',
'thread',
] satisfies ContextTypes[],
] satisfies StatusContextType[],
},
hidden: categoryDisplay,
muted: categoryDisplay,
@@ -1,5 +1,6 @@
import type { ComponentType, MouseEventHandler, ReactNode } from 'react';
import StatusContainer from '@/mastodon/containers/status_container';
import type { Account as TAccount } from '@/mastodon/models/account';
import type { Status as TStatus } from '@/mastodon/models/status';
@@ -7,15 +8,55 @@ import Status from '../status';
import type { StatusHeaderRenderFn } from './header';
// Taken from the Status component.
export interface StatusProps {
status: TStatus;
export type StatusContextType =
| 'account'
| 'bookmarks'
| 'composer'
| 'detailed'
| 'favourites'
| 'home'
| `list:${string}`
| 'notifications'
| 'public'
| 'search'
| 'thread';
export interface StatusContainerProps {
id?: string | null;
account?: TAccount;
children?: ReactNode;
previousId?: string;
nextInReplyToId?: string;
rootId?: string;
onClick?: MouseEventHandler<HTMLDivElement>;
muted?: boolean;
hidden?: boolean;
unread?: boolean;
featured?: boolean;
showThread?: boolean;
showActions?: boolean;
isQuotedPost?: boolean;
shouldHighlightOnMount?: boolean;
contextType?: StatusContextType;
withCounters?: boolean;
unfocusable?: boolean;
headerRenderFn?: StatusHeaderRenderFn;
getScrollPosition?: () => null | { height: number; top: number };
updateScrollBottom?: (snapshot: number) => void;
cacheMediaWidth?: (width: number) => void;
cachedMediaWidth?: number;
scrollKey?: string;
skipPrepend?: boolean;
avatarSize?: number;
withDismiss?: boolean;
}
export const TypedStatusContainer =
StatusContainer as ComponentType<StatusContainerProps>;
// Taken from the Status component.
export interface StatusProps extends StatusContainerProps {
status: TStatus;
nextInReplyToId?: string;
onReply: (status: TStatus) => void;
onFavourite: (status: TStatus) => void;
onReblog: (status: TStatus, event?: unknown) => void;
@@ -44,31 +85,12 @@ export interface StatusProps {
onToggleCollapsed: (status: TStatus, isCollapsed: boolean) => void;
onTranslate: (status: TStatus) => void;
onInteractionModal?: (type: string, status: TStatus) => void;
muted?: boolean;
hidden?: boolean;
unread?: boolean;
featured?: boolean;
showThread?: boolean;
showActions?: boolean;
isQuotedPost?: boolean;
shouldHighlightOnMount?: boolean;
getScrollPosition?: () => null | { height: number; top: number };
updateScrollBottom?: (snapshot: number) => void;
cacheMediaWidth?: (width: number) => void;
cachedMediaWidth?: number;
scrollKey?: string;
skipPrepend?: boolean;
avatarSize?: number;
deployPictureInPicture: (
status: TStatus,
type: string,
mediaProps: unknown,
) => void;
unfocusable?: boolean;
headerRenderFn?: StatusHeaderRenderFn;
pictureInPicture: Immutable.Map<'inUse' | 'available', boolean>;
contextType?: string;
withCounters?: boolean;
}
export const TypedStatus = Status as ComponentType<StatusProps>;
@@ -1,16 +1,16 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import type { ComponentType, ReactNode } from 'react';
import { defineMessage, FormattedMessage, useIntl } from 'react-intl';
import type { Map as ImmutableMap } from 'immutable';
import type { Merge } from 'type-fest';
import CancelFillIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
import { fetchRelationships } from 'mastodon/actions/accounts';
import { revealAccount } from 'mastodon/actions/accounts_typed';
import { fetchStatus } from 'mastodon/actions/statuses';
import { LearnMoreLink } from 'mastodon/components/learn_more_link';
import StatusContainer from 'mastodon/containers/status_container';
import { domain } from 'mastodon/initial_state';
import type { Account } from 'mastodon/models/account';
import type { Status } from 'mastodon/models/status';
@@ -23,6 +23,8 @@ import { Button } from './button';
import { IconButton } from './icon_button';
import type { StatusHeaderRenderFn } from './status/header';
import { StatusHeader } from './status/header';
import { TypedStatusContainer } from './status/types';
import type { StatusContainerProps, StatusContextType } from './status/types';
const MAX_QUOTE_POSTS_NESTING_LEVEL = 1;
@@ -143,24 +145,9 @@ const FilteredQuote: React.FC<{
);
};
// Adds a wrapper around StatusContainer as the types aren't inheriting correctly with Redux + React 19.
// TODO: Remove this after the Status component is in TS.
interface StatusContainerForQuotesProps {
id?: string | null;
contextType?: string;
isQuotedPost?: boolean;
avatarSize?: number;
headerRenderFn?: StatusHeaderRenderFn;
children?: ReactNode;
[key: string]: unknown;
}
const StatusContainerWithChildren =
StatusContainer as unknown as ComponentType<StatusContainerForQuotesProps>;
interface QuotedStatusProps {
quote: QuoteMap;
contextType?: string;
contextType?: StatusContextType;
parentQuotePostId?: string | null;
variant?: 'full' | 'link';
nestingLevel?: number;
@@ -354,7 +341,7 @@ export const QuotedStatus: React.FC<QuotedStatusProps> = ({
return (
<div className='status__quote'>
<StatusContainerWithChildren
<TypedStatusContainer
isQuotedPost
id={quotedStatusId}
contextType={contextType}
@@ -372,16 +359,17 @@ export const QuotedStatus: React.FC<QuotedStatusProps> = ({
nestingLevel={nestingLevel + 1}
/>
)}
</StatusContainerWithChildren>
</TypedStatusContainer>
</div>
);
};
export interface StatusQuoteManagerProps {
id: string;
contextType?: string;
[key: string]: unknown;
}
export type StatusQuoteManagerProps = Merge<
StatusContainerProps,
{
id: string;
}
>;
/**
* This wrapper component takes a status ID and, if the associated status
@@ -399,15 +387,15 @@ export const StatusQuoteManager = (props: StatusQuoteManagerProps) => {
if (quote) {
return (
<StatusContainerWithChildren {...props}>
<TypedStatusContainer {...props}>
<QuotedStatus
quote={quote}
parentQuotePostId={status?.get('id') as string}
contextType={props.contextType}
/>
</StatusContainerWithChildren>
</TypedStatusContainer>
);
}
return <StatusContainerWithChildren {...props} />;
return <TypedStatusContainer {...props} />;
};