Fix panel animations when switching tabs

This commit is contained in:
Jamie Kyle 2023-08-21 13:18:22 -07:00 committed by GitHub
parent 3339899684
commit df0be46c3c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 81 additions and 60 deletions

View file

@ -483,6 +483,7 @@ export type ConversationsStateType = Readonly<{
targetedMessageSource: TargetedMessageSource | undefined;
targetedConversationPanels: {
isAnimating: boolean;
wasAnimated: boolean;
direction: 'push' | 'pop' | undefined;
stack: ReadonlyArray<PanelRenderType>;
watermark: number;
@ -4156,6 +4157,7 @@ export function getEmptyState(): ConversationsStateType {
showArchived: false,
targetedConversationPanels: {
isAnimating: false,
wasAnimated: false,
direction: undefined,
stack: [],
watermark: -1,
@ -4710,6 +4712,7 @@ export function reducer(
selectedConversationId,
targetedConversationPanels: {
isAnimating: false,
wasAnimated: false,
direction: undefined,
stack: [],
watermark: -1,
@ -5651,6 +5654,7 @@ export function reducer(
const targetedConversationPanels = {
isAnimating: false,
wasAnimated: false,
direction: 'push' as const,
stack,
watermark,
@ -5691,6 +5695,7 @@ export function reducer(
const targetedConversationPanels = {
isAnimating: false,
wasAnimated: false,
direction: 'pop' as const,
stack: state.targetedConversationPanels.stack,
watermark,
@ -5726,6 +5731,7 @@ export function reducer(
targetedConversationPanels: {
...state.targetedConversationPanels,
isAnimating: false,
wasAnimated: true,
},
};
}

View file

@ -1201,6 +1201,13 @@ export const getIsPanelAnimating = createSelector(
}
);
export const getWasPanelAnimated = createSelector(
getConversations,
(conversations): boolean => {
return conversations.targetedConversationPanels.wasAnimated;
}
);
export const getConversationTitle = createSelector(
getIntl,
getActivePanel,

View file

@ -2,7 +2,14 @@
// SPDX-License-Identifier: AGPL-3.0-only
import type { MutableRefObject } from 'react';
import React, { forwardRef, useEffect, useMemo, useRef, useState } from 'react';
import React, {
forwardRef,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { useSelector } from 'react-redux';
import type { PanelRenderType } from '../../types/Panels';
import * as log from '../../logging/log';
@ -23,6 +30,7 @@ import { getIntl } from '../selectors/user';
import {
getIsPanelAnimating,
getPanelInformation,
getWasPanelAnimated,
} from '../selectors/conversations';
import { focusableSelectors } from '../../util/focusableSelectors';
import { missingCaseError } from '../../util/missingCaseError';
@ -92,37 +100,48 @@ export function ConversationPanel({
const panelInformation = useSelector(getPanelInformation);
const { panelAnimationDone, panelAnimationStarted } =
useConversationsActions();
const [shouldRenderPoppedPanel, setShouldRenderPoppedPanel] = useState(true);
const animateRef = useRef<HTMLDivElement | null>(null);
const overlayRef = useRef<HTMLDivElement | null>(null);
const prefersReducedMotion = useReducedMotion();
useEffect(() => {
setShouldRenderPoppedPanel(true);
}, [panelInformation?.prevPanel]);
const i18n = useSelector(getIntl);
const isRTL = i18n.getLocaleDirection() === 'rtl';
const isAnimating = useSelector(getIsPanelAnimating);
const wasAnimated = useSelector(getWasPanelAnimated);
const [lastPanelDoneAnimating, setLastPanelDoneAnimating] =
useState<PanelRenderType | null>(null);
const wasAnimatedRef = useRef(wasAnimated);
useEffect(() => {
wasAnimatedRef.current = wasAnimated;
}, [wasAnimated]);
useEffect(() => {
if (prefersReducedMotion) {
setLastPanelDoneAnimating(null);
}, [panelInformation?.prevPanel]);
const onAnimationDone = useCallback(
(panel: PanelRenderType | null) => {
setLastPanelDoneAnimating(panel);
panelAnimationDone();
setShouldRenderPoppedPanel(false);
},
[panelAnimationDone]
);
useEffect(() => {
if (prefersReducedMotion || wasAnimatedRef.current) {
onAnimationDone(panelInformation?.prevPanel ?? null);
return;
}
if (panelInformation?.direction === 'pop') {
if (!shouldRenderPoppedPanel) {
return;
}
return doAnimate({
isRTL,
onAnimationDone: () => {
panelAnimationDone();
setShouldRenderPoppedPanel(false);
onAnimationDone(panelInformation?.prevPanel ?? null);
},
onAnimationStarted: panelAnimationStarted,
overlay: {
@ -143,13 +162,11 @@ export function ConversationPanel({
}
if (panelInformation?.direction === 'push') {
if (!panelInformation?.currPanel) {
return;
}
return doAnimate({
isRTL,
onAnimationDone: panelAnimationDone,
onAnimationDone: () => {
onAnimationDone(panelInformation?.prevPanel ?? null);
},
onAnimationStarted: panelAnimationStarted,
overlay: {
ref: overlayRef,
@ -171,13 +188,12 @@ export function ConversationPanel({
return undefined;
}, [
isRTL,
panelAnimationDone,
onAnimationDone,
panelAnimationStarted,
panelInformation?.currPanel,
panelInformation?.direction,
panelInformation?.prevPanel,
prefersReducedMotion,
shouldRenderPoppedPanel,
]);
if (!panelInformation) {
@ -200,10 +216,10 @@ export function ConversationPanel({
panel={activePanel}
/>
)}
{shouldRenderPoppedPanel && (
{lastPanelDoneAnimating !== prevPanel && (
<div className="ConversationPanel__overlay" ref={overlayRef} />
)}
{shouldRenderPoppedPanel && prevPanel && (
{prevPanel && lastPanelDoneAnimating !== prevPanel && (
<PanelContainer
conversationId={conversationId}
panel={prevPanel}

View file

@ -696,6 +696,13 @@
"reasonCategory": "usageTrusted",
"updated": "2023-04-20T16:43:40.643Z"
},
{
"rule": "thenify-multiArgs",
"path": "node_modules/make-dir/node_modules/pify/index.js",
"line": "\t\tif (options.multiArgs) {",
"reasonCategory": "usageTrusted",
"updated": "2023-08-21T18:28:53.361Z"
},
{
"rule": "DOM-outerHTML",
"path": "node_modules/domutils/node_modules/dom-serializer/lib/esm/index.js",
@ -1126,13 +1133,6 @@
"reasonCategory": "notExercisedByOurApp",
"updated": "2023-06-29T17:01:25.145Z"
},
{
"rule": "thenify-multiArgs",
"path": "node_modules/make-dir/node_modules/pify/index.js",
"line": "\t\tif (options.multiArgs) {",
"reasonCategory": "falseMatch",
"updated": "2023-08-18T19:09:30.283Z"
},
{
"rule": "DOM-innerHTML",
"path": "node_modules/min-document/serialize.js",
@ -2355,8 +2355,7 @@
"path": "ts/components/LeftPane.tsx",
"line": " const measureRef = useRef<HTMLDivElement>(null);",
"reasonCategory": "usageTrusted",
"updated": "2023-08-09T21:48:42.602Z",
"reasonDetail": "<optional>"
"updated": "2023-08-09T21:48:42.602Z"
},
{
"rule": "React-useRef",
@ -2427,16 +2426,14 @@
"path": "ts/components/Modal.tsx",
"line": " const bodyRef = useRef<HTMLDivElement>(null);",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
"path": "ts/components/Modal.tsx",
"line": " const bodyInnerRef = useRef<HTMLDivElement>(null);",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
@ -2529,24 +2526,21 @@
"path": "ts/components/StoryViewer.tsx",
"line": " const progressBarRef = useRef<HTMLDivElement>(null);",
"reasonCategory": "usageTrusted",
"updated": "2022-10-13T15:18:21.267Z",
"reasonDetail": "<optional>"
"updated": "2022-10-13T15:18:21.267Z"
},
{
"rule": "React-useRef",
"path": "ts/components/StoryViewer.tsx",
"line": " const animationRef = useRef<Animation | null>(null);",
"reasonCategory": "usageTrusted",
"updated": "2022-10-13T15:18:21.267Z",
"reasonDetail": "<optional>"
"updated": "2022-10-13T15:18:21.267Z"
},
{
"rule": "React-useRef",
"path": "ts/components/StoryViewer.tsx",
"line": " const onFinishRef = useRef<(() => void) | null>(null);",
"reasonCategory": "usageTrusted",
"updated": "2022-10-13T15:18:21.267Z",
"reasonDetail": "<optional>"
"updated": "2022-10-13T15:18:21.267Z"
},
{
"rule": "React-useRef",
@ -2595,8 +2589,7 @@
"path": "ts/components/TextAttachment.tsx",
"line": " const ref = useRef<HTMLDivElement>(null);",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
@ -2617,8 +2610,7 @@
"path": "ts/components/Tooltip.tsx",
"line": " const timeoutRef = useRef<NodeJS.Timeout | undefined>();",
"reasonCategory": "usageTrusted",
"updated": "2023-08-10T00:23:35.320Z",
"reasonDetail": "<optional>"
"updated": "2023-08-10T00:23:35.320Z"
},
{
"rule": "React-createRef",
@ -2832,56 +2824,49 @@
"path": "ts/hooks/useSizeObserver.tsx",
"line": " const sizeRef = useRef<Size | null>(null);",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
"path": "ts/hooks/useSizeObserver.tsx",
"line": " const onSizeChangeRef = useRef<SizeChangeHandler | void>(onSizeChange);",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
"path": "ts/hooks/useSizeObserver.tsx",
"line": " const ref = useRef<any>();",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
"path": "ts/hooks/useSizeObserver.tsx",
"line": " * const scrollerRef = useRef()",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
"path": "ts/hooks/useSizeObserver.tsx",
"line": " * const scrollerInnerRef = useRef()",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
"path": "ts/hooks/useSizeObserver.tsx",
"line": " const scrollRef = useRef<Scroll | null>(null);",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
"path": "ts/hooks/useSizeObserver.tsx",
"line": " const onScrollChangeRef = useRef<ScrollChangeHandler>(onScrollChange);",
"reasonCategory": "usageTrusted",
"updated": "2023-07-25T21:55:26.191Z",
"reasonDetail": "<optional>"
"updated": "2023-07-25T21:55:26.191Z"
},
{
"rule": "React-useRef",
@ -2936,6 +2921,13 @@
"reasonCategory": "usageTrusted",
"updated": "2023-07-13T23:34:39.367Z"
},
{
"rule": "React-useRef",
"path": "ts/state/smart/ConversationPanel.tsx",
"line": " const wasAnimatedRef = useRef(wasAnimated);",
"reasonCategory": "usageTrusted",
"updated": "2023-08-20T22:14:52.008Z"
},
{
"rule": "React-useRef",
"path": "ts/state/smart/InstallScreen.tsx",