diff --git a/app/main.ts b/app/main.ts index 312c02a495c1..37c24c14a86b 100644 --- a/app/main.ts +++ b/app/main.ts @@ -2291,7 +2291,7 @@ ipc.on('get-config', async event => { proxyUrl: process.env.HTTPS_PROXY || process.env.https_proxy || undefined, contentProxyUrl: config.get('contentProxyUrl'), sfuUrl: config.get('sfuUrl'), - reducedMotionSetting: animationSettings.prefersReducedMotion, + reducedMotionSetting: DISABLE_GPU || animationSettings.prefersReducedMotion, registrationChallengeUrl: config.get('registrationChallengeUrl'), serverPublicParams: config.get('serverPublicParams'), serverTrustRoot: config.get('serverTrustRoot'), diff --git a/stylesheets/_conversation.scss b/stylesheets/_conversation.scss deleted file mode 100644 index 914e1f6ba62c..000000000000 --- a/stylesheets/_conversation.scss +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2015 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -@import './mixins'; - -@keyframes panel--in--ltr { - from { - // stylelint-disable-next-line declaration-property-value-disallowed-list - transform: translateX(500px); - } - - to { - // stylelint-disable-next-line declaration-property-value-disallowed-list - transform: translateX(0); - } -} - -@keyframes panel--in--rtl { - from { - // stylelint-disable-next-line declaration-property-value-disallowed-list - transform: translateX(-500px); - } - - to { - // stylelint-disable-next-line declaration-property-value-disallowed-list - transform: translateX(0); - } -} - -.conversation { - @include light-theme { - background-color: $color-white; - } - - @include dark-theme { - background-color: $color-gray-95; - } - - .panel { - &:not(.main) { - &:dir(ltr) { - animation: panel--in--ltr 350ms cubic-bezier(0.17, 0.17, 0, 1); - } - &:dir(rtl) { - animation: panel--in--rtl 350ms cubic-bezier(0.17, 0.17, 0, 1); - } - } - - &--static { - animation: none; - } - - &--remove { - &:dir(ltr) { - // stylelint-disable-next-line declaration-property-value-disallowed-list - transform: translateX(100%); - } - &:dir(rtl) { - // stylelint-disable-next-line declaration-property-value-disallowed-list - transform: translateX(-100%); - } - transition: transform 350ms cubic-bezier(0.17, 0.17, 0, 1); - } - } -} - -// Make sure the main panel is hidden when other panels are in the dom -.panel + .main.panel { - display: none; -} - -.message-detail-wrapper { - height: calc(100% - 48px); - width: 100%; - overflow-y: auto; -} - -.typing-bubble-wrapper { - margin-bottom: 20px; -} - -.contact-detail-pane { - overflow-y: scroll; - padding-top: 40px; - padding-bottom: 40px; -} - -.permissions-popup, -.debug-log-window { - .modal { - background-color: transparent; - padding: 0; - } -} diff --git a/stylesheets/_global.scss b/stylesheets/_global.scss index 231b6daf9682..189e0019127f 100644 --- a/stylesheets/_global.scss +++ b/stylesheets/_global.scss @@ -163,12 +163,6 @@ a { } } -.group-member-list { - .container { - outline: none; - } -} - $loading-height: 16px; .loading { diff --git a/stylesheets/_index.scss b/stylesheets/_index.scss deleted file mode 100644 index aeddb4357047..000000000000 --- a/stylesheets/_index.scss +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -#app-container { - height: 100%; -} - -.conversation-stack, -.inbox, -.no-conversation-open { - height: 100%; - overflow: hidden; - position: relative; -} - -.scrollable { - height: 100%; - overflow: auto; -} - -.no-conversation-open { - display: flex; - flex-direction: column; - text-align: center; - justify-content: center; - align-items: center; -} - -.conversation-stack { - flex-grow: 1; -} - -.conversation.placeholder { - text-align: center; - user-select: none; - - .container { - height: 100%; - width: 100%; - display: flex; - justify-content: center; - align-items: center; - } - .content { - display: inline-block; - } - - h3 { - font-size: large; - } -} diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss index 9e9ea35e90f7..4fb344e4dacc 100644 --- a/stylesheets/_modules.scss +++ b/stylesheets/_modules.scss @@ -6,6 +6,16 @@ // CAUTION: these styles are often overridden by other components // if you make changes to these, you must check EVERY component that uses +#app-container { + height: 100%; +} + +.inbox { + height: 100%; + overflow: hidden; + position: relative; +} + .module-title-bar-drag-area { -webkit-app-region: drag; height: var(--title-bar-drag-area-height); diff --git a/stylesheets/components/ConversationPanel.scss b/stylesheets/components/ConversationPanel.scss index 74fbf48b923a..006df9ccd8f2 100644 --- a/stylesheets/components/ConversationPanel.scss +++ b/stylesheets/components/ConversationPanel.scss @@ -8,7 +8,7 @@ position: absolute; top: 0; width: 100%; - z-index: $z-index-base; + z-index: $z-index-above-base; @include light-theme() { background-color: $color-white; @@ -18,12 +18,19 @@ background-color: $color-gray-95; } + &__body { + margin-top: calc(#{$header-height} + var(--title-bar-drag-area-height)); + } + &__header { - padding-top: var(--title-bar-drag-area-height); + align-items: center; display: flex; flex-direction: row; - align-items: center; height: calc(#{$header-height} + var(--title-bar-drag-area-height)); + padding-top: var(--title-bar-drag-area-height); + position: fixed; + width: 100%; + z-index: $z-index-base; @include light-theme { color: $color-gray-90; @@ -96,4 +103,17 @@ } } } + + &__overlay { + height: 100%; + inset-inline-start: 0; + position: absolute; + top: 0; + width: 100%; + z-index: $z-index-above-base; + } + + &__hidden { + display: none; + } } diff --git a/stylesheets/components/Inbox.scss b/stylesheets/components/Inbox.scss index e9757534d8d3..769a538e163f 100644 --- a/stylesheets/components/Inbox.scss +++ b/stylesheets/components/Inbox.scss @@ -5,4 +5,32 @@ display: flex; flex-direction: row; height: 100%; + + &__conversation-stack { + flex-grow: 1; + height: 100%; + overflow: hidden; + position: relative; + } + + &__no-conversation-open { + align-items: center; + display: flex; + flex-direction: column; + height: 100%; + justify-content: center; + overflow: hidden; + position: relative; + text-align: center; + } + + .__conversation { + @include light-theme { + background-color: $color-white; + } + + @include dark-theme { + background-color: $color-gray-95; + } + } } diff --git a/stylesheets/manifest.scss b/stylesheets/manifest.scss index 76c23c4c3cbd..0f306c859bce 100644 --- a/stylesheets/manifest.scss +++ b/stylesheets/manifest.scss @@ -12,10 +12,6 @@ @import 'progress'; @import 'emoji'; -// Old style: main view -@import 'index'; -@import 'conversation'; - // Old style: modules @import 'modules'; diff --git a/ts/components/Inbox.tsx b/ts/components/Inbox.tsx index 2bae1e55788d..7c71801d58e6 100644 --- a/ts/components/Inbox.tsx +++ b/ts/components/Inbox.tsx @@ -264,24 +264,24 @@ export function Inbox({
-
{renderLeftPane()}
+
{renderLeftPane()}
-
+
{selectedConversationId && (
{renderConversationView()}
)} {!prevConversationId && ( -
+
{renderMiniPlayer({ shouldFlow: false })}

{i18n('icu:welcomeToSignal')}

-

+

JSX.Element; renderTimeline: () => JSX.Element; renderPanel: () => JSX.Element | undefined; + shouldHideConversationView?: boolean; }; export function ConversationView({ @@ -29,6 +31,7 @@ export function ConversationView({ renderConversationHeader, renderTimeline, renderPanel, + shouldHideConversationView, }: PropsType): JSX.Element { const onDrop = React.useCallback( (event: React.DragEvent) => { @@ -92,18 +95,28 @@ export function ConversationView({ ); return ( -

-
- {renderConversationHeader()} -
-
-
-
- {renderTimeline()} -
+
+
+
+ {renderConversationHeader()}
-
- {renderCompositionArea()} +
+
+
+ {renderTimeline()} +
+
+
+ {renderCompositionArea()} +
{renderPanel()} diff --git a/ts/hooks/useKeyboardShortcuts.tsx b/ts/hooks/useKeyboardShortcuts.tsx index f042b3386861..552c8a01a91f 100644 --- a/ts/hooks/useKeyboardShortcuts.tsx +++ b/ts/hooks/useKeyboardShortcuts.tsx @@ -5,10 +5,9 @@ import { useCallback, useEffect } from 'react'; import { get } from 'lodash'; import { useSelector } from 'react-redux'; -import type { PanelRenderType } from '../types/Panels'; import type { StateType } from '../state/reducer'; import * as KeyboardLayout from '../services/keyboardLayout'; -import { getTopPanel } from '../state/selectors/conversations'; +import { getHasPanelOpen } from '../state/selectors/conversations'; import { isInFullScreenCall } from '../state/selectors/calling'; import { isShowingAnyModal } from '../state/selectors/globalModals'; import { shouldShowStoriesView } from '../state/selectors/stories'; @@ -30,10 +29,7 @@ function isCtrlOrAlt(ev: KeyboardEvent): boolean { } function useHasPanels(): boolean { - const topPanel = useSelector( - getTopPanel - ); - return Boolean(topPanel); + return useSelector(getHasPanelOpen); } function useHasGlobalModal(): boolean { diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index 21f57a79f6e1..292c7b9d4efc 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -470,7 +470,12 @@ export type ConversationsStateType = Readonly<{ targetedMessage: string | undefined; targetedMessageCounter: number; targetedMessageSource: TargetedMessageSource | undefined; - targetedConversationPanels: ReadonlyArray; + targetedConversationPanels: { + isAnimating: boolean; + direction: 'push' | 'pop' | undefined; + stack: ReadonlyArray; + watermark: number; + }; targetedMessageForDetails?: MessageAttributesType; lastSelectedMessage: MessageTimestamps | undefined; @@ -541,6 +546,8 @@ export const TARGETED_CONVERSATION_CHANGED = 'conversations/TARGETED_CONVERSATION_CHANGED'; const PUSH_PANEL = 'conversations/PUSH_PANEL'; const POP_PANEL = 'conversations/POP_PANEL'; +const PANEL_ANIMATION_DONE = 'conversations/PANEL_ANIMATION_DONE'; +const PANEL_ANIMATION_STARTED = 'conversations/PANEL_ANIMATION_STARTED'; export const MESSAGE_CHANGED = 'MESSAGE_CHANGED'; export const MESSAGE_DELETED = 'MESSAGE_DELETED'; export const MESSAGE_EXPIRED = 'conversations/MESSAGE_EXPIRED'; @@ -904,6 +911,14 @@ type PopPanelActionType = ReadonlyDeep<{ type: typeof POP_PANEL; payload: null; }>; +type PanelAnimationDoneActionType = ReadonlyDeep<{ + type: typeof PANEL_ANIMATION_DONE; + payload: null; +}>; +type PanelAnimationStartedActionType = ReadonlyDeep<{ + type: typeof PANEL_ANIMATION_STARTED; + payload: null; +}>; type ReplaceAvatarsActionType = ReadonlyDeep<{ type: typeof REPLACE_AVATARS; @@ -947,6 +962,8 @@ export type ConversationActionType = | MessageTargetedActionType | MessagesAddedActionType | MessagesResetActionType + | PanelAnimationStartedActionType + | PanelAnimationDoneActionType | PopPanelActionType | PushPanelActionType | RemoveAllConversationsActionType @@ -1042,6 +1059,8 @@ export const actions = { openGiftBadge, popPanelForConversation, pushPanelForConversation, + panelAnimationDone, + panelAnimationStarted, removeAllConversations, removeConversation, removeCustomColorOnConversations, @@ -2955,10 +2974,9 @@ function popPanelForConversation(): ThunkAction< > { return (dispatch, getState) => { const { conversations } = getState(); - const { targetedConversationPanels: selectedConversationPanels } = - conversations; + const { targetedConversationPanels } = conversations; - if (!selectedConversationPanels.length) { + if (!targetedConversationPanels.stack.length) { return; } @@ -2969,6 +2987,20 @@ function popPanelForConversation(): ThunkAction< }; } +function panelAnimationStarted(): PanelAnimationStartedActionType { + return { + type: PANEL_ANIMATION_STARTED, + payload: null, + }; +} + +function panelAnimationDone(): PanelAnimationDoneActionType { + return { + type: PANEL_ANIMATION_DONE, + payload: null, + }; +} + function deleteMessagesForEveryone( messageIds: ReadonlyArray ): ThunkAction< @@ -4087,7 +4119,12 @@ export function getEmptyState(): ConversationsStateType { lastSelectedMessage: undefined, selectedMessageIds: undefined, showArchived: false, - targetedConversationPanels: [], + targetedConversationPanels: { + isAnimating: false, + direction: undefined, + stack: [], + watermark: -1, + }, }; } @@ -4623,7 +4660,12 @@ export function reducer( return { ...omit(state, 'contactSpoofingReview'), selectedConversationId, - targetedConversationPanels: [], + targetedConversationPanels: { + isAnimating: false, + direction: undefined, + stack: [], + watermark: -1, + }, messagesLookup: omit(state.messagesLookup, [...messageIds]), messagesByConversation: omit(state.messagesByConversation, [ conversationId, @@ -5186,6 +5228,10 @@ export function reducer( existingConversation.scrollToMessageCounter + 1, }, }, + targetedConversationPanels: { + ...state.targetedConversationPanels, + watermark: -1, + }, }; } if (action.type === MESSAGE_DELETED) { @@ -5539,46 +5585,91 @@ export function reducer( } if (action.type === PUSH_PANEL) { + const currentStack = state.targetedConversationPanels.stack; + const watermark = Math.min( + state.targetedConversationPanels.watermark + 1, + currentStack.length + ); + const stack = [...currentStack.slice(0, watermark), action.payload]; + + const targetedConversationPanels = { + isAnimating: false, + direction: 'push' as const, + stack, + watermark, + }; + if (action.payload.type === PanelType.MessageDetails) { return { ...state, - targetedConversationPanels: [ - ...state.targetedConversationPanels, - action.payload, - ], + targetedConversationPanels, targetedMessageForDetails: action.payload.args.message, }; } return { ...state, - targetedConversationPanels: [ - ...state.targetedConversationPanels, - action.payload, - ], + targetedConversationPanels, }; } if (action.type === POP_PANEL) { - const { targetedConversationPanels: selectedConversationPanels } = state; - const nextPanels = [...selectedConversationPanels]; - const panel = nextPanels.pop(); - - if (!panel) { + if (state.targetedConversationPanels.watermark === -1) { return state; } - if (panel.type === PanelType.MessageDetails) { + const poppedPanel = + state.targetedConversationPanels.stack[ + state.targetedConversationPanels.watermark + ]; + + if (!poppedPanel) { + return state; + } + + const watermark = Math.max( + state.targetedConversationPanels.watermark - 1, + -1 + ); + + const targetedConversationPanels = { + isAnimating: false, + direction: 'pop' as const, + stack: state.targetedConversationPanels.stack, + watermark, + }; + + if (poppedPanel.type === PanelType.MessageDetails) { return { ...state, - targetedConversationPanels: nextPanels, + targetedConversationPanels, targetedMessageForDetails: undefined, }; } return { ...state, - targetedConversationPanels: nextPanels, + targetedConversationPanels, + }; + } + + if (action.type === PANEL_ANIMATION_STARTED) { + return { + ...state, + targetedConversationPanels: { + ...state.targetedConversationPanels, + isAnimating: true, + }, + }; + } + + if (action.type === PANEL_ANIMATION_DONE) { + return { + ...state, + targetedConversationPanels: { + ...state.targetedConversationPanels, + isAnimating: false, + }, }; } diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index fdc960e0e84e..85cb87861d2a 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -125,10 +125,10 @@ export const getConversationsByGroupId = createSelector( return state.conversationsByGroupId; } ); -export const getTargetedConversationsPanelsCount = createSelector( +export const getHasPanelOpen = createSelector( getConversations, - (state: ConversationsStateType): number => { - return state.targetedConversationPanels.length; + (state: ConversationsStateType): boolean => { + return state.targetedConversationPanels.watermark > 0; } ); export const getConversationsByUsername = createSelector( @@ -1133,17 +1133,53 @@ export const getHideStoryConversationIds = createSelector( ) ); -export const getTopPanel = createSelector( +export const getActivePanel = createSelector( getConversations, (conversations): PanelRenderType | undefined => - conversations.targetedConversationPanels[ - conversations.targetedConversationPanels.length - 1 + conversations.targetedConversationPanels.stack[ + conversations.targetedConversationPanels.watermark ] ); +type PanelInformationType = { + currPanel: PanelRenderType | undefined; + direction: 'push' | 'pop'; + prevPanel: PanelRenderType | undefined; +}; + +export const getPanelInformation = createSelector( + getConversations, + getActivePanel, + (conversations, currPanel): PanelInformationType | undefined => { + const { direction, watermark } = conversations.targetedConversationPanels; + + if (!direction) { + return; + } + + const watermarkDirection = + direction === 'push' ? watermark - 1 : watermark + 1; + const prevPanel = + conversations.targetedConversationPanels.stack[watermarkDirection]; + + return { + currPanel, + direction, + prevPanel, + }; + } +); + +export const getIsPanelAnimating = createSelector( + getConversations, + (conversations): boolean => { + return conversations.targetedConversationPanels.isAnimating; + } +); + export const getConversationTitle = createSelector( getIntl, - getTopPanel, + getActivePanel, (i18n, panel): string | undefined => getConversationTitleForPanelType(i18n, panel?.type) ); diff --git a/ts/state/smart/CompositionArea.tsx b/ts/state/smart/CompositionArea.tsx index 628be404a305..bd1972156c85 100644 --- a/ts/state/smart/CompositionArea.tsx +++ b/ts/state/smart/CompositionArea.tsx @@ -25,9 +25,9 @@ import { getEmojiSkinTone, getTextFormattingEnabled } from '../selectors/items'; import { getConversationSelector, getGroupAdminsSelector, + getHasPanelOpen, getLastEditableMessageId, getSelectedMessageIds, - getTargetedConversationsPanelsCount, isMissingRequiredProfileSharing, } from '../selectors/conversations'; import { getPropsForQuote } from '../selectors/message'; @@ -61,7 +61,7 @@ const mapStateToProps = (state: StateType, props: ExternalProps) => { const { id } = props; const platform = getPlatform(state); - const shouldHidePopovers = getTargetedConversationsPanelsCount(state) > 0; + const shouldHidePopovers = getHasPanelOpen(state); const conversationSelector = getConversationSelector(state); const conversation = conversationSelector(id); diff --git a/ts/state/smart/ConversationHeader.tsx b/ts/state/smart/ConversationHeader.tsx index c008b7de2697..78edb335a7a6 100644 --- a/ts/state/smart/ConversationHeader.tsx +++ b/ts/state/smart/ConversationHeader.tsx @@ -14,6 +14,7 @@ import { getPreferredBadgeSelector } from '../selectors/badges'; import { getConversationByUuidSelector, getConversationSelector, + getHasPanelOpen, isMissingRequiredProfileSharing, } from '../selectors/conversations'; import { CallMode } from '../../types/Calling'; @@ -85,9 +86,7 @@ export function SmartConversationHeader({ id }: OwnProps): JSX.Element { const badgeSelector = useSelector(getPreferredBadgeSelector); const badge = badgeSelector(conversation.badges); const i18n = useSelector(getIntl); - const hasPanelShowing = useSelector( - state => state.conversations.targetedConversationPanels.length > 0 - ); + const hasPanelShowing = useSelector(getHasPanelOpen); const outgoingCallButtonStyle = useSelector< StateType, OutgoingCallButtonStyle diff --git a/ts/state/smart/ConversationPanel.tsx b/ts/state/smart/ConversationPanel.tsx index f37a59936b25..7568310cd92e 100644 --- a/ts/state/smart/ConversationPanel.tsx +++ b/ts/state/smart/ConversationPanel.tsx @@ -1,11 +1,10 @@ // Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import React, { useEffect, useMemo, useRef } from 'react'; -import classNames from 'classnames'; +import type { MutableRefObject } from 'react'; +import React, { forwardRef, useEffect, useMemo, useRef, useState } from 'react'; import { useSelector } from 'react-redux'; import type { PanelRenderType } from '../../types/Panels'; -import type { StateType } from '../reducer'; import * as log from '../../logging/log'; import { ContactDetail } from '../../components/conversation/ContactDetail'; import { PanelType } from '../../types/Panels'; @@ -19,102 +18,259 @@ import { SmartGroupV2Permissions } from './GroupV2Permissions'; import { SmartMessageDetail } from './MessageDetail'; import { SmartPendingInvites } from './PendingInvites'; import { SmartStickerManager } from './StickerManager'; +import { getConversationTitleForPanelType } from '../../util/getConversationTitleForPanelType'; import { getIntl } from '../selectors/user'; -import { getConversationTitle, getTopPanel } from '../selectors/conversations'; -import { useConversationsActions } from '../ducks/conversations'; +import { + getIsPanelAnimating, + getPanelInformation, +} from '../selectors/conversations'; import { focusableSelectors } from '../../util/focusableSelectors'; +import { missingCaseError } from '../../util/missingCaseError'; +import { useConversationsActions } from '../ducks/conversations'; +import { useReducedMotion } from '../../hooks/useReducedMotion'; + +const ANIMATION_CONFIG = { + duration: 350, + easing: 'cubic-bezier(0.17, 0.17, 0, 1)', + fill: 'forwards' as const, +}; + +type AnimationProps = { + ref: MutableRefObject; + keyframes: Array; +}; + +function doAnimate({ + isRTL, + onAnimationStarted, + onAnimationDone, + overlay, + panel, +}: { + isRTL: boolean; + onAnimationStarted: () => unknown; + onAnimationDone: () => unknown; + overlay: AnimationProps<{ backgroundColor: string }>; + panel: AnimationProps<{ transform: string }>; +}) { + const animateNode = panel.ref.current; + if (!animateNode) { + return; + } + + const overlayAnimation = overlay.ref.current?.animate(overlay.keyframes, { + ...ANIMATION_CONFIG, + id: 'panel-animation-overlay', + }); + + const animation = animateNode.animate(panel.keyframes, { + ...ANIMATION_CONFIG, + id: 'panel-animation', + direction: isRTL ? 'reverse' : 'normal', + }); + + onAnimationStarted(); + + function onFinish() { + onAnimationDone(); + } + + animation.addEventListener('finish', onFinish); + + return () => { + overlayAnimation?.cancel(); + animation.removeEventListener('finish', onFinish); + animation.cancel(); + }; +} export function ConversationPanel({ conversationId, }: { conversationId: string; }): JSX.Element | null { - const i18n = useSelector(getIntl); - const { popPanelForConversation, startConversation } = + const panelInformation = useSelector(getPanelInformation); + const { panelAnimationDone, panelAnimationStarted } = useConversationsActions(); - const topPanel = useSelector( - getTopPanel - ); - const conversationTitle = useSelector(getConversationTitle); + const [shouldRenderPoppedPanel, setShouldRenderPoppedPanel] = useState(true); + const animateRef = useRef(null); + const overlayRef = useRef(null); + const prefersReducedMotion = useReducedMotion(); - const selectors = useMemo(() => focusableSelectors.join(','), []); - const panelRef = useRef(null); useEffect(() => { - const panelNode = panelRef.current; - if (!panelNode) { + setShouldRenderPoppedPanel(true); + }, [panelInformation?.prevPanel]); + + const i18n = useSelector(getIntl); + const isRTL = i18n.getLocaleDirection() === 'rtl'; + + const isAnimating = useSelector(getIsPanelAnimating); + + useEffect(() => { + if (prefersReducedMotion) { + panelAnimationDone(); + setShouldRenderPoppedPanel(false); return; } - const elements = panelNode.querySelectorAll(selectors); + if (panelInformation?.direction === 'pop') { + if (!shouldRenderPoppedPanel) { + return; + } + + return doAnimate({ + isRTL, + onAnimationDone: () => { + panelAnimationDone(); + setShouldRenderPoppedPanel(false); + }, + onAnimationStarted: panelAnimationStarted, + overlay: { + ref: overlayRef, + keyframes: [ + { backgroundColor: 'rgba(0, 0, 0, 0.2)' }, + { backgroundColor: 'rgba(0, 0, 0, 0)' }, + ], + }, + panel: { + ref: animateRef, + keyframes: [ + { transform: 'translateX(0%)' }, + { transform: 'translateX(100%)' }, + ], + }, + }); + } + + if (panelInformation?.direction === 'push') { + if (!panelInformation?.currPanel) { + return; + } + + return doAnimate({ + isRTL, + onAnimationDone: panelAnimationDone, + onAnimationStarted: panelAnimationStarted, + overlay: { + ref: overlayRef, + keyframes: [ + { backgroundColor: 'rgba(0, 0, 0, 0)' }, + { backgroundColor: 'rgba(0, 0, 0, 0.2)' }, + ], + }, + panel: { + ref: animateRef, + keyframes: [ + { transform: 'translateX(100%)' }, + { transform: 'translateX(0%)' }, + ], + }, + }); + } + + return undefined; + }, [ + isRTL, + panelAnimationDone, + panelAnimationStarted, + panelInformation?.currPanel, + panelInformation?.direction, + panelInformation?.prevPanel, + prefersReducedMotion, + shouldRenderPoppedPanel, + ]); + + if (!panelInformation) { + return null; + } + + const { currPanel: activePanel, direction, prevPanel } = panelInformation; + + if (!direction) { + return null; + } + + if (direction === 'pop') { + return ( + <> + {activePanel && ( + + )} + {shouldRenderPoppedPanel && ( +
+ )} + {shouldRenderPoppedPanel && prevPanel && ( + + )} + + ); + } + + if (direction === 'push' && activePanel) { + return ( + <> + {isAnimating && prevPanel && ( + + )} +
+ + + ); + } + + return null; +} + +type PanelPropsType = { + conversationId: string; + panel: PanelRenderType; +}; + +const PanelContainer = forwardRef< + HTMLDivElement, + PanelPropsType & { isActive?: boolean } +>(function PanelContainerInner( + { conversationId, isActive, panel }, + ref +): JSX.Element { + const i18n = useSelector(getIntl); + const { popPanelForConversation } = useConversationsActions(); + const conversationTitle = getConversationTitleForPanelType(i18n, panel.type); + + const selectors = useMemo(() => focusableSelectors.join(','), []); + const focusRef = useRef(null); + useEffect(() => { + if (!isActive) { + return; + } + + const focusNode = focusRef.current; + if (!focusNode) { + return; + } + + const elements = focusNode.querySelectorAll(selectors); if (!elements.length) { return; } elements[0]?.focus(); - }, [selectors, topPanel]); - - if (!topPanel) { - return null; - } - - let panelChild: JSX.Element; - let panelClassName = ''; - - if (topPanel.type === PanelType.AllMedia) { - panelChild = ; - } else if (topPanel.type === PanelType.ChatColorEditor) { - panelChild = ; - } else if (topPanel.type === PanelType.ContactDetails) { - const { contact, signalAccount } = topPanel.args; - - panelChild = ( - { - if (signalAccount) { - startConversation(signalAccount.phoneNumber, signalAccount.uuid); - } - }} - /> - ); - } else if (topPanel.type === PanelType.ConversationDetails) { - panelClassName = 'conversation-details-pane'; - panelChild = ; - } else if (topPanel.type === PanelType.GroupInvites) { - panelChild = ( - - ); - } else if (topPanel.type === PanelType.GroupLinkManagement) { - panelChild = ; - } else if (topPanel.type === PanelType.GroupPermissions) { - panelChild = ; - } else if (topPanel.type === PanelType.GroupV1Members) { - panelClassName = 'group-member-list'; - panelChild = ; - } else if (topPanel.type === PanelType.MessageDetails) { - panelClassName = 'message-detail-wrapper'; - panelChild = ; - } else if (topPanel.type === PanelType.NotificationSettings) { - panelChild = ( - - ); - } else if (topPanel.type === PanelType.StickerManager) { - panelClassName = 'sticker-manager-wrapper'; - panelChild = ; - } else { - log.warn('renderPanel: Got unexpected panel', topPanel); - return null; - } + }, [isActive, panel, selectors]); return ( -
+
- {panelChild} +
+ +
); +}); + +function PanelElement({ + conversationId, + panel, +}: PanelPropsType): JSX.Element | null { + const i18n = useSelector(getIntl); + const { startConversation } = useConversationsActions(); + + if (panel.type === PanelType.AllMedia) { + return ; + } + + if (panel.type === PanelType.ChatColorEditor) { + return ; + } + + if (panel.type === PanelType.ContactDetails) { + const { contact, signalAccount } = panel.args; + + return ( + { + if (signalAccount) { + startConversation(signalAccount.phoneNumber, signalAccount.uuid); + } + }} + /> + ); + } + + if (panel.type === PanelType.ConversationDetails) { + return ; + } + + if (panel.type === PanelType.GroupInvites) { + return ( + + ); + } + + if (panel.type === PanelType.GroupLinkManagement) { + return ; + } + + if (panel.type === PanelType.GroupPermissions) { + return ; + } + + if (panel.type === PanelType.GroupV1Members) { + return ; + } + + if (panel.type === PanelType.MessageDetails) { + return ; + } + + if (panel.type === PanelType.NotificationSettings) { + return ( + + ); + } + + if (panel.type === PanelType.StickerManager) { + return ; + } + + log.warn(missingCaseError(panel)); + return null; } diff --git a/ts/state/smart/ConversationView.tsx b/ts/state/smart/ConversationView.tsx index 8b479e4cfaca..e90280ec615b 100644 --- a/ts/state/smart/ConversationView.tsx +++ b/ts/state/smart/ConversationView.tsx @@ -10,6 +10,8 @@ import { SmartCompositionArea } from './CompositionArea'; import { SmartConversationHeader } from './ConversationHeader'; import { SmartTimeline } from './Timeline'; import { + getActivePanel, + getIsPanelAnimating, getSelectedConversationId, getSelectedMessageIds, } from '../selectors/conversations'; @@ -37,6 +39,12 @@ export function SmartConversationView(): JSX.Element { ); }); + const shouldHideConversationView = useSelector((state: StateType) => { + const activePanel = getActivePanel(state); + const isAnimating = getIsPanelAnimating(state); + return activePanel && !isAnimating; + }); + return ( )} renderPanel={() => } + shouldHideConversationView={shouldHideConversationView} /> ); } diff --git a/ts/test-mock/benchmarks/convo_open_bench.ts b/ts/test-mock/benchmarks/convo_open_bench.ts index 85a0355c27fc..3f7b1160227a 100644 --- a/ts/test-mock/benchmarks/convo_open_bench.ts +++ b/ts/test-mock/benchmarks/convo_open_bench.ts @@ -56,7 +56,7 @@ Bootstrap.benchmark(async (bootstrap: Bootstrap): Promise => { assert(app); const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); const openConvo = async (contact: PrimaryDevice): Promise => { debug('opening conversation', contact.profileName); diff --git a/ts/test-mock/benchmarks/group_send_bench.ts b/ts/test-mock/benchmarks/group_send_bench.ts index 51df20f636f3..d849ebbf870e 100644 --- a/ts/test-mock/benchmarks/group_send_bench.ts +++ b/ts/test-mock/benchmarks/group_send_bench.ts @@ -106,7 +106,7 @@ Bootstrap.benchmark(async (bootstrap: Bootstrap): Promise => { debug('opening conversation'); { - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); const item = leftPane .locator( @@ -118,7 +118,7 @@ Bootstrap.benchmark(async (bootstrap: Bootstrap): Promise => { } const timeline = window.locator( - '.timeline-wrapper, .conversation .ConversationView' + '.timeline-wrapper, .Inbox__conversation .ConversationView' ); const deltaList = new Array(); diff --git a/ts/test-mock/benchmarks/send_bench.ts b/ts/test-mock/benchmarks/send_bench.ts index 7a3a723fb6c3..0cd9494ffc23 100644 --- a/ts/test-mock/benchmarks/send_bench.ts +++ b/ts/test-mock/benchmarks/send_bench.ts @@ -65,7 +65,7 @@ Bootstrap.benchmark(async (bootstrap: Bootstrap): Promise => { debug('opening conversation'); { - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); const item = leftPane.locator( `[data-testid="${first.toContact().uuid}"] >> text=${LAST_MESSAGE}` ); @@ -73,7 +73,7 @@ Bootstrap.benchmark(async (bootstrap: Bootstrap): Promise => { } const timeline = window.locator( - '.timeline-wrapper, .conversation .ConversationView' + '.timeline-wrapper, .Inbox__conversation .ConversationView' ); const deltaList = new Array(); diff --git a/ts/test-mock/benchmarks/storage_sync_bench.ts b/ts/test-mock/benchmarks/storage_sync_bench.ts index 7e55b41305d9..02a61ce1b9b4 100644 --- a/ts/test-mock/benchmarks/storage_sync_bench.ts +++ b/ts/test-mock/benchmarks/storage_sync_bench.ts @@ -47,7 +47,7 @@ Bootstrap.benchmark(async (bootstrap: Bootstrap): Promise => { const app = await bootstrap.link(); const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); const item = leftPane.locator( `[data-testid="${lastContact?.toContact().uuid}"]` diff --git a/ts/test-mock/messaging/edit_test.ts b/ts/test-mock/messaging/edit_test.ts index 491da4bfdfc7..791ee5ca0352 100644 --- a/ts/test-mock/messaging/edit_test.ts +++ b/ts/test-mock/messaging/edit_test.ts @@ -93,7 +93,7 @@ describe('editing', function needsName() { } debug('opening conversation'); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); await leftPane .locator('.module-conversation-list__item--contact-or-conversation') .first() @@ -153,7 +153,7 @@ describe('editing', function needsName() { } debug('opening conversation'); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); await leftPane .locator('.module-conversation-list__item--contact-or-conversation') .first() @@ -223,7 +223,7 @@ describe('editing', function needsName() { }); debug('opening conversation'); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); await leftPane .locator('.module-conversation-list__item--contact-or-conversation') .first() diff --git a/ts/test-mock/messaging/sender_key_test.ts b/ts/test-mock/messaging/sender_key_test.ts index a1482090cce7..34340d4e5f46 100644 --- a/ts/test-mock/messaging/sender_key_test.ts +++ b/ts/test-mock/messaging/sender_key_test.ts @@ -75,12 +75,12 @@ describe('senderKey', function needsName() { distributionId, }); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('Opening group'); await leftPane.locator(`[data-testid="${group.id}"]`).click(); - const conversationStack = window.locator('.conversation-stack'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('Verifying message'); await conversationStack diff --git a/ts/test-mock/messaging/stories_test.ts b/ts/test-mock/messaging/stories_test.ts index c48773f228d4..91559d4a0ef1 100644 --- a/ts/test-mock/messaging/stories_test.ts +++ b/ts/test-mock/messaging/stories_test.ts @@ -195,7 +195,7 @@ describe('story/messaging', function unknownContacts() { { timestamp: sentAt + 2 } ); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('Finding both replies'); await leftPane @@ -214,7 +214,7 @@ describe('story/messaging', function unknownContacts() { debug('waiting for storage service sync to complete'); await app.waitForStorageService(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('Create and send a story to the group'); await leftPane.getByRole('button', { name: 'Stories' }).click(); diff --git a/ts/test-mock/messaging/unknown_contact_test.ts b/ts/test-mock/messaging/unknown_contact_test.ts index 654b144627b8..ab6ed27c0538 100644 --- a/ts/test-mock/messaging/unknown_contact_test.ts +++ b/ts/test-mock/messaging/unknown_contact_test.ts @@ -58,14 +58,14 @@ describe('unknown contacts', function unknownContacts() { }); debug('opening conversation'); - const leftPane = page.locator('.left-pane-wrapper'); + const leftPane = page.locator('#LeftPane'); const conversationListItem = leftPane.getByRole('button', { name: 'Chat with Unknown contact', }); await conversationListItem.getByText('Message Request').click(); - const conversationStack = page.locator('.conversation-stack'); + const conversationStack = page.locator('.Inbox__conversation-stack'); await conversationStack.getByText('Missed voice call').waitFor(); debug('accepting message request'); diff --git a/ts/test-mock/playwright.ts b/ts/test-mock/playwright.ts index 6912245f46f0..6a1db7c62a6f 100644 --- a/ts/test-mock/playwright.ts +++ b/ts/test-mock/playwright.ts @@ -64,7 +64,7 @@ export class App extends EventEmitter { public async waitForEnabledComposer(): Promise { const window = await this.getWindow(); const composeArea = window.locator( - '.composition-area-wrapper, .conversation .ConversationView' + '.composition-area-wrapper, .Inbox__conversation .ConversationView' ); const composeContainer = composeArea.locator( '[data-testid=CompositionInput][data-enabled=true]' diff --git a/ts/test-mock/pnp/accept_gv2_invite_test.ts b/ts/test-mock/pnp/accept_gv2_invite_test.ts index 8ee15984d715..8b25212a1cdd 100644 --- a/ts/test-mock/pnp/accept_gv2_invite_test.ts +++ b/ts/test-mock/pnp/accept_gv2_invite_test.ts @@ -49,7 +49,7 @@ describe('pnp/accept gv2 invite', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('Opening group'); await leftPane.locator(`[data-testid="${group.id}"]`).click(); @@ -67,7 +67,7 @@ describe('pnp/accept gv2 invite', function needsName() { const window = await app.getWindow(); - const conversationStack = window.locator('.conversation-stack'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('Accepting'); await conversationStack @@ -139,7 +139,7 @@ describe('pnp/accept gv2 invite', function needsName() { const window = await app.getWindow(); - const conversationStack = window.locator('.conversation-stack'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('Declining'); await conversationStack @@ -189,7 +189,7 @@ describe('pnp/accept gv2 invite', function needsName() { uuidKind: UUIDKind.ACI, }); - const conversationStack = window.locator('.conversation-stack'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('Waiting for the ACI invite'); await window @@ -251,7 +251,7 @@ describe('pnp/accept gv2 invite', function needsName() { uuidKind: UUIDKind.ACI, }); - const conversationStack = window.locator('.conversation-stack'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('Declining'); await conversationStack @@ -300,7 +300,7 @@ describe('pnp/accept gv2 invite', function needsName() { }); const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('Opening new group'); await leftPane.locator(`[data-testid="${group.id}"]`).click(); diff --git a/ts/test-mock/pnp/change_number_test.ts b/ts/test-mock/pnp/change_number_test.ts index fa8c830093d8..88d8e95a0802 100644 --- a/ts/test-mock/pnp/change_number_test.ts +++ b/ts/test-mock/pnp/change_number_test.ts @@ -35,7 +35,7 @@ describe('pnp/change number', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('prepare a message for original PNI'); const messageBefore = await first.encryptText(desktop, 'Before', { diff --git a/ts/test-mock/pnp/merge_test.ts b/ts/test-mock/pnp/merge_test.ts index dcdc7540d880..6c0924bf9b8a 100644 --- a/ts/test-mock/pnp/merge_test.ts +++ b/ts/test-mock/pnp/merge_test.ts @@ -109,7 +109,7 @@ describe('pnp/merge', function needsName() { const { phone } = bootstrap; const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('opening conversation with the aci contact'); await leftPane @@ -246,7 +246,7 @@ describe('pnp/merge', function needsName() { } const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('opening conversation with the merged contact'); await leftPane @@ -344,7 +344,7 @@ describe('pnp/merge', function needsName() { } const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('opening conversation with the merged contact'); await leftPane diff --git a/ts/test-mock/pnp/pni_change_test.ts b/ts/test-mock/pnp/pni_change_test.ts index bc409a2ba828..7c4e955b8604 100644 --- a/ts/test-mock/pnp/pni_change_test.ts +++ b/ts/test-mock/pnp/pni_change_test.ts @@ -74,7 +74,7 @@ describe('pnp/PNI Change', function needsName() { debug('Open conversation with contactA'); { - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); await leftPane .locator( @@ -174,7 +174,7 @@ describe('pnp/PNI Change', function needsName() { debug('Open conversation with contactA'); { - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); await leftPane .locator( @@ -276,7 +276,7 @@ describe('pnp/PNI Change', function needsName() { debug('Open conversation with contactA'); { - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); await leftPane .locator( @@ -408,7 +408,7 @@ describe('pnp/PNI Change', function needsName() { debug('Open conversation with contactA'); { - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); await leftPane .locator( diff --git a/ts/test-mock/pnp/pni_signature_test.ts b/ts/test-mock/pnp/pni_signature_test.ts index 90b92b2bb613..49da03c4e493 100644 --- a/ts/test-mock/pnp/pni_signature_test.ts +++ b/ts/test-mock/pnp/pni_signature_test.ts @@ -99,8 +99,8 @@ describe('pnp/PNI Signature', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); - const conversationStack = window.locator('.conversation-stack'); + const leftPane = window.locator('#LeftPane'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('creating a stranger'); const stranger = await server.createPrimaryDevice({ @@ -254,7 +254,7 @@ describe('pnp/PNI Signature', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('opening conversation with the pni contact'); await leftPane diff --git a/ts/test-mock/pnp/send_gv2_invite_test.ts b/ts/test-mock/pnp/send_gv2_invite_test.ts index 053c4ea213ca..d790ec1a1868 100644 --- a/ts/test-mock/pnp/send_gv2_invite_test.ts +++ b/ts/test-mock/pnp/send_gv2_invite_test.ts @@ -97,8 +97,8 @@ describe('pnp/send gv2 invite', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); - const conversationStack = window.locator('.conversation-stack'); + const leftPane = window.locator('#LeftPane'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('clicking compose and "New group" buttons'); diff --git a/ts/test-mock/pnp/username_test.ts b/ts/test-mock/pnp/username_test.ts index 9f2766d4a423..e56f4567feef 100644 --- a/ts/test-mock/pnp/username_test.ts +++ b/ts/test-mock/pnp/username_test.ts @@ -86,7 +86,7 @@ describe('pnp/username', function needsName() { const { phone } = bootstrap; const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('find username in the left pane'); await leftPane @@ -335,7 +335,7 @@ describe('pnp/username', function needsName() { const window = await app.getWindow(); debug('opening note to self'); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); await leftPane.locator(`[data-testid="${desktop.uuid}"]`).click(); debug('clicking link'); diff --git a/ts/test-mock/rate-limit/viewed_test.ts b/ts/test-mock/rate-limit/viewed_test.ts index a4cdebc26a22..cbf2e0c5f18b 100644 --- a/ts/test-mock/rate-limit/viewed_test.ts +++ b/ts/test-mock/rate-limit/viewed_test.ts @@ -85,8 +85,8 @@ describe('challenge/receipts', function challengeReceiptsTest() { }); const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); - const conversationStack = window.locator('.conversation-stack'); + const leftPane = window.locator('#LeftPane'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug(`Opening conversation with contact (${contact.toContact().uuid})`); await leftPane diff --git a/ts/test-mock/storage/archive_test.ts b/ts/test-mock/storage/archive_test.ts index 12cbe0923181..122ff7b10108 100644 --- a/ts/test-mock/storage/archive_test.ts +++ b/ts/test-mock/storage/archive_test.ts @@ -33,8 +33,8 @@ describe('storage service', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); - const conversationStack = window.locator('.conversation-stack'); + const leftPane = window.locator('#LeftPane'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('archiving contact'); { diff --git a/ts/test-mock/storage/max_read_keys_test.ts b/ts/test-mock/storage/max_read_keys_test.ts index 882710948acd..a0c037521b14 100644 --- a/ts/test-mock/storage/max_read_keys_test.ts +++ b/ts/test-mock/storage/max_read_keys_test.ts @@ -41,7 +41,7 @@ describe('storage service', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); debug('wait for first contact to be pinned in the left pane'); await leftPane diff --git a/ts/test-mock/storage/message_request_test.ts b/ts/test-mock/storage/message_request_test.ts index d39bb2884366..b29b2f182dc2 100644 --- a/ts/test-mock/storage/message_request_test.ts +++ b/ts/test-mock/storage/message_request_test.ts @@ -48,8 +48,8 @@ describe('storage service', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); - const conversationStack = window.locator('.conversation-stack'); + const leftPane = window.locator('#LeftPane'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('Opening conversation with a stranger'); debug(stranger.toContact().uuid); @@ -117,7 +117,7 @@ describe('storage service', function needsName() { debug('Enter message text'); const composeArea = window.locator( - '.composition-area-wrapper, .conversation .ConversationView' + '.composition-area-wrapper, .Inbox__conversation .ConversationView' ); const input = composeArea.locator('[data-testid=CompositionInput]'); diff --git a/ts/test-mock/storage/pin_unpin_test.ts b/ts/test-mock/storage/pin_unpin_test.ts index 4ab5df4dd207..c129e4225194 100644 --- a/ts/test-mock/storage/pin_unpin_test.ts +++ b/ts/test-mock/storage/pin_unpin_test.ts @@ -36,8 +36,8 @@ describe('storage service', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); - const conversationStack = window.locator('.conversation-stack'); + const leftPane = window.locator('#LeftPane'); + const conversationStack = window.locator('.Inbox__conversation-stack'); debug('Verifying that the group is pinned on startup'); await leftPane.locator(`[data-testid="${group.id}"]`).waitFor(); diff --git a/ts/test-mock/storage/sticker_test.ts b/ts/test-mock/storage/sticker_test.ts index acf3c026ae49..decaf44f89bb 100644 --- a/ts/test-mock/storage/sticker_test.ts +++ b/ts/test-mock/storage/sticker_test.ts @@ -110,9 +110,9 @@ describe('storage service', function needsName() { const window = await app.getWindow(); - const leftPane = window.locator('.left-pane-wrapper'); + const leftPane = window.locator('#LeftPane'); const conversationView = window.locator( - '.conversation > .ConversationView' + '.Inbox__conversation > .ConversationView' ); debug('sending two sticker pack links'); diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index 1652eb569695..7b2552b3d18a 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -2391,13 +2391,6 @@ "updated": "2022-06-14T22:04:43.988Z", "reasonDetail": "Handling outside click" }, - { - "rule": "React-useRef", - "path": "ts/components/Modal.tsx", - "line": " const modalRef = useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2021-08-05T00:22:31.660Z" - }, { "rule": "React-useRef", "path": "ts/components/Modal.tsx", @@ -2416,67 +2409,10 @@ }, { "rule": "React-useRef", - "path": "ts/components/TextAttachment.tsx", - "line": " const ref = useRef(null);", - "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", - "updated": "2023-07-25T21:55:26.191Z", - "reasonDetail": "" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useSizeObserver.tsx", - "line": " const sizeRef = useRef(null);", - "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", - "updated": "2023-07-25T21:55:26.191Z", - "reasonDetail": "" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useSizeObserver.tsx", - "line": " const onSizeChangeRef = useRef(onSizeChange);", - "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", - "updated": "2023-07-25T21:55:26.191Z", - "reasonDetail": "" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useSizeObserver.tsx", - "line": " const ref = useRef();", - "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", - "updated": "2023-07-25T21:55:26.191Z", - "reasonDetail": "" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useSizeObserver.tsx", - "line": " * const scrollerRef = useRef()", - "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", - "updated": "2023-07-25T21:55:26.191Z", - "reasonDetail": "" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useSizeObserver.tsx", - "line": " * const scrollerInnerRef = useRef()", - "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", - "updated": "2023-07-25T21:55:26.191Z", - "reasonDetail": "" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useSizeObserver.tsx", - "line": " const scrollRef = useRef(null);", - "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", - "updated": "2023-07-25T21:55:26.191Z", - "reasonDetail": "" - }, - { - "rule": "React-useRef", - "path": "ts/hooks/useSizeObserver.tsx", - "line": " const onScrollChangeRef = useRef(onScrollChange);", - "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", - "updated": "2023-07-25T21:55:26.191Z", - "reasonDetail": "" + "path": "ts/components/Modal.tsx", + "line": " const modalRef = useRef(null);", + "reasonCategory": "usageTrusted", + "updated": "2021-08-05T00:22:31.660Z" }, { "rule": "React-useRef", @@ -2616,6 +2552,14 @@ "reasonCategory": "usageTrusted", "updated": "2022-10-05T18:51:56.411Z" }, + { + "rule": "React-useRef", + "path": "ts/components/TextAttachment.tsx", + "line": " const ref = useRef(null);", + "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", + "updated": "2023-07-25T21:55:26.191Z", + "reasonDetail": "" + }, { "rule": "React-useRef", "path": "ts/components/TextAttachment.tsx", @@ -2858,6 +2802,62 @@ "reasonCategory": "usageTrusted", "updated": "2021-10-22T00:52:39.251Z" }, + { + "rule": "React-useRef", + "path": "ts/hooks/useSizeObserver.tsx", + "line": " const sizeRef = useRef(null);", + "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", + "updated": "2023-07-25T21:55:26.191Z", + "reasonDetail": "" + }, + { + "rule": "React-useRef", + "path": "ts/hooks/useSizeObserver.tsx", + "line": " const onSizeChangeRef = useRef(onSizeChange);", + "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", + "updated": "2023-07-25T21:55:26.191Z", + "reasonDetail": "" + }, + { + "rule": "React-useRef", + "path": "ts/hooks/useSizeObserver.tsx", + "line": " const ref = useRef();", + "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", + "updated": "2023-07-25T21:55:26.191Z", + "reasonDetail": "" + }, + { + "rule": "React-useRef", + "path": "ts/hooks/useSizeObserver.tsx", + "line": " * const scrollerRef = useRef()", + "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", + "updated": "2023-07-25T21:55:26.191Z", + "reasonDetail": "" + }, + { + "rule": "React-useRef", + "path": "ts/hooks/useSizeObserver.tsx", + "line": " * const scrollerInnerRef = useRef()", + "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", + "updated": "2023-07-25T21:55:26.191Z", + "reasonDetail": "" + }, + { + "rule": "React-useRef", + "path": "ts/hooks/useSizeObserver.tsx", + "line": " const scrollRef = useRef(null);", + "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", + "updated": "2023-07-25T21:55:26.191Z", + "reasonDetail": "" + }, + { + "rule": "React-useRef", + "path": "ts/hooks/useSizeObserver.tsx", + "line": " const onScrollChangeRef = useRef(onScrollChange);", + "reasonCategory": "falseMatch|testCode|exampleCode|otherUtilityCode|regexMatchedSafeCode|notExercisedByOurApp|ruleNeeded|usageTrusted", + "updated": "2023-07-25T21:55:26.191Z", + "reasonDetail": "" + }, { "rule": "React-useRef", "path": "ts/quill/formatting/menu.tsx", @@ -2885,9 +2885,23 @@ { "rule": "React-useRef", "path": "ts/state/smart/ConversationPanel.tsx", - "line": " const panelRef = useRef(null);", + "line": " const animateRef = useRef(null);", "reasonCategory": "usageTrusted", - "updated": "2023-06-15T19:55:51.367Z" + "updated": "2023-07-13T23:34:39.367Z" + }, + { + "rule": "React-useRef", + "path": "ts/state/smart/ConversationPanel.tsx", + "line": " const overlayRef = useRef(null);", + "reasonCategory": "usageTrusted", + "updated": "2023-07-13T23:34:39.367Z" + }, + { + "rule": "React-useRef", + "path": "ts/state/smart/ConversationPanel.tsx", + "line": " const focusRef = useRef(null);", + "reasonCategory": "usageTrusted", + "updated": "2023-07-13T23:34:39.367Z" }, { "rule": "React-useRef",