Fix chat IDs being stuck in URL (#3105)

This commit is contained in:
Alexander Zinchuk 2023-05-02 15:22:55 +04:00
parent 61a26749d0
commit 56f41804c1
10 changed files with 100 additions and 56 deletions

View File

@ -28,6 +28,7 @@ import renderText from './helpers/renderText';
import useMedia from '../../hooks/useMedia'; import useMedia from '../../hooks/useMedia';
import useMediaTransition from '../../hooks/useMediaTransition'; import useMediaTransition from '../../hooks/useMediaTransition';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import { useFastClick } from '../../hooks/useFastClick';
import OptimizedVideo from '../ui/OptimizedVideo'; import OptimizedVideo from '../ui/OptimizedVideo';
@ -130,9 +131,11 @@ const Avatar: FC<OwnProps> = ({
if (isSavedMessages) { if (isSavedMessages) {
content = ( content = (
<i <i
className={buildClassName(cn.icon, className={buildClassName(
cn.icon,
'icon', 'icon',
'icon-avatar-saved-messages')} 'icon-avatar-saved-messages',
)}
role="img" role="img"
aria-label={author} aria-label={author}
/> />
@ -140,9 +143,11 @@ const Avatar: FC<OwnProps> = ({
} else if (isDeleted) { } else if (isDeleted) {
content = ( content = (
<i <i
className={buildClassName(cn.icon, className={buildClassName(
cn.icon,
'icon', 'icon',
'icon-avatar-deleted-account')} 'icon-avatar-deleted-account',
)}
role="img" role="img"
aria-label={author} aria-label={author}
/> />
@ -150,9 +155,11 @@ const Avatar: FC<OwnProps> = ({
} else if (isReplies) { } else if (isReplies) {
content = ( content = (
<i <i
className={buildClassName(cn.icon, className={buildClassName(
cn.icon,
'icon', 'icon',
'icon-reply-filled')} 'icon-reply-filled',
)}
role="img" role="img"
aria-label={author} aria-label={author}
/> />
@ -205,11 +212,12 @@ const Avatar: FC<OwnProps> = ({
); );
const hasMedia = Boolean(isSavedMessages || imgBlobUrl); const hasMedia = Boolean(isSavedMessages || imgBlobUrl);
const handleClick = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {
const { handleClick, handleMouseDown } = useFastClick((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {
if (onClick) { if (onClick) {
onClick(e, hasMedia); onClick(e, hasMedia);
} }
}, [onClick, hasMedia]); });
const senderId = (user || chat) && (user || chat)!.id; const senderId = (user || chat) && (user || chat)!.id;
@ -217,9 +225,10 @@ const Avatar: FC<OwnProps> = ({
<div <div
ref={ref} ref={ref}
className={fullClassName} className={fullClassName}
onClick={handleClick}
data-test-sender-id={IS_TEST ? senderId : undefined} data-test-sender-id={IS_TEST ? senderId : undefined}
aria-label={typeof content === 'string' ? author : undefined} aria-label={typeof content === 'string' ? author : undefined}
onClick={handleClick}
onMouseDown={handleMouseDown}
> >
{typeof content === 'string' ? renderText(content, [size === 'jumbo' ? 'hq_emoji' : 'emoji']) : content} {typeof content === 'string' ? renderText(content, [size === 'jumbo' ? 'hq_emoji' : 'emoji']) : content}
</div> </div>

View File

@ -11,11 +11,11 @@ import type { ObserveFn } from '../../hooks/useIntersectionObserver';
import type { FC } from '../../lib/teact/teact'; import type { FC } from '../../lib/teact/teact';
import type { ApiChat } from '../../api/types'; import type { ApiChat } from '../../api/types';
import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { getOrderedTopics } from '../../global/helpers'; import { getOrderedTopics } from '../../global/helpers';
import { getIsMobile } from '../../hooks/useAppLayout'; import { getIsMobile } from '../../hooks/useAppLayout';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import { useFastClick } from '../../hooks/useFastClick';
import { REM } from './helpers/mediaDimensions'; import { REM } from './helpers/mediaDimensions';
import renderText from './helpers/renderText'; import renderText from './helpers/renderText';
@ -59,17 +59,22 @@ const ChatForumLastMessage: FC<OwnProps> = ({
const [isReversedCorner, setIsReversedCorner] = useState(false); const [isReversedCorner, setIsReversedCorner] = useState(false);
const [overwrittenWidth, setOverwrittenWidth] = useState<number | undefined>(undefined); const [overwrittenWidth, setOverwrittenWidth] = useState<number | undefined>(undefined);
function handleOpenTopic(e: React.MouseEvent<HTMLDivElement>) { const {
handleClick: handleOpenTopicClick,
handleMouseDown: handleOpenTopicMouseDown,
} = useFastClick((e: React.MouseEvent<HTMLDivElement>) => {
if (lastActiveTopic.unreadCount === 0) return; if (lastActiveTopic.unreadCount === 0) return;
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
openChat({ openChat({
id: chat.id, id: chat.id,
threadId: lastActiveTopic.id, threadId: lastActiveTopic.id,
shouldReplaceHistory: true, shouldReplaceHistory: true,
noForumTopicPanel: getIsMobile(), noForumTopicPanel: getIsMobile(),
}); });
} });
useEffect(() => { useEffect(() => {
const lastMessageElement = lastMessageRef.current; const lastMessageElement = lastMessageRef.current;
@ -105,8 +110,8 @@ const ChatForumLastMessage: FC<OwnProps> = ({
lastActiveTopic.unreadCount && styles.unread, lastActiveTopic.unreadCount && styles.unread,
)} )}
ref={mainColumnRef} ref={mainColumnRef}
onMouseDown={IS_TOUCH_ENV ? undefined : handleOpenTopic} onClick={handleOpenTopicClick}
onClick={IS_TOUCH_ENV ? handleOpenTopic : undefined} onMouseDown={handleOpenTopicMouseDown}
> >
<TopicIcon <TopicIcon
topic={lastActiveTopic} topic={lastActiveTopic}
@ -144,8 +149,8 @@ const ChatForumLastMessage: FC<OwnProps> = ({
<div <div
className={buildClassName(styles.lastMessage, lastActiveTopic?.unreadCount && styles.unread)} className={buildClassName(styles.lastMessage, lastActiveTopic?.unreadCount && styles.unread)}
ref={lastMessageRef} ref={lastMessageRef}
onMouseDown={IS_TOUCH_ENV ? undefined : handleOpenTopic} onClick={handleOpenTopicClick}
onClick={IS_TOUCH_ENV ? handleOpenTopic : undefined} onMouseDown={handleOpenTopicMouseDown}
> >
{lastMessage} {lastMessage}
{!overwrittenWidth && !isReversedCorner && ( {!overwrittenWidth && !isReversedCorner && (

View File

@ -1,5 +1,5 @@
import type { FC } from '../../lib/teact/teact'; import type { FC } from '../../lib/teact/teact';
import React, { useCallback, useRef } from '../../lib/teact/teact'; import React, { useRef } from '../../lib/teact/teact';
import type { import type {
ApiUser, ApiMessage, ApiChat, ApiUser, ApiMessage, ApiChat,
@ -18,7 +18,6 @@ import { getPictogramDimensions } from './helpers/mediaDimensions';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import type { ObserveFn } from '../../hooks/useIntersectionObserver'; import type { ObserveFn } from '../../hooks/useIntersectionObserver';
import { IS_TOUCH_ENV, MouseButton } from '../../util/windowEnvironment';
import { useIsIntersecting } from '../../hooks/useIntersectionObserver'; import { useIsIntersecting } from '../../hooks/useIntersectionObserver';
import useMedia from '../../hooks/useMedia'; import useMedia from '../../hooks/useMedia';
import useThumbnail from '../../hooks/useThumbnail'; import useThumbnail from '../../hooks/useThumbnail';
@ -29,6 +28,7 @@ import MessageSummary from './MessageSummary';
import MediaSpoiler from './MediaSpoiler'; import MediaSpoiler from './MediaSpoiler';
import './EmbeddedMessage.scss'; import './EmbeddedMessage.scss';
import { useFastClick } from '../../hooks/useFastClick';
type OwnProps = { type OwnProps = {
className?: string; className?: string;
@ -72,13 +72,7 @@ const EmbeddedMessage: FC<OwnProps> = ({
const senderTitle = sender ? getSenderTitle(lang, sender) : message?.forwardInfo?.hiddenUserName; const senderTitle = sender ? getSenderTitle(lang, sender) : message?.forwardInfo?.hiddenUserName;
const handleClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => { const { handleClick, handleMouseDown } = useFastClick(onClick);
if (e.type === 'mousedown' && e.button !== MouseButton.Main) {
return;
}
onClick?.();
}, [onClick]);
return ( return (
<div <div
@ -88,8 +82,8 @@ const EmbeddedMessage: FC<OwnProps> = ({
className, className,
sender && !noUserColors && `color-${getUserColorKey(sender)}`, sender && !noUserColors && `color-${getUserColorKey(sender)}`,
)} )}
onClick={message && IS_TOUCH_ENV ? handleClick : undefined} onClick={message && handleClick}
onMouseDown={message && !IS_TOUCH_ENV ? handleClick : undefined} onMouseDown={message && handleMouseDown}
> >
{mediaThumbnail && renderPictogram(mediaThumbnail, mediaBlobUrl, isRoundVideo, isProtected, isSpoiler)} {mediaThumbnail && renderPictogram(mediaThumbnail, mediaBlobUrl, isRoundVideo, isProtected, isSpoiler)}
<div className="message-text"> <div className="message-text">

View File

@ -20,6 +20,7 @@ import { getOrderedTopics } from '../../../global/helpers';
import captureEscKeyListener from '../../../util/captureEscKeyListener'; import captureEscKeyListener from '../../../util/captureEscKeyListener';
import { waitForTransitionEnd } from '../../../util/cssAnimationEndListeners'; import { waitForTransitionEnd } from '../../../util/cssAnimationEndListeners';
import { captureEvents, SwipeDirection } from '../../../util/captureEvents'; import { captureEvents, SwipeDirection } from '../../../util/captureEvents';
import { createLocationHash } from '../../../util/routing';
import useInfiniteScroll from '../../../hooks/useInfiniteScroll'; import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
import { useIntersectionObserver, useOnIntersect } from '../../../hooks/useIntersectionObserver'; import { useIntersectionObserver, useOnIntersect } from '../../../hooks/useIntersectionObserver';
@ -139,6 +140,7 @@ const ForumPanel: FC<OwnProps & StateProps> = ({
useHistoryBack({ useHistoryBack({
isActive: isVisible, isActive: isVisible,
onBack: handleClose, onBack: handleClose,
hash: chat ? createLocationHash(chat.id, 'thread', MAIN_THREAD_ID) : undefined,
}); });
useEffect(() => (isVisible ? captureEscKeyListener(handleClose) : undefined), [handleClose, isVisible]); useEffect(() => (isVisible ? captureEscKeyListener(handleClose) : undefined), [handleClose, isVisible]);

View File

@ -10,13 +10,14 @@ import {
getMessageMediaHash, getMessageSingleInlineButton, getMessageMediaHash, getMessageSingleInlineButton,
} from '../../global/helpers'; } from '../../global/helpers';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { IS_TOUCH_ENV, MouseButton } from '../../util/windowEnvironment'; import { IS_TOUCH_ENV } from '../../util/windowEnvironment';
import renderText from '../common/helpers/renderText'; import renderText from '../common/helpers/renderText';
import useMedia from '../../hooks/useMedia'; import useMedia from '../../hooks/useMedia';
import useThumbnail from '../../hooks/useThumbnail'; import useThumbnail from '../../hooks/useThumbnail';
import useFlag from '../../hooks/useFlag'; import useFlag from '../../hooks/useFlag';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import { useFastClick } from '../../hooks/useFastClick';
import useAsyncRendering from '../right/hooks/useAsyncRendering'; import useAsyncRendering from '../right/hooks/useAsyncRendering';
import RippleEffect from '../ui/RippleEffect'; import RippleEffect from '../ui/RippleEffect';
@ -78,13 +79,7 @@ const HeaderPinnedMessage: FC<OwnProps> = ({
const [noHoverColor, markNoHoverColor, unmarkNoHoverColor] = useFlag(); const [noHoverColor, markNoHoverColor, unmarkNoHoverColor] = useFlag();
const handleClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => { const { handleClick, handleMouseDown } = useFastClick(onClick);
if (e.type === 'mousedown' && e.button !== MouseButton.Main) {
return;
}
onClick?.(e);
}, [onClick]);
function renderPictogram(thumbDataUri?: string, blobUrl?: string, spoiler?: boolean) { function renderPictogram(thumbDataUri?: string, blobUrl?: string, spoiler?: boolean) {
const { width, height } = getPictogramDimensions(); const { width, height } = getPictogramDimensions();
@ -148,8 +143,8 @@ const HeaderPinnedMessage: FC<OwnProps> = ({
/> />
<div <div
className={buildClassName(styles.pinnedMessage, noHoverColor && styles.noHover)} className={buildClassName(styles.pinnedMessage, noHoverColor && styles.noHover)}
onClick={IS_TOUCH_ENV ? handleClick : undefined} onClick={handleClick}
onMouseDown={!IS_TOUCH_ENV ? handleClick : undefined} onMouseDown={handleMouseDown}
dir={lang.isRtl ? 'rtl' : undefined} dir={lang.isRtl ? 'rtl' : undefined}
> >
<PinnedMessageNavigation <PinnedMessageNavigation

View File

@ -67,6 +67,7 @@ import GroupCallTopPane from '../calls/group/GroupCallTopPane';
import ChatReportPanel from './ChatReportPanel'; import ChatReportPanel from './ChatReportPanel';
import './MiddleHeader.scss'; import './MiddleHeader.scss';
import { useFastClick } from '../../hooks/useFastClick';
const ANIMATION_DURATION = 350; const ANIMATION_DURATION = 350;
const BACK_BUTTON_INACTIVE_TIME = 450; const BACK_BUTTON_INACTIVE_TIME = 450;
@ -178,9 +179,9 @@ const MiddleHeader: FC<OwnProps & StateProps> = ({
const componentRef = useRef<HTMLDivElement>(null); const componentRef = useRef<HTMLDivElement>(null);
const shouldAnimateTools = useRef<boolean>(true); const shouldAnimateTools = useRef<boolean>(true);
const handleHeaderClick = useCallback(() => { const { handleClick: handleHeaderClick, handleMouseDown: handleHeaderMouseDown } = useFastClick(() => {
openChatWithInfo({ id: chatId, threadId }); openChatWithInfo({ id: chatId, threadId });
}, [openChatWithInfo, chatId, threadId]); });
const handleUnpinMessage = useCallback((messageId: number) => { const handleUnpinMessage = useCallback((messageId: number) => {
pinMessage({ messageId, isUnpin: true }); pinMessage({ messageId, isUnpin: true });
@ -350,7 +351,11 @@ const MiddleHeader: FC<OwnProps & StateProps> = ({
return ( return (
<> <>
{(isLeftColumnHideable || currentTransitionKey > 0) && renderBackButton(shouldShowCloseButton, true)} {(isLeftColumnHideable || currentTransitionKey > 0) && renderBackButton(shouldShowCloseButton, true)}
<div className="chat-info-wrapper" onClick={handleHeaderClick}> <div
className="chat-info-wrapper"
onClick={handleHeaderClick}
onMouseDown={handleHeaderMouseDown}
>
{isUserId(chatId) ? ( {isUserId(chatId) ? (
<PrivateChatInfo <PrivateChatInfo
key={chatId} key={chatId}

View File

@ -18,6 +18,7 @@ import MessageOutgoingStatus from '../../common/MessageOutgoingStatus';
import AnimatedCounter from '../../common/AnimatedCounter'; import AnimatedCounter from '../../common/AnimatedCounter';
import './MessageMeta.scss'; import './MessageMeta.scss';
import { useFastClick } from '../../../hooks/useFastClick';
type OwnProps = { type OwnProps = {
message: ApiMessage; message: ApiMessage;
@ -53,13 +54,15 @@ const MessageMeta: FC<OwnProps> = ({
const lang = useLang(); const lang = useLang();
const [isActivated, markActivated] = useFlag(); const [isActivated, markActivated] = useFlag();
const handleClick = (e: React.MouseEvent) => { const { handleClick, handleMouseDown } = useFastClick(onClick);
function handleImportedClick(e: React.MouseEvent) {
e.stopPropagation(); e.stopPropagation();
showNotification({ showNotification({
message: lang('ImportedInfo'), message: lang('ImportedInfo'),
}); });
}; }
function handleOpenThread(e: React.MouseEvent) { function handleOpenThread(e: React.MouseEvent) {
e.stopPropagation(); e.stopPropagation();
@ -99,7 +102,8 @@ const MessageMeta: FC<OwnProps> = ({
<span <span
className={fullClassName} className={fullClassName}
dir={lang.isRtl ? 'rtl' : 'ltr'} dir={lang.isRtl ? 'rtl' : 'ltr'}
onClick={onClick} onClick={handleClick}
onMouseDown={handleMouseDown}
data-ignore-on-paste data-ignore-on-paste
> >
{isTranslated && ( {isTranslated && (
@ -130,10 +134,10 @@ const MessageMeta: FC<OwnProps> = ({
<span className="message-time" title={title} onMouseEnter={markActivated}> <span className="message-time" title={title} onMouseEnter={markActivated}>
{message.forwardInfo?.isImported && ( {message.forwardInfo?.isImported && (
<> <>
<span className="message-imported" onClick={handleClick}> <span className="message-imported" onClick={handleImportedClick}>
{formatDateTimeToString(message.forwardInfo.date * 1000, lang.code, true)} {formatDateTimeToString(message.forwardInfo.date * 1000, lang.code, true)}
</span> </span>
<span className="message-imported" onClick={handleClick}>{lang('ImportedMessage')}</span> <span className="message-imported" onClick={handleImportedClick}>{lang('ImportedMessage')}</span>
</> </>
)} )}
{message.isEdited && `${lang('EditedMessage')} `} {message.isEdited && `${lang('EditedMessage')} `}

View File

@ -10,6 +10,7 @@ import useContextMenuHandlers from '../../hooks/useContextMenuHandlers';
import useMenuPosition from '../../hooks/useMenuPosition'; import useMenuPosition from '../../hooks/useMenuPosition';
import useFlag from '../../hooks/useFlag'; import useFlag from '../../hooks/useFlag';
import useLang from '../../hooks/useLang'; import useLang from '../../hooks/useLang';
import { useFastClick } from '../../hooks/useFastClick';
import RippleEffect from './RippleEffect'; import RippleEffect from './RippleEffect';
import Menu from './Menu'; import Menu from './Menu';
@ -31,7 +32,9 @@ type MenuItemContextActionSeparator = {
key?: string; key?: string;
}; };
export type MenuItemContextAction = MenuItemContextActionItem | MenuItemContextActionSeparator; export type MenuItemContextAction =
MenuItemContextActionItem
| MenuItemContextActionSeparator;
interface OwnProps { interface OwnProps {
ref?: RefObject<HTMLDivElement>; ref?: RefObject<HTMLDivElement>;
@ -62,6 +65,7 @@ interface OwnProps {
onSecondaryIconClick?: (e: React.MouseEvent<HTMLButtonElement>) => void; onSecondaryIconClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
onDragEnter?: (e: React.DragEvent<HTMLDivElement>) => void; onDragEnter?: (e: React.DragEvent<HTMLDivElement>) => void;
} }
const ListItem: FC<OwnProps> = ({ const ListItem: FC<OwnProps> = ({
ref, ref,
buttonRef, buttonRef,
@ -162,15 +166,20 @@ const ListItem: FC<OwnProps> = ({
} }
}, [allowDisabledClick, clickArg, disabled, markIsTouched, onClick, ripple, unmarkIsTouched, href]); }, [allowDisabledClick, clickArg, disabled, markIsTouched, onClick, ripple, unmarkIsTouched, href]);
const handleSecondaryIconClick = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => { const {
handleClick: handleSecondaryIconClick,
handleMouseDown: handleSecondaryIconMouseDown,
} = useFastClick((e: React.MouseEvent<HTMLButtonElement>) => {
if ((disabled && !allowDisabledClick) || e.button !== 0 || (!onSecondaryIconClick && !contextActions)) return; if ((disabled && !allowDisabledClick) || e.button !== 0 || (!onSecondaryIconClick && !contextActions)) return;
e.stopPropagation(); e.stopPropagation();
if (onSecondaryIconClick) { if (onSecondaryIconClick) {
onSecondaryIconClick(e); onSecondaryIconClick(e);
} else { } else {
handleContextMenu(e); handleContextMenu(e);
} }
}; });
const handleMouseDown = useCallback((e: React.MouseEvent<HTMLElement, MouseEvent>) => { const handleMouseDown = useCallback((e: React.MouseEvent<HTMLElement, MouseEvent>) => {
if (inactive || IS_TOUCH_ENV) { if (inactive || IS_TOUCH_ENV) {
@ -242,8 +251,8 @@ const ListItem: FC<OwnProps> = ({
round round
color="translucent" color="translucent"
size="smaller" size="smaller"
onClick={IS_TOUCH_ENV ? handleSecondaryIconClick : undefined} onClick={handleSecondaryIconClick}
onMouseDown={!IS_TOUCH_ENV ? handleSecondaryIconClick : undefined} onMouseDown={handleSecondaryIconMouseDown}
> >
<i className={`icon icon-${secondaryIcon}`} /> <i className={`icon icon-${secondaryIcon}`} />
</Button> </Button>

View File

@ -9,17 +9,18 @@ import { requestForcedReflow, requestMutation } from '../../lib/fasterdom/faster
import type { FC } from '../../lib/teact/teact'; import type { FC } from '../../lib/teact/teact';
import type { MenuItemContextAction } from './ListItem'; import type { MenuItemContextAction } from './ListItem';
import { IS_TOUCH_ENV, MouseButton } from '../../util/windowEnvironment'; import { MouseButton } from '../../util/windowEnvironment';
import forceReflow from '../../util/forceReflow'; import forceReflow from '../../util/forceReflow';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import renderText from '../common/helpers/renderText'; import renderText from '../common/helpers/renderText';
import useMenuPosition from '../../hooks/useMenuPosition'; import useMenuPosition from '../../hooks/useMenuPosition';
import useContextMenuHandlers from '../../hooks/useContextMenuHandlers'; import useContextMenuHandlers from '../../hooks/useContextMenuHandlers';
import { useFastClick } from '../../hooks/useFastClick';
import Menu from './Menu'; import Menu from './Menu';
import MenuItem from './MenuItem'; import MenuItem from './MenuItem';
import MenuSeparator from './MenuSeparator';
import MenuSeparator from './MenuSeparator';
import './Tab.scss'; import './Tab.scss';
type OwnProps = { type OwnProps = {
@ -112,7 +113,7 @@ const Tab: FC<OwnProps> = ({
handleContextMenuHide, isContextMenuOpen, handleContextMenuHide, isContextMenuOpen,
} = useContextMenuHandlers(tabRef, !contextActions); } = useContextMenuHandlers(tabRef, !contextActions);
const handleClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => { const { handleClick, handleMouseDown } = useFastClick((e: React.MouseEvent<HTMLDivElement>) => {
if (contextActions && (e.button === MouseButton.Secondary || !onClick)) { if (contextActions && (e.button === MouseButton.Secondary || !onClick)) {
handleBeforeContextMenu(e); handleBeforeContextMenu(e);
} }
@ -122,7 +123,7 @@ const Tab: FC<OwnProps> = ({
} }
onClick?.(clickArg!); onClick?.(clickArg!);
}, [clickArg, contextActions, handleBeforeContextMenu, onClick]); });
const getTriggerElement = useCallback(() => tabRef.current, []); const getTriggerElement = useCallback(() => tabRef.current, []);
@ -157,8 +158,8 @@ const Tab: FC<OwnProps> = ({
return ( return (
<div <div
className={buildClassName('Tab', onClick && 'Tab--interactive', className)} className={buildClassName('Tab', onClick && 'Tab--interactive', className)}
onClick={IS_TOUCH_ENV ? handleClick : undefined} onClick={handleClick}
onMouseDown={!IS_TOUCH_ENV ? handleClick : undefined} onMouseDown={handleMouseDown}
onContextMenu={handleContextMenu} onContextMenu={handleContextMenu}
ref={tabRef} ref={tabRef}
> >

20
src/hooks/useFastClick.ts Normal file
View File

@ -0,0 +1,20 @@
import type React from '../lib/teact/teact';
import { IS_TOUCH_ENV, MouseButton } from '../util/windowEnvironment';
type EventArg<E> = React.MouseEvent<E>;
type EventHandler<E> = (e: EventArg<E>) => void;
export function useFastClick<T extends HTMLDivElement | HTMLButtonElement>(callback?: EventHandler<T>) {
const wrapperHandler = callback ? (e: EventArg<T>) => {
if (e.type === 'mousedown' && e.button !== MouseButton.Main) {
return;
}
callback(e);
} : undefined;
return IS_TOUCH_ENV
? { handleClick: wrapperHandler }
: { handleMouseDown: wrapperHandler };
}