@@ -8,6 +8,53 @@ import { coordX, coordY, touchEnabled, type VKUITouchEvent } from '../../lib/tou
88import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect' ;
99import type { HasComponent , HasRootRef } from '../../types' ;
1010
11+ interface EventWithType {
12+ /**
13+ * Тип события.
14+ */
15+ readonly type : string ;
16+ }
17+
18+ function isTouchEvent ( event : EventWithType ) {
19+ return event . type . startsWith ( 'touch' ) ;
20+ }
21+
22+ type CheckEvent = ( event : EventWithType ) => void ;
23+
24+ type IsEventLock = ( event : EventWithType ) => boolean ;
25+
26+ /**
27+ * Телефоны после touch событий могут отправлять события мыши,
28+ * Это может происходить при обычном нажатии.
29+ *
30+ * Нельзя использовать хук во время рендеринга.
31+ */
32+ function useMouseEventLock ( ) : [ IsEventLock , CheckEvent ] {
33+ const isMouseEventLockRef = React . useRef < boolean > ( false ) ;
34+ const timerRef = React . useRef < ReturnType < typeof setTimeout > > ( undefined ) ;
35+
36+ const isEventLock : IsEventLock = React . useCallback ( ( event : EventWithType ) => {
37+ return ! isTouchEvent ( event ) && isMouseEventLockRef . current === true ;
38+ } , [ ] ) ;
39+
40+ const checkEvent : CheckEvent = React . useCallback ( ( event : EventWithType ) => {
41+ if ( ! isTouchEvent ( event ) ) {
42+ return ;
43+ }
44+
45+ isMouseEventLockRef . current = true ;
46+
47+ clearTimeout ( timerRef . current ) ;
48+ timerRef . current = setTimeout ( ( ) => {
49+ isMouseEventLockRef . current = false ;
50+ } , 1000 ) ;
51+ } , [ ] ) ;
52+
53+ React . useEffect ( ( ) => ( ) => clearTimeout ( timerRef . current ) , [ ] ) ;
54+
55+ return [ isEventLock , checkEvent ] ;
56+ }
57+
1158/**
1259 * Костыль для правильной работы тайпскрипта.
1360 */
@@ -236,6 +283,8 @@ export const Touch = ({
236283 const didSlide = React . useRef ( false ) ;
237284 const disposeTargetNativeGestureEvents = React . useRef < VoidFunction | null > ( null ) ;
238285
286+ const [ isEventLock , checkEventForLock ] = useMouseEventLock ( ) ;
287+
239288 const cleanupTargetNativeGestureEvents = ( ) => {
240289 gestureRef . current = null ;
241290 if ( disposeTargetNativeGestureEvents . current ) {
@@ -246,10 +295,6 @@ export const Touch = ({
246295
247296 React . useEffect ( ( ) => cleanupTargetNativeGestureEvents , [ ] ) ;
248297
249- const isTouchEvent = ( event : MouseEvent | TouchEvent ) => {
250- return event . type . startsWith ( 'touch' ) ;
251- } ;
252-
253298 /**
254299 * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onEnd`/`onEndX`/`onEndY`.
255300 */
@@ -339,6 +384,13 @@ export const Touch = ({
339384 const handlePointerDown = useStableCallback (
340385 ( event : React . MouseEvent < HTMLElement > | React . TouchEvent < HTMLElement > | TouchEvent ) => {
341386 // Если touchstart сэмулировало mousedown, то заканчиваем обработку
387+ if ( isEventLock ( event ) ) {
388+ return ;
389+ }
390+
391+ // Помечаем что произошло touch событие
392+ checkEventForLock ( event ) ;
393+
342394 if ( gestureRef . current !== null ) {
343395 return ;
344396 }
@@ -465,11 +517,6 @@ export const Touch = ({
465517 // handlePointerDown(onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)
466518 onMouseDownCapture = { useCapture ? handlePointerDown : undefined }
467519 onMouseDown = { ! useCapture ? handlePointerDown : undefined }
468- onPointerDown = { ( event : PointerEvent ) => {
469- if ( event . pointerType === 'touch' || event . pointerType === 'pen' ) {
470- event . preventDefault ( ) ;
471- }
472- } }
473520 />
474521 ) ;
475522} ;
0 commit comments