86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
import React, {
|
|
FC, useLayoutEffect, useRef, memo,
|
|
} from '../../lib/teact/teact';
|
|
|
|
import buildClassName from '../../util/buildClassName';
|
|
import renderText from '../common/helpers/renderText';
|
|
|
|
import './Tab.scss';
|
|
|
|
type OwnProps = {
|
|
className?: string;
|
|
title: string;
|
|
active?: boolean;
|
|
badgeCount?: number;
|
|
isBadgeActive?: boolean;
|
|
previousActiveTab?: number;
|
|
onClick: (arg: number) => void;
|
|
clickArg: number;
|
|
};
|
|
|
|
const Tab: FC<OwnProps> = ({
|
|
className,
|
|
title,
|
|
active,
|
|
badgeCount,
|
|
isBadgeActive,
|
|
previousActiveTab,
|
|
onClick,
|
|
clickArg,
|
|
}) => {
|
|
// eslint-disable-next-line no-null/no-null
|
|
const tabRef = useRef<HTMLButtonElement>(null);
|
|
|
|
useLayoutEffect(() => {
|
|
if (!active || previousActiveTab === undefined) {
|
|
return;
|
|
}
|
|
|
|
const tab = tabRef.current!;
|
|
const indicator = tab.querySelector('i')!;
|
|
const prevTab = tab.parentElement!.children[previousActiveTab];
|
|
if (!prevTab) {
|
|
return;
|
|
}
|
|
const currentIndicator = prevTab.querySelector('i')!;
|
|
|
|
currentIndicator.classList.remove('animate');
|
|
indicator.classList.remove('animate');
|
|
|
|
// We move and resize our indicator so it repeats the position and size of the previous one.
|
|
const shiftLeft = currentIndicator.parentElement!.offsetLeft - indicator.parentElement!.offsetLeft;
|
|
const scaleFactor = currentIndicator.clientWidth / indicator.clientWidth;
|
|
indicator.style.transform = `translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`;
|
|
|
|
// 3 AFs needed here to synchronize animations with Transition component
|
|
requestAnimationFrame(() => {
|
|
requestAnimationFrame(() => {
|
|
requestAnimationFrame(() => {
|
|
// Now we remove the transform to let it animate to its own position and size.
|
|
indicator.classList.add('animate');
|
|
indicator.style.transform = 'none';
|
|
});
|
|
});
|
|
});
|
|
}, [active, previousActiveTab]);
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
className={buildClassName('Tab', className, active && 'active')}
|
|
onClick={() => onClick(clickArg)}
|
|
ref={tabRef}
|
|
>
|
|
<span>
|
|
{renderText(title)}
|
|
{!!badgeCount && (
|
|
<span className={buildClassName('badge', isBadgeActive && 'active')}>{badgeCount}</span>
|
|
)}
|
|
<i />
|
|
</span>
|
|
</button>
|
|
);
|
|
};
|
|
|
|
export default memo(Tab);
|