Chat Badge: Fix animation (#6905)

This commit is contained in:
Alexander Zinchuk 2026-05-05 13:46:33 +02:00
parent 57bcad5215
commit caa1cc8621
3 changed files with 42 additions and 8 deletions

View File

@ -20,6 +20,8 @@
}
.transition {
transform-origin: center;
display: flex;
align-items: center;
justify-content: center;
@ -28,7 +30,7 @@
opacity: 1;
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
transition: transform 0.15s ease-out, opacity 0.15s ease-out;
&:not(:global(.open)) {
transform: scale(0);
@ -38,12 +40,6 @@
&:not(:global(.shown)) {
display: none;
}
&:global(.closing) {
transition:
transform 0.2s ease-out,
opacity 0.2s ease-out;
}
}
.wrapper {

View File

@ -18,6 +18,7 @@ import useSelector, { useShallowSelector } from '../../../hooks/data/useSelector
import useDerivedState from '../../../hooks/useDerivedState';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import useShowTransitionSwap from '../../../hooks/useShowTransitionSwap';
import AnimatedCounter from '../../common/AnimatedCounter';
import Icon from '../../common/icons/Icon';
@ -153,6 +154,12 @@ const ChatBadge = ({
|| isTopicUnopened || hasMiniApp,
);
const contentCategory = (isUnread || unreadMentionsCount || unreadReactionsCount
|| unreadPollVotesCount || isTopicUnopened)
? 'active'
: (hasMiniApp ? 'miniapp' : (isPinned ? 'pinned' : 'none'));
const effectiveIsOpen = useShowTransitionSwap(isShown, contentCategory);
const handleOpenApp = useLastCallback((e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.stopPropagation();
@ -263,7 +270,7 @@ const ChatBadge = ({
isOnAvatar && styles.onAvatar,
transitionClassName,
)}
isOpen={isShown}
isOpen={effectiveIsOpen}
>
{renderContent()}
</ShowTransition>

View File

@ -0,0 +1,31 @@
import { useRef } from '../lib/teact/teact';
import useForceUpdate from './useForceUpdate';
import usePreviousDeprecated from './usePreviousDeprecated';
import useSyncEffect from './useSyncEffect';
const SWAP_CLOSE_DURATION = 150;
export default function useShowTransitionSwap(isOpen: boolean, contentKey?: string): boolean {
const prevIsOpen = usePreviousDeprecated(isOpen);
const prevContentKey = usePreviousDeprecated(contentKey);
const isSwappingRef = useRef(false);
const forceUpdate = useForceUpdate();
if (isOpen && prevIsOpen
&& contentKey !== undefined && prevContentKey !== undefined
&& prevContentKey !== contentKey && !isSwappingRef.current) {
isSwappingRef.current = true;
}
useSyncEffect(() => {
if (!isSwappingRef.current) return undefined;
const timer = window.setTimeout(() => {
isSwappingRef.current = false;
forceUpdate();
}, SWAP_CLOSE_DURATION);
return () => clearTimeout(timer);
}, [contentKey]);
return isOpen && !isSwappingRef.current;
}