Skip to content

Commit 2a90233

Browse files
chore: fix ReactionSelector dialog placement (#3003)
### 🎯 Goal Fixes the rendering of the ReactionSelector where if opened in thread, it'd open in the left upper corner. before/after <img width="1200" height="609" alt="Screenshot 2026-03-12 at 12 19 43 PM" src="https://github.com/user-attachments/assets/5ae9c34c-92e7-4856-833e-2b0edd6c97b2" /> <img width="1200" height="609" alt="Screenshot 2026-03-12 at 12 19 38 PM" src="https://github.com/user-attachments/assets/27006166-833f-4ca4-8120-c494c9a0aa54" />
1 parent 29bb396 commit 2a90233

3 files changed

Lines changed: 29 additions & 13 deletions

File tree

src/components/MessageActions/MessageActions.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useBaseMessageActionSetFilter, useSplitMessageActionSet } from './hooks
1313
import { defaultMessageActionSet } from './defaults';
1414
import { ActionsIcon, type MESSAGE_ACTIONS } from '../Message';
1515
import { Button } from '../Button';
16+
import { ReactionSelector } from '../Reactions';
1617

1718
type BaseMessageActionSetItem = {
1819
placement: 'quick' | 'dropdown';
@@ -49,7 +50,7 @@ export const MessageActions = ({
4950
messageActionSet = defaultMessageActionSet,
5051
}: MessageActionsProps) => {
5152
const { theme } = useChatContext();
52-
const { isMyMessage, message } = useMessageContext();
53+
const { isMyMessage, message, threadList } = useMessageContext();
5354
const { t } = useTranslationContext();
5455
const [actionsBoxButtonElement, setActionsBoxButtonElement] =
5556
useState<HTMLSpanElement | null>(null);
@@ -64,7 +65,10 @@ export const MessageActions = ({
6465
);
6566

6667
const dropdownDialogId = `message-actions--${message.id}`;
67-
const reactionSelectorDialogId = `reaction-selector--${message.id}`;
68+
const reactionSelectorDialogId = ReactionSelector.getReactionSelectorDialogId({
69+
messageId: message.id,
70+
threadList,
71+
});
6872
const { dialog, dialogManager } = useDialogOnNearestManager({ id: dropdownDialogId });
6973
const dropdownDialogIsOpen = useDialogIsOpen(dropdownDialogId, dialogManager?.id);
7074
const reactionSelectorDialogIsOpen = useDialogIsOpen(

src/components/Reactions/ReactionSelector.tsx

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useMemo, useState } from 'react';
1+
import React, { type JSX, useMemo, useState } from 'react';
22
import clsx from 'clsx';
33

44
import { useDialog } from '../Dialog';
@@ -20,9 +20,17 @@ export type ReactionSelectorProps = {
2020
own_reactions?: ReactionResponse[];
2121
};
2222

23+
interface ReactionSelectorInterface {
24+
(props: ReactionSelectorProps): JSX.Element;
25+
getReactionSelectorDialogId: (_: {
26+
messageId: string;
27+
threadList?: boolean;
28+
}) => `reaction-selector${'-thread' | ''}--${string}`;
29+
}
30+
2331
const stableOwnReactions: ReactionResponse[] = [];
2432

25-
const UnMemoizedReactionSelector = (props: ReactionSelectorProps) => {
33+
export const ReactionSelector: ReactionSelectorInterface = (props) => {
2634
const { handleReaction: propHandleReaction, own_reactions: propOwnReactions } = props;
2735
const [extendedListOpen, setExtendedListOpen] = useState(false);
2836

@@ -33,8 +41,12 @@ const UnMemoizedReactionSelector = (props: ReactionSelectorProps) => {
3341
closeReactionSelectorOnClick,
3442
handleReaction: contextHandleReaction,
3543
message,
44+
threadList,
3645
} = useMessageContext('ReactionSelector');
37-
const dialogId = `reaction-selector--${message.id}`;
46+
const dialogId = ReactionSelector.getReactionSelectorDialogId({
47+
messageId: message.id,
48+
threadList,
49+
});
3850
const dialog = useDialog({ id: dialogId });
3951

4052
const handleReaction = propHandleReaction ?? contextHandleReaction;
@@ -136,9 +148,7 @@ const UnMemoizedReactionSelector = (props: ReactionSelectorProps) => {
136148
);
137149
};
138150

139-
/**
140-
* Component that allows a user to select a reaction.
141-
*/
142-
export const ReactionSelector = React.memo(
143-
UnMemoizedReactionSelector,
144-
) as typeof UnMemoizedReactionSelector;
151+
ReactionSelector.getReactionSelectorDialogId = (({ messageId, threadList }) => {
152+
const dialogIdNamespace = threadList ? '-thread' : '';
153+
return `reaction-selector${dialogIdNamespace}--${messageId}`;
154+
}) satisfies ReactionSelectorInterface['getReactionSelectorDialogId'];

src/components/Reactions/ReactionSelectorWithButton.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ export const ReactionSelectorWithButton = ({
2828
const { ReactionSelector = DefaultReactionSelector } =
2929
useComponentContext('MessageOptions');
3030
const buttonRef = useRef<ElementRef<'button'>>(null);
31-
const dialogIdNamespace = threadList ? '-thread-' : '';
32-
const dialogId = `reaction-selector${dialogIdNamespace}--${message.id}`;
31+
const dialogId = DefaultReactionSelector.getReactionSelectorDialogId({
32+
messageId: message.id,
33+
threadList,
34+
});
3335
const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });
3436
const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);
3537

0 commit comments

Comments
 (0)