mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2025-12-20 02:08:57 +00:00
Fix react picker positioning in narrow window
This commit is contained in:
@@ -6,12 +6,6 @@ import type { LocalizerType } from '../../types/I18N.std.js';
|
|||||||
import { AxoMenuBuilder } from '../../axo/AxoMenuBuilder.dom.js';
|
import { AxoMenuBuilder } from '../../axo/AxoMenuBuilder.dom.js';
|
||||||
import { isPinnedMessagesEnabled } from '../../util/isPinnedMessagesEnabled.std.js';
|
import { isPinnedMessagesEnabled } from '../../util/isPinnedMessagesEnabled.std.js';
|
||||||
|
|
||||||
export type ContextMenuTriggerType = {
|
|
||||||
handleContextClick: (
|
|
||||||
event: React.MouseEvent<HTMLDivElement> | MouseEvent
|
|
||||||
) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
type MessageContextMenuProps = Readonly<{
|
type MessageContextMenuProps = Readonly<{
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
renderer: AxoMenuBuilder.Renderer;
|
renderer: AxoMenuBuilder.Renderer;
|
||||||
|
|||||||
@@ -3,14 +3,8 @@
|
|||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
import React, {
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
useCallback,
|
import type { ReactNode } from 'react';
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import type { ReactNode, Ref } from 'react';
|
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { Manager, Popper, Reference } from 'react-popper';
|
import { Manager, Popper, Reference } from 'react-popper';
|
||||||
import type { PreventOverflowModifier } from '@popperjs/core/lib/modifiers/preventOverflow.js';
|
import type { PreventOverflowModifier } from '@popperjs/core/lib/modifiers/preventOverflow.js';
|
||||||
@@ -39,10 +33,7 @@ import type {
|
|||||||
ForwardMessagesPayload,
|
ForwardMessagesPayload,
|
||||||
} from '../../state/ducks/globalModals.preload.js';
|
} from '../../state/ducks/globalModals.preload.js';
|
||||||
import { useScrollerLock } from '../../hooks/useScrollLock.dom.js';
|
import { useScrollerLock } from '../../hooks/useScrollLock.dom.js';
|
||||||
import {
|
import { MessageContextMenu } from './MessageContextMenu.dom.js';
|
||||||
type ContextMenuTriggerType,
|
|
||||||
MessageContextMenu,
|
|
||||||
} from './MessageContextMenu.dom.js';
|
|
||||||
import { ForwardMessagesModalType } from '../ForwardMessagesModal.dom.js';
|
import { ForwardMessagesModalType } from '../ForwardMessagesModal.dom.js';
|
||||||
import { useGroupedAndOrderedReactions } from '../../util/groupAndOrderReactions.dom.js';
|
import { useGroupedAndOrderedReactions } from '../../util/groupAndOrderReactions.dom.js';
|
||||||
import { isNotNil } from '../../util/isNotNil.std.js';
|
import { isNotNil } from '../../util/isNotNil.std.js';
|
||||||
@@ -108,7 +99,6 @@ export type Props = PropsData &
|
|||||||
export function TimelineMessage(props: Props): JSX.Element {
|
export function TimelineMessage(props: Props): JSX.Element {
|
||||||
const {
|
const {
|
||||||
attachments,
|
attachments,
|
||||||
author,
|
|
||||||
canDownload,
|
canDownload,
|
||||||
canCopy,
|
canCopy,
|
||||||
canEditMessage,
|
canEditMessage,
|
||||||
@@ -149,7 +139,6 @@ export function TimelineMessage(props: Props): JSX.Element {
|
|||||||
const [reactionPickerRoot, setReactionPickerRoot] = useState<
|
const [reactionPickerRoot, setReactionPickerRoot] = useState<
|
||||||
HTMLDivElement | undefined
|
HTMLDivElement | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
const menuTriggerRef = useRef<ContextMenuTriggerType | null>(null);
|
|
||||||
const [pinMessageDialogOpen, setPinMessageDialogOpen] = useState(false);
|
const [pinMessageDialogOpen, setPinMessageDialogOpen] = useState(false);
|
||||||
|
|
||||||
const isWindowWidthNotNarrow =
|
const isWindowWidthNotNarrow =
|
||||||
@@ -172,10 +161,6 @@ export function TimelineMessage(props: Props): JSX.Element {
|
|||||||
};
|
};
|
||||||
}, [containerElementRef]);
|
}, [containerElementRef]);
|
||||||
|
|
||||||
// This id is what connects our triple-dot click with our associated pop-up menu.
|
|
||||||
// It needs to be unique.
|
|
||||||
const triggerId = String(id || `${author.id}-${timestamp}`);
|
|
||||||
|
|
||||||
const toggleReactionPicker = useCallback(
|
const toggleReactionPicker = useCallback(
|
||||||
(onlyRemove = false): void => {
|
(onlyRemove = false): void => {
|
||||||
if (reactionPickerRoot) {
|
if (reactionPickerRoot) {
|
||||||
@@ -392,10 +377,8 @@ export function TimelineMessage(props: Props): JSX.Element {
|
|||||||
<Manager>
|
<Manager>
|
||||||
<MessageMenu
|
<MessageMenu
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
triggerId={triggerId}
|
|
||||||
isWindowWidthNotNarrow={isWindowWidthNotNarrow}
|
isWindowWidthNotNarrow={isWindowWidthNotNarrow}
|
||||||
direction={direction}
|
direction={direction}
|
||||||
menuTriggerRef={menuTriggerRef}
|
|
||||||
onDownload={handleDownload}
|
onDownload={handleDownload}
|
||||||
onReplyToMessage={canReply ? handleReplyToMessage : null}
|
onReplyToMessage={canReply ? handleReplyToMessage : null}
|
||||||
onReact={canReact ? handleReact : null}
|
onReact={canReact ? handleReact : null}
|
||||||
@@ -433,10 +416,8 @@ export function TimelineMessage(props: Props): JSX.Element {
|
|||||||
);
|
);
|
||||||
}, [
|
}, [
|
||||||
i18n,
|
i18n,
|
||||||
triggerId,
|
|
||||||
isWindowWidthNotNarrow,
|
isWindowWidthNotNarrow,
|
||||||
direction,
|
direction,
|
||||||
menuTriggerRef,
|
|
||||||
canReply,
|
canReply,
|
||||||
canReact,
|
canReact,
|
||||||
handleDownload,
|
handleDownload,
|
||||||
@@ -484,9 +465,7 @@ export function TimelineMessage(props: Props): JSX.Element {
|
|||||||
|
|
||||||
type MessageMenuProps = {
|
type MessageMenuProps = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
triggerId: string;
|
|
||||||
isWindowWidthNotNarrow: boolean;
|
isWindowWidthNotNarrow: boolean;
|
||||||
menuTriggerRef: Ref<ContextMenuTriggerType>;
|
|
||||||
onDownload: (() => void) | null;
|
onDownload: (() => void) | null;
|
||||||
onReplyToMessage: (() => void) | null;
|
onReplyToMessage: (() => void) | null;
|
||||||
onReact: (() => void) | null;
|
onReact: (() => void) | null;
|
||||||
@@ -595,21 +574,33 @@ function MessageMenu({
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{renderMessageContextMenu(
|
<Reference>
|
||||||
'AxoDropdownMenu',
|
{({ ref: popperRef }) => {
|
||||||
<button
|
// Only attach the popper reference to the collapsed menu button if
|
||||||
type="button"
|
// the reaction button is not visible (it is hidden when the
|
||||||
aria-label={i18n('icu:messageContextMenuButton')}
|
// timeline is narrow)
|
||||||
className={classNames(
|
const maybePopperRef = !isWindowWidthNotNarrow
|
||||||
'module-message__buttons__menu',
|
? popperRef
|
||||||
`module-message__buttons__download--${direction}`
|
: undefined;
|
||||||
)}
|
|
||||||
onDoubleClick={ev => {
|
return renderMessageContextMenu(
|
||||||
// Prevent double click from triggering the replyToMessage action
|
'AxoDropdownMenu',
|
||||||
ev.stopPropagation();
|
<button
|
||||||
}}
|
ref={maybePopperRef}
|
||||||
/>
|
type="button"
|
||||||
)}
|
aria-label={i18n('icu:messageContextMenuButton')}
|
||||||
|
className={classNames(
|
||||||
|
'module-message__buttons__menu',
|
||||||
|
`module-message__buttons__download--${direction}`
|
||||||
|
)}
|
||||||
|
onDoubleClick={ev => {
|
||||||
|
// Prevent double click from triggering the replyToMessage action
|
||||||
|
ev.stopPropagation();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Reference>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1843,13 +1843,6 @@
|
|||||||
"updated": "2021-01-20T21:30:08.430Z",
|
"updated": "2021-01-20T21:30:08.430Z",
|
||||||
"reasonDetail": "Doesn't touch the DOM."
|
"reasonDetail": "Doesn't touch the DOM."
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"rule": "React-useRef",
|
|
||||||
"path": "ts/components/conversation/TimelineMessage.dom.tsx",
|
|
||||||
"line": " const menuTriggerRef = useRef<ContextMenuTriggerType | null>(null);",
|
|
||||||
"reasonCategory": "usageTrusted",
|
|
||||||
"updated": "2023-12-08T20:28:57.595Z"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"rule": "React-useRef",
|
"rule": "React-useRef",
|
||||||
"path": "ts/components/conversation/TypingBubble.dom.tsx",
|
"path": "ts/components/conversation/TypingBubble.dom.tsx",
|
||||||
|
|||||||
Reference in New Issue
Block a user