Prevent layout recalculations in some animations

This commit is contained in:
Fedor Indutny 2022-11-23 12:13:13 -08:00 committed by GitHub
parent 97454b6bac
commit e3299b0445
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 52 additions and 27 deletions

View file

@ -3924,8 +3924,8 @@ button.module-image__border-overlay:focus {
line-height: 0; line-height: 0;
overflow: hidden; overflow: hidden;
border-radius: 5px; border-radius: 5px;
transition: top 200ms linear, left 200ms linear, width 200ms linear, transform: translate(0, 0);
height 200ms linear; transition: transform 200ms linear, width 200ms linear, height 200ms linear;
&__remote-video { &__remote-video {
// The background-color is seen while the video loads. // The background-color is seen while the video loads.

View file

@ -13,12 +13,13 @@
position: absolute; position: absolute;
text-align: center; text-align: center;
top: 12px; top: 12px;
transition: top 200ms ease-out, opacity 200ms ease-out; transform: translateY(0);
transition: transform 200ms ease-out, opacity 200ms ease-out;
user-select: none; user-select: none;
z-index: $z-index-above-above-base; z-index: $z-index-above-above-base;
&--hidden { &--hidden {
opacity: 0; opacity: 0;
top: 5px; transform: translateY(-7px);
} }
} }

View file

@ -55,11 +55,12 @@
width: 24px; width: 24px;
height: 24px; height: 24px;
min-width: 24px; min-width: 24px;
margin-left: -24px; margin-left: 12px;
transform: translateX(-36px);
vertical-align: text-bottom; vertical-align: text-bottom;
border: none; border: none;
opacity: 0; opacity: 0;
transition: margin-left $transition, opacity $transition; transition: transform $transition, opacity $transition;
&:disabled { &:disabled {
cursor: default; cursor: default;
@ -68,7 +69,7 @@
&--show { &--show {
opacity: 1; opacity: 1;
margin-right: 6px; margin-right: 6px;
margin-left: 12px; transform: translateX(0px);
} }
@include light-theme { @include light-theme {

View file

@ -5,6 +5,7 @@
&__container { &__container {
animation: IncomingCallBar--animation 0.2s forwards ease-out; animation: IncomingCallBar--animation 0.2s forwards ease-out;
position: fixed; position: fixed;
top: 22px;
width: 100%; width: 100%;
z-index: $z-index-popup; z-index: $z-index-popup;
padding: { padding: {
@ -185,12 +186,12 @@
@keyframes IncomingCallBar--animation { @keyframes IncomingCallBar--animation {
from { from {
top: -100px; transform: translateY(-100px);
opacity: 0; opacity: 0;
} }
to { to {
top: 22px; transform: translateY(0px);
opacity: 1; opacity: 1;
} }
} }

View file

@ -15,6 +15,7 @@
flex-direction: row; flex-direction: row;
animation: 500ms module-InstallScreenQrCodeNotScannedStep__slide-in; animation: 500ms module-InstallScreenQrCodeNotScannedStep__slide-in;
position: relative; position: relative;
top: 0;
@include light-theme { @include light-theme {
max-width: $base-max-width; max-width: $base-max-width;
@ -113,12 +114,12 @@
@keyframes module-InstallScreenQrCodeNotScannedStep__slide-in { @keyframes module-InstallScreenQrCodeNotScannedStep__slide-in {
from { from {
top: -8px; transform: translateY(-8px);
opacity: 0; opacity: 0;
} }
to { to {
top: 0; transform: translateY(0px);
opacity: 1; opacity: 1;
} }
} }

View file

@ -238,7 +238,9 @@
border-radius: 2px; border-radius: 2px;
display: block; display: block;
height: 100%; height: 100%;
transition: width 500ms ease-out; width: 100%;
transform: translateX(-100%);
transition: transform 500ms ease-out;
} }
} }

View file

@ -115,33 +115,33 @@ export function CallingToastManager(props: PropsType): JSX.Element {
toast = screenSharingToast; toast = screenSharingToast;
} }
const [toastMessage, setToastMessage] = useState(''); const [isVisible, setIsVisible] = useState(false);
const timeoutRef = useRef<NodeJS.Timeout | null>(null); const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const dismissToast = useCallback(() => { const dismissToast = useCallback(() => {
if (timeoutRef) { if (timeoutRef) {
setToastMessage(''); setIsVisible(false);
} }
}, [setToastMessage, timeoutRef]); }, [setIsVisible, timeoutRef]);
useEffect(() => { useEffect(() => {
if (toast) { setIsVisible(toast !== undefined);
if (toast.type === 'dismissable') { }, [toast]);
clearTimeoutIfNecessary(timeoutRef.current);
timeoutRef.current = setTimeout(dismissToast, DEFAULT_LIFETIME);
}
setToastMessage(toast.message); useEffect(() => {
if (toast?.type === 'dismissable') {
clearTimeoutIfNecessary(timeoutRef.current);
timeoutRef.current = setTimeout(dismissToast, DEFAULT_LIFETIME);
} }
return () => { return () => {
clearTimeoutIfNecessary(timeoutRef.current); clearTimeoutIfNecessary(timeoutRef.current);
}; };
}, [dismissToast, setToastMessage, timeoutRef, toast]); }, [dismissToast, setIsVisible, timeoutRef, toast]);
return ( return (
<CallingToast isVisible={Boolean(toastMessage)} onClick={dismissToast}> <CallingToast isVisible={isVisible} onClick={dismissToast}>
{toastMessage} {toast?.message}
</CallingToast> </CallingToast>
); );
} }

View file

@ -7,6 +7,7 @@ import { action } from '@storybook/addon-actions';
import { DialogUpdate } from './DialogUpdate'; import { DialogUpdate } from './DialogUpdate';
import { DialogType } from '../types/Dialogs'; import { DialogType } from '../types/Dialogs';
import { WidthBreakpoint } from './_util'; import { WidthBreakpoint } from './_util';
import { SECOND } from '../util/durations';
import { FakeLeftPaneContainer } from '../test-both/helpers/FakeLeftPaneContainer'; import { FakeLeftPaneContainer } from '../test-both/helpers/FakeLeftPaneContainer';
import { setupI18n } from '../util/setupI18n'; import { setupI18n } from '../util/setupI18n';
@ -110,10 +111,29 @@ FullDownloadReadyWide.story = {
}; };
export function DownloadingWide(): JSX.Element { export function DownloadingWide(): JSX.Element {
const [downloadedSize, setDownloadedSize] = React.useState(0);
const { downloadSize } = defaultProps;
React.useEffect(() => {
const interval = setInterval(() => {
setDownloadedSize(x => {
const newValue = x + 0.25 * downloadSize;
if (newValue > downloadSize) {
return 0;
}
return newValue;
});
}, SECOND);
return () => clearInterval(interval);
}, [downloadSize]);
return ( return (
<FakeLeftPaneContainer containerWidthBreakpoint={WidthBreakpoint.Wide}> <FakeLeftPaneContainer containerWidthBreakpoint={WidthBreakpoint.Wide}>
<DialogUpdate <DialogUpdate
{...defaultProps} {...defaultProps}
downloadedSize={downloadedSize}
containerWidthBreakpoint={WidthBreakpoint.Wide} containerWidthBreakpoint={WidthBreakpoint.Wide}
currentVersion="5.24.0" currentVersion="5.24.0"
dialogType={DialogType.Downloading} dialogType={DialogType.Downloading}

View file

@ -204,7 +204,7 @@ export function DialogUpdate({
<div className="LeftPaneDialog__progress--container"> <div className="LeftPaneDialog__progress--container">
<div <div
className="LeftPaneDialog__progress--bar" className="LeftPaneDialog__progress--bar"
style={{ width: `${width}%` }} style={{ transform: `translateX(${width - 100}%)` }}
/> />
</div> </div>
</LeftPaneDialog> </LeftPaneDialog>

View file

@ -235,8 +235,7 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
if ('top' in props) { if ('top' in props) {
containerStyles.position = 'absolute'; containerStyles.position = 'absolute';
containerStyles.top = props.top; containerStyles.transform = `translate(${props.left}px, ${props.top}px)`;
containerStyles.left = props.left;
} }
} }