@vkontakte/vkui 7.6.2 → 7.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"Touch.d.ts","sourceRoot":"","sources":["../../../src/components/Touch/Touch.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEpF,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAkC5D,MAAM,WAAW,gBAAiB,SAAQ,OAAO;IAC/C;;OAEG;IACH,aAAa,EAAE,cAAc,CAAC;CAC/B;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,WAAW,EAAE,UAAU,KAAK,IAAI,CAAC;AAE7D,MAAM,MAAM,uBAAuB,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAExE,MAAM,WAAW,UACf,SAAQ,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAC1C,UAAU,CAAC,WAAW,CAAC,EACvB,YAAY;IACd;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC;;OAEG;IACH,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC;;OAEG;IACH,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC;;OAEG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC;;OAEG;IACH,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC;;OAEG;IACH,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC;;OAEG;IACH,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC;;OAEG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC;;OAEG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAC;CAClC;AAED,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,IAAI,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,GAAG,EAAE,OAAO,CAAC;IAEb;;OAEG;IACH,GAAG,EAAE,OAAO,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,eAAO,MAAM,KAAK,GAAI,qOAqBnB,UAAU,4CAqOZ,CAAC"}
1
+ {"version":3,"file":"Touch.d.ts","sourceRoot":"","sources":["../../../src/components/Touch/Touch.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEpF,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAkC5D,MAAM,WAAW,gBAAiB,SAAQ,OAAO;IAC/C;;OAEG;IACH,aAAa,EAAE,cAAc,CAAC;CAC/B;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,WAAW,EAAE,UAAU,KAAK,IAAI,CAAC;AAE7D,MAAM,MAAM,uBAAuB,GAAG,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAExE,MAAM,WAAW,UACf,SAAQ,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAC1C,UAAU,CAAC,WAAW,CAAC,EACvB,YAAY;IACd;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC;;OAEG;IACH,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC;;OAEG;IACH,QAAQ,CAAC,EAAE,uBAAuB,CAAC;IACnC;;OAEG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC;;OAEG;IACH,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC;;OAEG;IACH,OAAO,CAAC,EAAE,uBAAuB,CAAC;IAClC;;OAEG;IACH,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC;;OAEG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC;;OAEG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAC;CAClC;AAED,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,IAAI,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,GAAG,EAAE,OAAO,CAAC;IAEb;;OAEG;IACH,GAAG,EAAE,OAAO,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,eAAO,MAAM,KAAK,GAAI,qOAqBnB,UAAU,4CA8OZ,CAAC"}
@@ -46,6 +46,9 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
46
46
  }
47
47
  };
48
48
  React.useEffect(()=>cleanupTargetNativeGestureEvents, []);
49
+ const isTouchEvent = (event)=>{
50
+ return event.type.startsWith('touch');
51
+ };
49
52
  /**
50
53
  * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onEnd`/`onEndX`/`onEndY`.
51
54
  */ const handleNativePointerUp = useStableCallback((event)=>{
@@ -60,7 +63,7 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
60
63
  onEndY
61
64
  ], stopPropagation);
62
65
  }
63
- if (isTouchEnabled) {
66
+ if (isTouchEvent(event)) {
64
67
  // https://github.com/VKCOM/VKUI/issues/4414
65
68
  // если тач-устройство и был зафиксирован touchmove,
66
69
  // то событие клика не вызывается
@@ -122,6 +125,10 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
122
125
  }
123
126
  });
124
127
  const handlePointerDown = useStableCallback((event)=>{
128
+ // Если touchstart сэмулировало mousedown, то заканчиваем обработку
129
+ if (gestureRef.current !== null) {
130
+ return;
131
+ }
125
132
  const nativeEvent = 'nativeEvent' in event ? event.nativeEvent : event;
126
133
  gestureRef.current = initGesture(coordX(nativeEvent), coordY(nativeEvent));
127
134
  const shouldCallDirectionHandlerOnlyIsSlide = false;
@@ -136,7 +143,7 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
136
143
  };
137
144
  // FIXME: заменить touch/mouse-события ниже на pointer-события после того, как бразуеры из
138
145
  // .browserslistrc начнут поддерживать его (см. https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#browser_compatibility).
139
- if (isTouchEnabled) {
146
+ if (isTouchEvent(nativeEvent)) {
140
147
  if (isHTMLElement(event.target) || isSVGElement(event.target)) {
141
148
  // Тач-события не всплывают, поэтому навешиваем события на целевой элемент
142
149
  // см. #235, #1968, https://stackoverflow.com/a/45760014
@@ -219,9 +226,9 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
219
226
  // onLeave
220
227
  onPointerLeave: usePointerHover ? handlePointerLeave : undefined,
221
228
  onMouseLeave: !usePointerHover ? handlePointerLeave : undefined,
222
- // handlePointerDown (onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)
223
- onMouseDownCapture: !isTouchEnabled && useCapture ? handlePointerDown : undefined,
224
- onMouseDown: !isTouchEnabled && !useCapture ? handlePointerDown : undefined
229
+ // handlePointerDown(onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)
230
+ onMouseDownCapture: useCapture ? handlePointerDown : undefined,
231
+ onMouseDown: !useCapture ? handlePointerDown : undefined
225
232
  }));
226
233
  };
227
234
  function initGesture(startX, startY) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/Touch/Touch.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useExternRef } from '../../hooks/useExternRef';\nimport { useStableCallback } from '../../hooks/useStableCallback';\nimport { getWindow, isHTMLElement, isSVGElement } from '../../lib/dom';\nimport { coordX, coordY, touchEnabled, type VKUITouchEvent } from '../../lib/touch';\nimport { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';\nimport type { HasComponent, HasRootRef } from '../../types';\n\n/**\n * Костыль для правильной работы тайпскрипта.\n */\ntype HTMLorSVGElementWithEvents = {\n /**\n * AddEventListener.\n */\n addEventListener: (<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,\n options?: boolean | AddEventListenerOptions,\n ) => void) &\n (<K extends keyof SVGElementEventMap>(\n type: K,\n listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n /**\n * RemoveEventListener.\n */\n removeEventListener: (<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ) => void) &\n (<K extends keyof SVGElementEventMap>(\n type: K,\n listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ) => void);\n};\n\nexport interface CustomTouchEvent extends Gesture {\n /**\n * Оригинальное событие.\n */\n originalEvent: VKUITouchEvent;\n}\n\nexport type HoverHandler = (outputEvent: MouseEvent) => void;\n\nexport type CustomTouchEventHandler = (event: CustomTouchEvent) => void;\n\nexport interface TouchProps\n extends React.AllHTMLAttributes<HTMLElement>,\n HasRootRef<HTMLElement>,\n HasComponent {\n /**\n * Использовать pointer-events для hover-состояний.\n * Работает на отключенных элементах (disabled inputs).\n */\n usePointerHover?: boolean;\n /**\n * Использовать фазу capture для событий.\n */\n useCapture?: boolean;\n /**\n * Порог расстояния в пикселях для активации свайпа.\n * @default 5\n */\n slideThreshold?: number;\n /**\n * Блокировать click-события после распознавания свайпа.\n */\n noSlideClick?: boolean;\n /**\n * Останавливать всплытие событий.\n */\n stopPropagation?: boolean;\n /**\n * Обработчик входа курсора в область.\n */\n onEnter?: HoverHandler;\n /**\n * Обработчик выхода курсора из области.\n */\n onLeave?: HoverHandler;\n /**\n * Общий обработчик начала взаимодействия.\n */\n onStart?: CustomTouchEventHandler;\n /**\n * Обработчик начала горизонтального перемещения.\n */\n onStartX?: CustomTouchEventHandler;\n /**\n * Обработчик начала вертикального перемещения.\n */\n onStartY?: CustomTouchEventHandler;\n /**\n * Общий обработчик перемещения.\n */\n onMove?: CustomTouchEventHandler;\n /**\n * Обработчик горизонтального перемещения.\n */\n onMoveX?: CustomTouchEventHandler;\n /**\n * Обработчик вертикального перемещения.\n */\n onMoveY?: CustomTouchEventHandler;\n /**\n * Общий обработчик завершения взаимодействия.\n */\n onEnd?: CustomTouchEventHandler;\n /**\n * Обработчик завершения горизонтального свайпа.\n */\n onEndX?: CustomTouchEventHandler;\n /**\n * Обработчик завершения вертикального свайпа.\n */\n onEndY?: CustomTouchEventHandler;\n}\n\nexport interface Gesture {\n /**\n * Начальная X-координата касания.\n */\n startX: number;\n\n /**\n * Начальная Y-координата касания.\n */\n startY: number;\n\n /**\n * Время начала взаимодействия.\n */\n startT: Date;\n\n /**\n * Длительность взаимодействия в миллисекундах.\n */\n duration: number;\n\n /**\n * Флаг активного нажатия.\n */\n isPressed: boolean;\n\n /**\n * Флаг вертикального перемещения.\n */\n isY: boolean;\n\n /**\n * Флаг горизонтального перемещения.\n */\n isX: boolean;\n\n /**\n * Флаг горизонтального свайпа.\n */\n isSlideX: boolean;\n\n /**\n * Флаг вертикального свайпа.\n */\n isSlideY: boolean;\n\n /**\n * Общий флаг свайпа (вертикального или горизонтального).\n */\n isSlide: boolean;\n\n /**\n * Текущая X-координата курсора/касания.\n */\n clientX: number;\n\n /**\n * Текущая Y-координата курсора/касания.\n */\n clientY: number;\n\n /**\n * Смещение по X относительно начальной точки.\n */\n shiftX: number;\n\n /**\n * Смещение по Y относительно начальной точки.\n */\n shiftY: number;\n\n /**\n * Абсолютное смещение по X.\n */\n shiftXAbs: number;\n\n /**\n * Абсолютное смещение по Y.\n */\n shiftYAbs: number;\n}\n\n/**\n * @see https://vkui.io/components/touch\n */\nexport const Touch = ({\n onStart,\n onStartX,\n onStartY,\n onMove,\n onMoveX,\n onMoveY,\n onEnter,\n onLeave,\n onEnd,\n onEndX,\n onEndY,\n onClickCapture,\n usePointerHover,\n slideThreshold = 5,\n useCapture = false,\n Component = 'div',\n getRootRef,\n noSlideClick = false,\n stopPropagation = false,\n ...restProps\n}: TouchProps) => {\n const hostRef = useExternRef(getRootRef);\n const [isTouchEnabled] = React.useState(touchEnabled);\n const gestureRef = React.useRef<Gesture | null>(null);\n const didSlide = React.useRef(false);\n const disposeTargetNativeGestureEvents = React.useRef<VoidFunction | null>(null);\n\n const cleanupTargetNativeGestureEvents = () => {\n gestureRef.current = null;\n if (disposeTargetNativeGestureEvents.current) {\n disposeTargetNativeGestureEvents.current();\n disposeTargetNativeGestureEvents.current = null;\n }\n };\n\n React.useEffect(() => cleanupTargetNativeGestureEvents, []);\n\n /**\n * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onEnd`/`onEndX`/`onEndY`.\n */\n const handleNativePointerUp = useStableCallback((event: MouseEvent | TouchEvent) => {\n const gesture = gestureRef.current;\n\n /* istanbul ignore if: нужно для Typescript */\n if (!gesture) {\n return;\n }\n\n if (gesture.isPressed) {\n dispatchUserHandlers(event, gesture, [onEnd, onEndX, onEndY], stopPropagation);\n }\n\n if (isTouchEnabled) {\n // https://github.com/VKCOM/VKUI/issues/4414\n // если тач-устройство и был зафиксирован touchmove,\n // то событие клика не вызывается\n if (gesture.isSlide) {\n didSlide.current = false;\n }\n // Если это был тач-евент, симулируем отмену hover\n if (onLeave) {\n onLeave(event as MouseEvent);\n }\n } else {\n didSlide.current = Boolean(gesture.isSlide);\n }\n\n cleanupTargetNativeGestureEvents();\n });\n\n /**\n * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onMove`/`onMoveX`/`onMoveY`.\n */\n const handleNativePointerMove = useStableCallback((event: MouseEvent | TouchEvent) => {\n const gesture = gestureRef.current;\n\n /* istanbul ignore if: нужно для Typescript */\n if (!gesture) {\n return;\n }\n\n const clientX = coordX(event);\n const clientY = coordY(event);\n\n // смещения\n const shiftX = clientX - gesture.startX;\n const shiftY = clientY - gesture.startY;\n\n // абсолютные значения смещений\n const shiftXAbs = Math.abs(shiftX);\n const shiftYAbs = Math.abs(shiftY);\n\n // Если определяем мультитач, то прерываем жест\n if ('touches' in event && event.touches.length > 1) {\n return handleNativePointerUp(event);\n }\n\n // если мы ещё не определились\n if (!gesture.isX && !gesture.isY) {\n const willBeX = shiftXAbs >= slideThreshold && shiftXAbs > shiftYAbs;\n const willBeY = shiftYAbs >= slideThreshold && shiftYAbs > shiftXAbs;\n const willBeSlidedX = willBeX && (!!onMoveX || !!onMove);\n const willBeSlidedY = willBeY && (!!onMoveY || !!onMove);\n\n gesture.isY = willBeY;\n gesture.isX = willBeX;\n gesture.isSlideX = willBeSlidedX;\n gesture.isSlideY = willBeSlidedY;\n gesture.isSlide = willBeSlidedX || willBeSlidedY;\n }\n\n if (gesture.isSlide) {\n gesture.clientX = clientX;\n gesture.clientY = clientY;\n gesture.shiftX = shiftX;\n gesture.shiftY = shiftY;\n gesture.shiftXAbs = shiftXAbs;\n gesture.shiftYAbs = shiftYAbs;\n\n dispatchUserHandlers(event, gesture, [onMove, onMoveX, onMoveY], stopPropagation);\n }\n });\n\n const handlePointerDown = useStableCallback(\n (event: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement> | TouchEvent) => {\n const nativeEvent = 'nativeEvent' in event ? event.nativeEvent : event;\n\n gestureRef.current = initGesture(coordX(nativeEvent), coordY(nativeEvent));\n\n const shouldCallDirectionHandlerOnlyIsSlide = false;\n dispatchUserHandlers(\n event,\n gestureRef.current,\n [onStart, onStartX, onStartY],\n stopPropagation,\n shouldCallDirectionHandlerOnlyIsSlide,\n );\n\n const eventOptions = { capture: useCapture, passive: false };\n\n // FIXME: заменить touch/mouse-события ниже на pointer-события после того, как бразуеры из\n // .browserslistrc начнут поддерживать его (см. https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#browser_compatibility).\n if (isTouchEnabled) {\n if (isHTMLElement(event.target) || isSVGElement(event.target)) {\n // Тач-события не всплывают, поэтому навешиваем события на целевой элемент\n // см. #235, #1968, https://stackoverflow.com/a/45760014\n const target: HTMLorSVGElementWithEvents = event.target;\n\n target.addEventListener('touchmove', handleNativePointerMove, eventOptions);\n target.addEventListener('touchend', handleNativePointerUp, eventOptions);\n target.addEventListener('touchcancel', handleNativePointerUp, eventOptions);\n\n disposeTargetNativeGestureEvents.current = () => {\n target.removeEventListener('touchmove', handleNativePointerMove, eventOptions);\n target.removeEventListener('touchend', handleNativePointerUp, eventOptions);\n target.removeEventListener('touchcancel', handleNativePointerUp, eventOptions);\n };\n }\n } else {\n // Используем события на Document, т.к. mouse-события на целевом элементе могут теряться при\n // выходе за границы этого элемента.\n const doc = getWindow(event.currentTarget).document;\n\n doc.addEventListener('mousemove', handleNativePointerMove, eventOptions);\n doc.addEventListener('mouseup', handleNativePointerUp, eventOptions);\n doc.addEventListener('mouseleave', handleNativePointerUp, eventOptions);\n\n disposeTargetNativeGestureEvents.current = () => {\n doc.removeEventListener('mousemove', handleNativePointerMove, eventOptions);\n doc.removeEventListener('mouseup', handleNativePointerUp, eventOptions);\n doc.removeEventListener('mouseleave', handleNativePointerUp, eventOptions);\n };\n }\n },\n );\n\n const handlePointerEnter = onEnter\n ? (event: React.MouseEvent<HTMLElement>) => onEnter(event.nativeEvent)\n : undefined;\n\n const handlePointerLeave = onLeave\n ? (event: React.MouseEvent<HTMLElement>) => onLeave(event.nativeEvent)\n : undefined;\n\n /**\n * Отменяет нативное браузерное поведение для вложенных ссылок и изображений.\n */\n const handleDragStart = (event: React.DragEvent<HTMLElement>) => {\n const target = event.target as HTMLElement;\n if (target.tagName === 'A' || target.tagName === 'IMG') {\n event.preventDefault();\n }\n };\n\n /**\n * Отменяет переход по вложенной ссылке, если был зафиксирован свайп.\n */\n const handleClickCapture: typeof onClickCapture = (event) => {\n if (!didSlide.current) {\n return onClickCapture && onClickCapture(event);\n }\n\n if (noSlideClick) {\n event.stopPropagation();\n\n // https://github.com/VKCOM/VKUI/issues/1977\n // https://github.com/VKCOM/VKUI/issues/3892\n event.preventDefault();\n } else {\n onClickCapture && onClickCapture(event);\n }\n\n didSlide.current = false;\n };\n\n useIsomorphicLayoutEffect(\n function initializeNativeTouchStartEventWithPassiveFalse() {\n const hostEl = hostRef.current;\n if (!hostEl || !isTouchEnabled) {\n return;\n }\n\n const options = { capture: useCapture, passive: false };\n hostEl.addEventListener('touchstart', handlePointerDown, options);\n\n return () => {\n hostEl.removeEventListener('touchstart', handlePointerDown, options);\n };\n },\n [hostRef, isTouchEnabled, useCapture, handlePointerDown],\n );\n\n return (\n <Component\n {...restProps}\n ref={hostRef}\n onDragStart={handleDragStart}\n onClickCapture={handleClickCapture}\n // onEnter\n onPointerEnter={usePointerHover ? handlePointerEnter : undefined}\n onMouseEnter={!usePointerHover ? handlePointerEnter : undefined}\n // onLeave\n onPointerLeave={usePointerHover ? handlePointerLeave : undefined}\n onMouseLeave={!usePointerHover ? handlePointerLeave : undefined}\n // handlePointerDown (onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)\n onMouseDownCapture={!isTouchEnabled && useCapture ? handlePointerDown : undefined}\n onMouseDown={!isTouchEnabled && !useCapture ? handlePointerDown : undefined}\n />\n );\n};\n\nfunction initGesture(startX: number, startY: number): Gesture {\n return {\n startX,\n startY,\n startT: new Date(),\n duration: 0,\n isPressed: true,\n isY: false,\n isX: false,\n isSlideX: false,\n isSlideY: false,\n isSlide: false,\n clientX: 0,\n clientY: 0,\n shiftX: 0,\n shiftY: 0,\n shiftXAbs: 0,\n shiftYAbs: 0,\n };\n}\n\ntype Handlers = [\n CustomTouchEventHandler | undefined,\n CustomTouchEventHandler | undefined,\n CustomTouchEventHandler | undefined,\n];\n\nfunction dispatchUserHandlers(\n event: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent,\n gesture: Gesture,\n [handler, handlerX, handlerY]: Handlers,\n stopPropagation?: boolean,\n shouldCallDirectionHandlerOnlyIsSlide = true,\n) {\n if (stopPropagation) {\n event.stopPropagation();\n }\n\n const data = {\n ...gesture,\n originalEvent: event as unknown as VKUITouchEvent,\n duration: Date.now() - gesture.startT.getTime(),\n };\n\n if (handler) {\n handler(data);\n }\n\n if (handlerX) {\n if (shouldCallDirectionHandlerOnlyIsSlide) {\n if (gesture.isSlideX) {\n handlerX(data);\n }\n } else {\n handlerX(data);\n }\n }\n\n if (handlerY) {\n if (shouldCallDirectionHandlerOnlyIsSlide) {\n if (gesture.isSlideY) {\n handlerY(data);\n }\n } else {\n handlerY(data);\n }\n }\n}\n"],"names":["React","useExternRef","useStableCallback","getWindow","isHTMLElement","isSVGElement","coordX","coordY","touchEnabled","useIsomorphicLayoutEffect","Touch","onStart","onStartX","onStartY","onMove","onMoveX","onMoveY","onEnter","onLeave","onEnd","onEndX","onEndY","onClickCapture","usePointerHover","slideThreshold","useCapture","Component","getRootRef","noSlideClick","stopPropagation","restProps","hostRef","isTouchEnabled","useState","gestureRef","useRef","didSlide","disposeTargetNativeGestureEvents","cleanupTargetNativeGestureEvents","current","useEffect","handleNativePointerUp","event","gesture","isPressed","dispatchUserHandlers","isSlide","Boolean","handleNativePointerMove","clientX","clientY","shiftX","startX","shiftY","startY","shiftXAbs","Math","abs","shiftYAbs","touches","length","isX","isY","willBeX","willBeY","willBeSlidedX","willBeSlidedY","isSlideX","isSlideY","handlePointerDown","nativeEvent","initGesture","shouldCallDirectionHandlerOnlyIsSlide","eventOptions","capture","passive","target","addEventListener","removeEventListener","doc","currentTarget","document","handlePointerEnter","undefined","handlePointerLeave","handleDragStart","tagName","preventDefault","handleClickCapture","initializeNativeTouchStartEventWithPassiveFalse","hostEl","options","ref","onDragStart","onPointerEnter","onMouseEnter","onPointerLeave","onMouseLeave","onMouseDownCapture","onMouseDown","startT","Date","duration","handler","handlerX","handlerY","data","originalEvent","now","getTime"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/Touch/Touch.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useExternRef } from '../../hooks/useExternRef';\nimport { useStableCallback } from '../../hooks/useStableCallback';\nimport { getWindow, isHTMLElement, isSVGElement } from '../../lib/dom';\nimport { coordX, coordY, touchEnabled, type VKUITouchEvent } from '../../lib/touch';\nimport { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';\nimport type { HasComponent, HasRootRef } from '../../types';\n\n/**\n * Костыль для правильной работы тайпскрипта.\n */\ntype HTMLorSVGElementWithEvents = {\n /**\n * AddEventListener.\n */\n addEventListener: (<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,\n options?: boolean | AddEventListenerOptions,\n ) => void) &\n (<K extends keyof SVGElementEventMap>(\n type: K,\n listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n /**\n * RemoveEventListener.\n */\n removeEventListener: (<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ) => void) &\n (<K extends keyof SVGElementEventMap>(\n type: K,\n listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ) => void);\n};\n\nexport interface CustomTouchEvent extends Gesture {\n /**\n * Оригинальное событие.\n */\n originalEvent: VKUITouchEvent;\n}\n\nexport type HoverHandler = (outputEvent: MouseEvent) => void;\n\nexport type CustomTouchEventHandler = (event: CustomTouchEvent) => void;\n\nexport interface TouchProps\n extends React.AllHTMLAttributes<HTMLElement>,\n HasRootRef<HTMLElement>,\n HasComponent {\n /**\n * Использовать pointer-events для hover-состояний.\n * Работает на отключенных элементах (disabled inputs).\n */\n usePointerHover?: boolean;\n /**\n * Использовать фазу capture для событий.\n */\n useCapture?: boolean;\n /**\n * Порог расстояния в пикселях для активации свайпа.\n * @default 5\n */\n slideThreshold?: number;\n /**\n * Блокировать click-события после распознавания свайпа.\n */\n noSlideClick?: boolean;\n /**\n * Останавливать всплытие событий.\n */\n stopPropagation?: boolean;\n /**\n * Обработчик входа курсора в область.\n */\n onEnter?: HoverHandler;\n /**\n * Обработчик выхода курсора из области.\n */\n onLeave?: HoverHandler;\n /**\n * Общий обработчик начала взаимодействия.\n */\n onStart?: CustomTouchEventHandler;\n /**\n * Обработчик начала горизонтального перемещения.\n */\n onStartX?: CustomTouchEventHandler;\n /**\n * Обработчик начала вертикального перемещения.\n */\n onStartY?: CustomTouchEventHandler;\n /**\n * Общий обработчик перемещения.\n */\n onMove?: CustomTouchEventHandler;\n /**\n * Обработчик горизонтального перемещения.\n */\n onMoveX?: CustomTouchEventHandler;\n /**\n * Обработчик вертикального перемещения.\n */\n onMoveY?: CustomTouchEventHandler;\n /**\n * Общий обработчик завершения взаимодействия.\n */\n onEnd?: CustomTouchEventHandler;\n /**\n * Обработчик завершения горизонтального свайпа.\n */\n onEndX?: CustomTouchEventHandler;\n /**\n * Обработчик завершения вертикального свайпа.\n */\n onEndY?: CustomTouchEventHandler;\n}\n\nexport interface Gesture {\n /**\n * Начальная X-координата касания.\n */\n startX: number;\n\n /**\n * Начальная Y-координата касания.\n */\n startY: number;\n\n /**\n * Время начала взаимодействия.\n */\n startT: Date;\n\n /**\n * Длительность взаимодействия в миллисекундах.\n */\n duration: number;\n\n /**\n * Флаг активного нажатия.\n */\n isPressed: boolean;\n\n /**\n * Флаг вертикального перемещения.\n */\n isY: boolean;\n\n /**\n * Флаг горизонтального перемещения.\n */\n isX: boolean;\n\n /**\n * Флаг горизонтального свайпа.\n */\n isSlideX: boolean;\n\n /**\n * Флаг вертикального свайпа.\n */\n isSlideY: boolean;\n\n /**\n * Общий флаг свайпа (вертикального или горизонтального).\n */\n isSlide: boolean;\n\n /**\n * Текущая X-координата курсора/касания.\n */\n clientX: number;\n\n /**\n * Текущая Y-координата курсора/касания.\n */\n clientY: number;\n\n /**\n * Смещение по X относительно начальной точки.\n */\n shiftX: number;\n\n /**\n * Смещение по Y относительно начальной точки.\n */\n shiftY: number;\n\n /**\n * Абсолютное смещение по X.\n */\n shiftXAbs: number;\n\n /**\n * Абсолютное смещение по Y.\n */\n shiftYAbs: number;\n}\n\n/**\n * @see https://vkui.io/components/touch\n */\nexport const Touch = ({\n onStart,\n onStartX,\n onStartY,\n onMove,\n onMoveX,\n onMoveY,\n onEnter,\n onLeave,\n onEnd,\n onEndX,\n onEndY,\n onClickCapture,\n usePointerHover,\n slideThreshold = 5,\n useCapture = false,\n Component = 'div',\n getRootRef,\n noSlideClick = false,\n stopPropagation = false,\n ...restProps\n}: TouchProps) => {\n const hostRef = useExternRef(getRootRef);\n const [isTouchEnabled] = React.useState(touchEnabled);\n const gestureRef = React.useRef<Gesture | null>(null);\n const didSlide = React.useRef(false);\n const disposeTargetNativeGestureEvents = React.useRef<VoidFunction | null>(null);\n\n const cleanupTargetNativeGestureEvents = () => {\n gestureRef.current = null;\n if (disposeTargetNativeGestureEvents.current) {\n disposeTargetNativeGestureEvents.current();\n disposeTargetNativeGestureEvents.current = null;\n }\n };\n\n React.useEffect(() => cleanupTargetNativeGestureEvents, []);\n\n const isTouchEvent = (event: MouseEvent | TouchEvent) => {\n return event.type.startsWith('touch');\n };\n\n /**\n * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onEnd`/`onEndX`/`onEndY`.\n */\n const handleNativePointerUp = useStableCallback((event: MouseEvent | TouchEvent) => {\n const gesture = gestureRef.current;\n\n /* istanbul ignore if: нужно для Typescript */\n if (!gesture) {\n return;\n }\n\n if (gesture.isPressed) {\n dispatchUserHandlers(event, gesture, [onEnd, onEndX, onEndY], stopPropagation);\n }\n\n if (isTouchEvent(event)) {\n // https://github.com/VKCOM/VKUI/issues/4414\n // если тач-устройство и был зафиксирован touchmove,\n // то событие клика не вызывается\n if (gesture.isSlide) {\n didSlide.current = false;\n }\n // Если это был тач-евент, симулируем отмену hover\n if (onLeave) {\n onLeave(event as MouseEvent);\n }\n } else {\n didSlide.current = Boolean(gesture.isSlide);\n }\n\n cleanupTargetNativeGestureEvents();\n });\n\n /**\n * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onMove`/`onMoveX`/`onMoveY`.\n */\n const handleNativePointerMove = useStableCallback((event: MouseEvent | TouchEvent) => {\n const gesture = gestureRef.current;\n\n /* istanbul ignore if: нужно для Typescript */\n if (!gesture) {\n return;\n }\n\n const clientX = coordX(event);\n const clientY = coordY(event);\n\n // смещения\n const shiftX = clientX - gesture.startX;\n const shiftY = clientY - gesture.startY;\n\n // абсолютные значения смещений\n const shiftXAbs = Math.abs(shiftX);\n const shiftYAbs = Math.abs(shiftY);\n\n // Если определяем мультитач, то прерываем жест\n if ('touches' in event && event.touches.length > 1) {\n return handleNativePointerUp(event);\n }\n\n // если мы ещё не определились\n if (!gesture.isX && !gesture.isY) {\n const willBeX = shiftXAbs >= slideThreshold && shiftXAbs > shiftYAbs;\n const willBeY = shiftYAbs >= slideThreshold && shiftYAbs > shiftXAbs;\n const willBeSlidedX = willBeX && (!!onMoveX || !!onMove);\n const willBeSlidedY = willBeY && (!!onMoveY || !!onMove);\n\n gesture.isY = willBeY;\n gesture.isX = willBeX;\n gesture.isSlideX = willBeSlidedX;\n gesture.isSlideY = willBeSlidedY;\n gesture.isSlide = willBeSlidedX || willBeSlidedY;\n }\n\n if (gesture.isSlide) {\n gesture.clientX = clientX;\n gesture.clientY = clientY;\n gesture.shiftX = shiftX;\n gesture.shiftY = shiftY;\n gesture.shiftXAbs = shiftXAbs;\n gesture.shiftYAbs = shiftYAbs;\n\n dispatchUserHandlers(event, gesture, [onMove, onMoveX, onMoveY], stopPropagation);\n }\n });\n\n const handlePointerDown = useStableCallback(\n (event: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement> | TouchEvent) => {\n // Если touchstart сэмулировало mousedown, то заканчиваем обработку\n if (gestureRef.current !== null) {\n return;\n }\n\n const nativeEvent = 'nativeEvent' in event ? event.nativeEvent : event;\n\n gestureRef.current = initGesture(coordX(nativeEvent), coordY(nativeEvent));\n\n const shouldCallDirectionHandlerOnlyIsSlide = false;\n dispatchUserHandlers(\n event,\n gestureRef.current,\n [onStart, onStartX, onStartY],\n stopPropagation,\n shouldCallDirectionHandlerOnlyIsSlide,\n );\n\n const eventOptions = { capture: useCapture, passive: false };\n\n // FIXME: заменить touch/mouse-события ниже на pointer-события после того, как бразуеры из\n // .browserslistrc начнут поддерживать его (см. https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#browser_compatibility).\n if (isTouchEvent(nativeEvent)) {\n if (isHTMLElement(event.target) || isSVGElement(event.target)) {\n // Тач-события не всплывают, поэтому навешиваем события на целевой элемент\n // см. #235, #1968, https://stackoverflow.com/a/45760014\n const target: HTMLorSVGElementWithEvents = event.target;\n\n target.addEventListener('touchmove', handleNativePointerMove, eventOptions);\n target.addEventListener('touchend', handleNativePointerUp, eventOptions);\n target.addEventListener('touchcancel', handleNativePointerUp, eventOptions);\n\n disposeTargetNativeGestureEvents.current = () => {\n target.removeEventListener('touchmove', handleNativePointerMove, eventOptions);\n target.removeEventListener('touchend', handleNativePointerUp, eventOptions);\n target.removeEventListener('touchcancel', handleNativePointerUp, eventOptions);\n };\n }\n } else {\n // Используем события на Document, т.к. mouse-события на целевом элементе могут теряться при\n // выходе за границы этого элемента.\n const doc = getWindow(event.currentTarget).document;\n\n doc.addEventListener('mousemove', handleNativePointerMove, eventOptions);\n doc.addEventListener('mouseup', handleNativePointerUp, eventOptions);\n doc.addEventListener('mouseleave', handleNativePointerUp, eventOptions);\n\n disposeTargetNativeGestureEvents.current = () => {\n doc.removeEventListener('mousemove', handleNativePointerMove, eventOptions);\n doc.removeEventListener('mouseup', handleNativePointerUp, eventOptions);\n doc.removeEventListener('mouseleave', handleNativePointerUp, eventOptions);\n };\n }\n },\n );\n\n const handlePointerEnter = onEnter\n ? (event: React.MouseEvent<HTMLElement>) => onEnter(event.nativeEvent)\n : undefined;\n\n const handlePointerLeave = onLeave\n ? (event: React.MouseEvent<HTMLElement>) => onLeave(event.nativeEvent)\n : undefined;\n\n /**\n * Отменяет нативное браузерное поведение для вложенных ссылок и изображений.\n */\n const handleDragStart = (event: React.DragEvent<HTMLElement>) => {\n const target = event.target as HTMLElement;\n if (target.tagName === 'A' || target.tagName === 'IMG') {\n event.preventDefault();\n }\n };\n\n /**\n * Отменяет переход по вложенной ссылке, если был зафиксирован свайп.\n */\n const handleClickCapture: typeof onClickCapture = (event) => {\n if (!didSlide.current) {\n return onClickCapture && onClickCapture(event);\n }\n\n if (noSlideClick) {\n event.stopPropagation();\n\n // https://github.com/VKCOM/VKUI/issues/1977\n // https://github.com/VKCOM/VKUI/issues/3892\n event.preventDefault();\n } else {\n onClickCapture && onClickCapture(event);\n }\n\n didSlide.current = false;\n };\n\n useIsomorphicLayoutEffect(\n function initializeNativeTouchStartEventWithPassiveFalse() {\n const hostEl = hostRef.current;\n if (!hostEl || !isTouchEnabled) {\n return;\n }\n\n const options = { capture: useCapture, passive: false };\n hostEl.addEventListener('touchstart', handlePointerDown, options);\n\n return () => {\n hostEl.removeEventListener('touchstart', handlePointerDown, options);\n };\n },\n [hostRef, isTouchEnabled, useCapture, handlePointerDown],\n );\n\n return (\n <Component\n {...restProps}\n ref={hostRef}\n onDragStart={handleDragStart}\n onClickCapture={handleClickCapture}\n // onEnter\n onPointerEnter={usePointerHover ? handlePointerEnter : undefined}\n onMouseEnter={!usePointerHover ? handlePointerEnter : undefined}\n // onLeave\n onPointerLeave={usePointerHover ? handlePointerLeave : undefined}\n onMouseLeave={!usePointerHover ? handlePointerLeave : undefined}\n // handlePointerDown(onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)\n onMouseDownCapture={useCapture ? handlePointerDown : undefined}\n onMouseDown={!useCapture ? handlePointerDown : undefined}\n />\n );\n};\n\nfunction initGesture(startX: number, startY: number): Gesture {\n return {\n startX,\n startY,\n startT: new Date(),\n duration: 0,\n isPressed: true,\n isY: false,\n isX: false,\n isSlideX: false,\n isSlideY: false,\n isSlide: false,\n clientX: 0,\n clientY: 0,\n shiftX: 0,\n shiftY: 0,\n shiftXAbs: 0,\n shiftYAbs: 0,\n };\n}\n\ntype Handlers = [\n CustomTouchEventHandler | undefined,\n CustomTouchEventHandler | undefined,\n CustomTouchEventHandler | undefined,\n];\n\nfunction dispatchUserHandlers(\n event: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent,\n gesture: Gesture,\n [handler, handlerX, handlerY]: Handlers,\n stopPropagation?: boolean,\n shouldCallDirectionHandlerOnlyIsSlide = true,\n) {\n if (stopPropagation) {\n event.stopPropagation();\n }\n\n const data = {\n ...gesture,\n originalEvent: event as unknown as VKUITouchEvent,\n duration: Date.now() - gesture.startT.getTime(),\n };\n\n if (handler) {\n handler(data);\n }\n\n if (handlerX) {\n if (shouldCallDirectionHandlerOnlyIsSlide) {\n if (gesture.isSlideX) {\n handlerX(data);\n }\n } else {\n handlerX(data);\n }\n }\n\n if (handlerY) {\n if (shouldCallDirectionHandlerOnlyIsSlide) {\n if (gesture.isSlideY) {\n handlerY(data);\n }\n } else {\n handlerY(data);\n }\n }\n}\n"],"names":["React","useExternRef","useStableCallback","getWindow","isHTMLElement","isSVGElement","coordX","coordY","touchEnabled","useIsomorphicLayoutEffect","Touch","onStart","onStartX","onStartY","onMove","onMoveX","onMoveY","onEnter","onLeave","onEnd","onEndX","onEndY","onClickCapture","usePointerHover","slideThreshold","useCapture","Component","getRootRef","noSlideClick","stopPropagation","restProps","hostRef","isTouchEnabled","useState","gestureRef","useRef","didSlide","disposeTargetNativeGestureEvents","cleanupTargetNativeGestureEvents","current","useEffect","isTouchEvent","event","type","startsWith","handleNativePointerUp","gesture","isPressed","dispatchUserHandlers","isSlide","Boolean","handleNativePointerMove","clientX","clientY","shiftX","startX","shiftY","startY","shiftXAbs","Math","abs","shiftYAbs","touches","length","isX","isY","willBeX","willBeY","willBeSlidedX","willBeSlidedY","isSlideX","isSlideY","handlePointerDown","nativeEvent","initGesture","shouldCallDirectionHandlerOnlyIsSlide","eventOptions","capture","passive","target","addEventListener","removeEventListener","doc","currentTarget","document","handlePointerEnter","undefined","handlePointerLeave","handleDragStart","tagName","preventDefault","handleClickCapture","initializeNativeTouchStartEventWithPassiveFalse","hostEl","options","ref","onDragStart","onPointerEnter","onMouseEnter","onPointerLeave","onMouseLeave","onMouseDownCapture","onMouseDown","startT","Date","duration","handler","handlerX","handlerY","data","originalEvent","now","getTime"],"mappings":"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"}
@@ -22,6 +22,9 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
22
22
  }
23
23
  };
24
24
  React.useEffect(()=>cleanupTargetNativeGestureEvents, []);
25
+ const isTouchEvent = (event)=>{
26
+ return event.type.startsWith('touch');
27
+ };
25
28
  /**
26
29
  * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onEnd`/`onEndX`/`onEndY`.
27
30
  */ const handleNativePointerUp = useStableCallback((event)=>{
@@ -36,7 +39,7 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
36
39
  onEndY
37
40
  ], stopPropagation);
38
41
  }
39
- if (isTouchEnabled) {
42
+ if (isTouchEvent(event)) {
40
43
  // https://github.com/VKCOM/VKUI/issues/4414
41
44
  // если тач-устройство и был зафиксирован touchmove,
42
45
  // то событие клика не вызывается
@@ -98,6 +101,10 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
98
101
  }
99
102
  });
100
103
  const handlePointerDown = useStableCallback((event)=>{
104
+ // Если touchstart сэмулировало mousedown, то заканчиваем обработку
105
+ if (gestureRef.current !== null) {
106
+ return;
107
+ }
101
108
  const nativeEvent = 'nativeEvent' in event ? event.nativeEvent : event;
102
109
  gestureRef.current = initGesture(coordX(nativeEvent), coordY(nativeEvent));
103
110
  const shouldCallDirectionHandlerOnlyIsSlide = false;
@@ -112,7 +119,7 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
112
119
  };
113
120
  // FIXME: заменить touch/mouse-события ниже на pointer-события после того, как бразуеры из
114
121
  // .browserslistrc начнут поддерживать его (см. https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#browser_compatibility).
115
- if (isTouchEnabled) {
122
+ if (isTouchEvent(nativeEvent)) {
116
123
  if (isHTMLElement(event.target) || isSVGElement(event.target)) {
117
124
  // Тач-события не всплывают, поэтому навешиваем события на целевой элемент
118
125
  // см. #235, #1968, https://stackoverflow.com/a/45760014
@@ -196,9 +203,9 @@ import { useIsomorphicLayoutEffect } from "../../lib/useIsomorphicLayoutEffect.j
196
203
  // onLeave
197
204
  onPointerLeave: usePointerHover ? handlePointerLeave : undefined,
198
205
  onMouseLeave: !usePointerHover ? handlePointerLeave : undefined,
199
- // handlePointerDown (onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)
200
- onMouseDownCapture: !isTouchEnabled && useCapture ? handlePointerDown : undefined,
201
- onMouseDown: !isTouchEnabled && !useCapture ? handlePointerDown : undefined
206
+ // handlePointerDown(onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)
207
+ onMouseDownCapture: useCapture ? handlePointerDown : undefined,
208
+ onMouseDown: !useCapture ? handlePointerDown : undefined
202
209
  });
203
210
  };
204
211
  function initGesture(startX, startY) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/Touch/Touch.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useExternRef } from '../../hooks/useExternRef';\nimport { useStableCallback } from '../../hooks/useStableCallback';\nimport { getWindow, isHTMLElement, isSVGElement } from '../../lib/dom';\nimport { coordX, coordY, touchEnabled, type VKUITouchEvent } from '../../lib/touch';\nimport { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';\nimport type { HasComponent, HasRootRef } from '../../types';\n\n/**\n * Костыль для правильной работы тайпскрипта.\n */\ntype HTMLorSVGElementWithEvents = {\n /**\n * AddEventListener.\n */\n addEventListener: (<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,\n options?: boolean | AddEventListenerOptions,\n ) => void) &\n (<K extends keyof SVGElementEventMap>(\n type: K,\n listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n /**\n * RemoveEventListener.\n */\n removeEventListener: (<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ) => void) &\n (<K extends keyof SVGElementEventMap>(\n type: K,\n listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ) => void);\n};\n\nexport interface CustomTouchEvent extends Gesture {\n /**\n * Оригинальное событие.\n */\n originalEvent: VKUITouchEvent;\n}\n\nexport type HoverHandler = (outputEvent: MouseEvent) => void;\n\nexport type CustomTouchEventHandler = (event: CustomTouchEvent) => void;\n\nexport interface TouchProps\n extends React.AllHTMLAttributes<HTMLElement>,\n HasRootRef<HTMLElement>,\n HasComponent {\n /**\n * Использовать pointer-events для hover-состояний.\n * Работает на отключенных элементах (disabled inputs).\n */\n usePointerHover?: boolean;\n /**\n * Использовать фазу capture для событий.\n */\n useCapture?: boolean;\n /**\n * Порог расстояния в пикселях для активации свайпа.\n * @default 5\n */\n slideThreshold?: number;\n /**\n * Блокировать click-события после распознавания свайпа.\n */\n noSlideClick?: boolean;\n /**\n * Останавливать всплытие событий.\n */\n stopPropagation?: boolean;\n /**\n * Обработчик входа курсора в область.\n */\n onEnter?: HoverHandler;\n /**\n * Обработчик выхода курсора из области.\n */\n onLeave?: HoverHandler;\n /**\n * Общий обработчик начала взаимодействия.\n */\n onStart?: CustomTouchEventHandler;\n /**\n * Обработчик начала горизонтального перемещения.\n */\n onStartX?: CustomTouchEventHandler;\n /**\n * Обработчик начала вертикального перемещения.\n */\n onStartY?: CustomTouchEventHandler;\n /**\n * Общий обработчик перемещения.\n */\n onMove?: CustomTouchEventHandler;\n /**\n * Обработчик горизонтального перемещения.\n */\n onMoveX?: CustomTouchEventHandler;\n /**\n * Обработчик вертикального перемещения.\n */\n onMoveY?: CustomTouchEventHandler;\n /**\n * Общий обработчик завершения взаимодействия.\n */\n onEnd?: CustomTouchEventHandler;\n /**\n * Обработчик завершения горизонтального свайпа.\n */\n onEndX?: CustomTouchEventHandler;\n /**\n * Обработчик завершения вертикального свайпа.\n */\n onEndY?: CustomTouchEventHandler;\n}\n\nexport interface Gesture {\n /**\n * Начальная X-координата касания.\n */\n startX: number;\n\n /**\n * Начальная Y-координата касания.\n */\n startY: number;\n\n /**\n * Время начала взаимодействия.\n */\n startT: Date;\n\n /**\n * Длительность взаимодействия в миллисекундах.\n */\n duration: number;\n\n /**\n * Флаг активного нажатия.\n */\n isPressed: boolean;\n\n /**\n * Флаг вертикального перемещения.\n */\n isY: boolean;\n\n /**\n * Флаг горизонтального перемещения.\n */\n isX: boolean;\n\n /**\n * Флаг горизонтального свайпа.\n */\n isSlideX: boolean;\n\n /**\n * Флаг вертикального свайпа.\n */\n isSlideY: boolean;\n\n /**\n * Общий флаг свайпа (вертикального или горизонтального).\n */\n isSlide: boolean;\n\n /**\n * Текущая X-координата курсора/касания.\n */\n clientX: number;\n\n /**\n * Текущая Y-координата курсора/касания.\n */\n clientY: number;\n\n /**\n * Смещение по X относительно начальной точки.\n */\n shiftX: number;\n\n /**\n * Смещение по Y относительно начальной точки.\n */\n shiftY: number;\n\n /**\n * Абсолютное смещение по X.\n */\n shiftXAbs: number;\n\n /**\n * Абсолютное смещение по Y.\n */\n shiftYAbs: number;\n}\n\n/**\n * @see https://vkui.io/components/touch\n */\nexport const Touch = ({\n onStart,\n onStartX,\n onStartY,\n onMove,\n onMoveX,\n onMoveY,\n onEnter,\n onLeave,\n onEnd,\n onEndX,\n onEndY,\n onClickCapture,\n usePointerHover,\n slideThreshold = 5,\n useCapture = false,\n Component = 'div',\n getRootRef,\n noSlideClick = false,\n stopPropagation = false,\n ...restProps\n}: TouchProps) => {\n const hostRef = useExternRef(getRootRef);\n const [isTouchEnabled] = React.useState(touchEnabled);\n const gestureRef = React.useRef<Gesture | null>(null);\n const didSlide = React.useRef(false);\n const disposeTargetNativeGestureEvents = React.useRef<VoidFunction | null>(null);\n\n const cleanupTargetNativeGestureEvents = () => {\n gestureRef.current = null;\n if (disposeTargetNativeGestureEvents.current) {\n disposeTargetNativeGestureEvents.current();\n disposeTargetNativeGestureEvents.current = null;\n }\n };\n\n React.useEffect(() => cleanupTargetNativeGestureEvents, []);\n\n /**\n * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onEnd`/`onEndX`/`onEndY`.\n */\n const handleNativePointerUp = useStableCallback((event: MouseEvent | TouchEvent) => {\n const gesture = gestureRef.current;\n\n /* istanbul ignore if: нужно для Typescript */\n if (!gesture) {\n return;\n }\n\n if (gesture.isPressed) {\n dispatchUserHandlers(event, gesture, [onEnd, onEndX, onEndY], stopPropagation);\n }\n\n if (isTouchEnabled) {\n // https://github.com/VKCOM/VKUI/issues/4414\n // если тач-устройство и был зафиксирован touchmove,\n // то событие клика не вызывается\n if (gesture.isSlide) {\n didSlide.current = false;\n }\n // Если это был тач-евент, симулируем отмену hover\n if (onLeave) {\n onLeave(event as MouseEvent);\n }\n } else {\n didSlide.current = Boolean(gesture.isSlide);\n }\n\n cleanupTargetNativeGestureEvents();\n });\n\n /**\n * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onMove`/`onMoveX`/`onMoveY`.\n */\n const handleNativePointerMove = useStableCallback((event: MouseEvent | TouchEvent) => {\n const gesture = gestureRef.current;\n\n /* istanbul ignore if: нужно для Typescript */\n if (!gesture) {\n return;\n }\n\n const clientX = coordX(event);\n const clientY = coordY(event);\n\n // смещения\n const shiftX = clientX - gesture.startX;\n const shiftY = clientY - gesture.startY;\n\n // абсолютные значения смещений\n const shiftXAbs = Math.abs(shiftX);\n const shiftYAbs = Math.abs(shiftY);\n\n // Если определяем мультитач, то прерываем жест\n if ('touches' in event && event.touches.length > 1) {\n return handleNativePointerUp(event);\n }\n\n // если мы ещё не определились\n if (!gesture.isX && !gesture.isY) {\n const willBeX = shiftXAbs >= slideThreshold && shiftXAbs > shiftYAbs;\n const willBeY = shiftYAbs >= slideThreshold && shiftYAbs > shiftXAbs;\n const willBeSlidedX = willBeX && (!!onMoveX || !!onMove);\n const willBeSlidedY = willBeY && (!!onMoveY || !!onMove);\n\n gesture.isY = willBeY;\n gesture.isX = willBeX;\n gesture.isSlideX = willBeSlidedX;\n gesture.isSlideY = willBeSlidedY;\n gesture.isSlide = willBeSlidedX || willBeSlidedY;\n }\n\n if (gesture.isSlide) {\n gesture.clientX = clientX;\n gesture.clientY = clientY;\n gesture.shiftX = shiftX;\n gesture.shiftY = shiftY;\n gesture.shiftXAbs = shiftXAbs;\n gesture.shiftYAbs = shiftYAbs;\n\n dispatchUserHandlers(event, gesture, [onMove, onMoveX, onMoveY], stopPropagation);\n }\n });\n\n const handlePointerDown = useStableCallback(\n (event: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement> | TouchEvent) => {\n const nativeEvent = 'nativeEvent' in event ? event.nativeEvent : event;\n\n gestureRef.current = initGesture(coordX(nativeEvent), coordY(nativeEvent));\n\n const shouldCallDirectionHandlerOnlyIsSlide = false;\n dispatchUserHandlers(\n event,\n gestureRef.current,\n [onStart, onStartX, onStartY],\n stopPropagation,\n shouldCallDirectionHandlerOnlyIsSlide,\n );\n\n const eventOptions = { capture: useCapture, passive: false };\n\n // FIXME: заменить touch/mouse-события ниже на pointer-события после того, как бразуеры из\n // .browserslistrc начнут поддерживать его (см. https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#browser_compatibility).\n if (isTouchEnabled) {\n if (isHTMLElement(event.target) || isSVGElement(event.target)) {\n // Тач-события не всплывают, поэтому навешиваем события на целевой элемент\n // см. #235, #1968, https://stackoverflow.com/a/45760014\n const target: HTMLorSVGElementWithEvents = event.target;\n\n target.addEventListener('touchmove', handleNativePointerMove, eventOptions);\n target.addEventListener('touchend', handleNativePointerUp, eventOptions);\n target.addEventListener('touchcancel', handleNativePointerUp, eventOptions);\n\n disposeTargetNativeGestureEvents.current = () => {\n target.removeEventListener('touchmove', handleNativePointerMove, eventOptions);\n target.removeEventListener('touchend', handleNativePointerUp, eventOptions);\n target.removeEventListener('touchcancel', handleNativePointerUp, eventOptions);\n };\n }\n } else {\n // Используем события на Document, т.к. mouse-события на целевом элементе могут теряться при\n // выходе за границы этого элемента.\n const doc = getWindow(event.currentTarget).document;\n\n doc.addEventListener('mousemove', handleNativePointerMove, eventOptions);\n doc.addEventListener('mouseup', handleNativePointerUp, eventOptions);\n doc.addEventListener('mouseleave', handleNativePointerUp, eventOptions);\n\n disposeTargetNativeGestureEvents.current = () => {\n doc.removeEventListener('mousemove', handleNativePointerMove, eventOptions);\n doc.removeEventListener('mouseup', handleNativePointerUp, eventOptions);\n doc.removeEventListener('mouseleave', handleNativePointerUp, eventOptions);\n };\n }\n },\n );\n\n const handlePointerEnter = onEnter\n ? (event: React.MouseEvent<HTMLElement>) => onEnter(event.nativeEvent)\n : undefined;\n\n const handlePointerLeave = onLeave\n ? (event: React.MouseEvent<HTMLElement>) => onLeave(event.nativeEvent)\n : undefined;\n\n /**\n * Отменяет нативное браузерное поведение для вложенных ссылок и изображений.\n */\n const handleDragStart = (event: React.DragEvent<HTMLElement>) => {\n const target = event.target as HTMLElement;\n if (target.tagName === 'A' || target.tagName === 'IMG') {\n event.preventDefault();\n }\n };\n\n /**\n * Отменяет переход по вложенной ссылке, если был зафиксирован свайп.\n */\n const handleClickCapture: typeof onClickCapture = (event) => {\n if (!didSlide.current) {\n return onClickCapture && onClickCapture(event);\n }\n\n if (noSlideClick) {\n event.stopPropagation();\n\n // https://github.com/VKCOM/VKUI/issues/1977\n // https://github.com/VKCOM/VKUI/issues/3892\n event.preventDefault();\n } else {\n onClickCapture && onClickCapture(event);\n }\n\n didSlide.current = false;\n };\n\n useIsomorphicLayoutEffect(\n function initializeNativeTouchStartEventWithPassiveFalse() {\n const hostEl = hostRef.current;\n if (!hostEl || !isTouchEnabled) {\n return;\n }\n\n const options = { capture: useCapture, passive: false };\n hostEl.addEventListener('touchstart', handlePointerDown, options);\n\n return () => {\n hostEl.removeEventListener('touchstart', handlePointerDown, options);\n };\n },\n [hostRef, isTouchEnabled, useCapture, handlePointerDown],\n );\n\n return (\n <Component\n {...restProps}\n ref={hostRef}\n onDragStart={handleDragStart}\n onClickCapture={handleClickCapture}\n // onEnter\n onPointerEnter={usePointerHover ? handlePointerEnter : undefined}\n onMouseEnter={!usePointerHover ? handlePointerEnter : undefined}\n // onLeave\n onPointerLeave={usePointerHover ? handlePointerLeave : undefined}\n onMouseLeave={!usePointerHover ? handlePointerLeave : undefined}\n // handlePointerDown (onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)\n onMouseDownCapture={!isTouchEnabled && useCapture ? handlePointerDown : undefined}\n onMouseDown={!isTouchEnabled && !useCapture ? handlePointerDown : undefined}\n />\n );\n};\n\nfunction initGesture(startX: number, startY: number): Gesture {\n return {\n startX,\n startY,\n startT: new Date(),\n duration: 0,\n isPressed: true,\n isY: false,\n isX: false,\n isSlideX: false,\n isSlideY: false,\n isSlide: false,\n clientX: 0,\n clientY: 0,\n shiftX: 0,\n shiftY: 0,\n shiftXAbs: 0,\n shiftYAbs: 0,\n };\n}\n\ntype Handlers = [\n CustomTouchEventHandler | undefined,\n CustomTouchEventHandler | undefined,\n CustomTouchEventHandler | undefined,\n];\n\nfunction dispatchUserHandlers(\n event: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent,\n gesture: Gesture,\n [handler, handlerX, handlerY]: Handlers,\n stopPropagation?: boolean,\n shouldCallDirectionHandlerOnlyIsSlide = true,\n) {\n if (stopPropagation) {\n event.stopPropagation();\n }\n\n const data = {\n ...gesture,\n originalEvent: event as unknown as VKUITouchEvent,\n duration: Date.now() - gesture.startT.getTime(),\n };\n\n if (handler) {\n handler(data);\n }\n\n if (handlerX) {\n if (shouldCallDirectionHandlerOnlyIsSlide) {\n if (gesture.isSlideX) {\n handlerX(data);\n }\n } else {\n handlerX(data);\n }\n }\n\n if (handlerY) {\n if (shouldCallDirectionHandlerOnlyIsSlide) {\n if (gesture.isSlideY) {\n handlerY(data);\n }\n } else {\n handlerY(data);\n }\n }\n}\n"],"names":["React","useExternRef","useStableCallback","getWindow","isHTMLElement","isSVGElement","coordX","coordY","touchEnabled","useIsomorphicLayoutEffect","Touch","onStart","onStartX","onStartY","onMove","onMoveX","onMoveY","onEnter","onLeave","onEnd","onEndX","onEndY","onClickCapture","usePointerHover","slideThreshold","useCapture","Component","getRootRef","noSlideClick","stopPropagation","restProps","hostRef","isTouchEnabled","useState","gestureRef","useRef","didSlide","disposeTargetNativeGestureEvents","cleanupTargetNativeGestureEvents","current","useEffect","handleNativePointerUp","event","gesture","isPressed","dispatchUserHandlers","isSlide","Boolean","handleNativePointerMove","clientX","clientY","shiftX","startX","shiftY","startY","shiftXAbs","Math","abs","shiftYAbs","touches","length","isX","isY","willBeX","willBeY","willBeSlidedX","willBeSlidedY","isSlideX","isSlideY","handlePointerDown","nativeEvent","initGesture","shouldCallDirectionHandlerOnlyIsSlide","eventOptions","capture","passive","target","addEventListener","removeEventListener","doc","currentTarget","document","handlePointerEnter","undefined","handlePointerLeave","handleDragStart","tagName","preventDefault","handleClickCapture","initializeNativeTouchStartEventWithPassiveFalse","hostEl","options","ref","onDragStart","onPointerEnter","onMouseEnter","onPointerLeave","onMouseLeave","onMouseDownCapture","onMouseDown","startT","Date","duration","handler","handlerX","handlerY","data","originalEvent","now","getTime"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/components/Touch/Touch.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { useExternRef } from '../../hooks/useExternRef';\nimport { useStableCallback } from '../../hooks/useStableCallback';\nimport { getWindow, isHTMLElement, isSVGElement } from '../../lib/dom';\nimport { coordX, coordY, touchEnabled, type VKUITouchEvent } from '../../lib/touch';\nimport { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';\nimport type { HasComponent, HasRootRef } from '../../types';\n\n/**\n * Костыль для правильной работы тайпскрипта.\n */\ntype HTMLorSVGElementWithEvents = {\n /**\n * AddEventListener.\n */\n addEventListener: (<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,\n options?: boolean | AddEventListenerOptions,\n ) => void) &\n (<K extends keyof SVGElementEventMap>(\n type: K,\n listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n /**\n * RemoveEventListener.\n */\n removeEventListener: (<K extends keyof HTMLElementEventMap>(\n type: K,\n listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ) => void) &\n (<K extends keyof SVGElementEventMap>(\n type: K,\n listener: (this: SVGElement, ev: SVGElementEventMap[K]) => any,\n options?: boolean | EventListenerOptions,\n ) => void);\n};\n\nexport interface CustomTouchEvent extends Gesture {\n /**\n * Оригинальное событие.\n */\n originalEvent: VKUITouchEvent;\n}\n\nexport type HoverHandler = (outputEvent: MouseEvent) => void;\n\nexport type CustomTouchEventHandler = (event: CustomTouchEvent) => void;\n\nexport interface TouchProps\n extends React.AllHTMLAttributes<HTMLElement>,\n HasRootRef<HTMLElement>,\n HasComponent {\n /**\n * Использовать pointer-events для hover-состояний.\n * Работает на отключенных элементах (disabled inputs).\n */\n usePointerHover?: boolean;\n /**\n * Использовать фазу capture для событий.\n */\n useCapture?: boolean;\n /**\n * Порог расстояния в пикселях для активации свайпа.\n * @default 5\n */\n slideThreshold?: number;\n /**\n * Блокировать click-события после распознавания свайпа.\n */\n noSlideClick?: boolean;\n /**\n * Останавливать всплытие событий.\n */\n stopPropagation?: boolean;\n /**\n * Обработчик входа курсора в область.\n */\n onEnter?: HoverHandler;\n /**\n * Обработчик выхода курсора из области.\n */\n onLeave?: HoverHandler;\n /**\n * Общий обработчик начала взаимодействия.\n */\n onStart?: CustomTouchEventHandler;\n /**\n * Обработчик начала горизонтального перемещения.\n */\n onStartX?: CustomTouchEventHandler;\n /**\n * Обработчик начала вертикального перемещения.\n */\n onStartY?: CustomTouchEventHandler;\n /**\n * Общий обработчик перемещения.\n */\n onMove?: CustomTouchEventHandler;\n /**\n * Обработчик горизонтального перемещения.\n */\n onMoveX?: CustomTouchEventHandler;\n /**\n * Обработчик вертикального перемещения.\n */\n onMoveY?: CustomTouchEventHandler;\n /**\n * Общий обработчик завершения взаимодействия.\n */\n onEnd?: CustomTouchEventHandler;\n /**\n * Обработчик завершения горизонтального свайпа.\n */\n onEndX?: CustomTouchEventHandler;\n /**\n * Обработчик завершения вертикального свайпа.\n */\n onEndY?: CustomTouchEventHandler;\n}\n\nexport interface Gesture {\n /**\n * Начальная X-координата касания.\n */\n startX: number;\n\n /**\n * Начальная Y-координата касания.\n */\n startY: number;\n\n /**\n * Время начала взаимодействия.\n */\n startT: Date;\n\n /**\n * Длительность взаимодействия в миллисекундах.\n */\n duration: number;\n\n /**\n * Флаг активного нажатия.\n */\n isPressed: boolean;\n\n /**\n * Флаг вертикального перемещения.\n */\n isY: boolean;\n\n /**\n * Флаг горизонтального перемещения.\n */\n isX: boolean;\n\n /**\n * Флаг горизонтального свайпа.\n */\n isSlideX: boolean;\n\n /**\n * Флаг вертикального свайпа.\n */\n isSlideY: boolean;\n\n /**\n * Общий флаг свайпа (вертикального или горизонтального).\n */\n isSlide: boolean;\n\n /**\n * Текущая X-координата курсора/касания.\n */\n clientX: number;\n\n /**\n * Текущая Y-координата курсора/касания.\n */\n clientY: number;\n\n /**\n * Смещение по X относительно начальной точки.\n */\n shiftX: number;\n\n /**\n * Смещение по Y относительно начальной точки.\n */\n shiftY: number;\n\n /**\n * Абсолютное смещение по X.\n */\n shiftXAbs: number;\n\n /**\n * Абсолютное смещение по Y.\n */\n shiftYAbs: number;\n}\n\n/**\n * @see https://vkui.io/components/touch\n */\nexport const Touch = ({\n onStart,\n onStartX,\n onStartY,\n onMove,\n onMoveX,\n onMoveY,\n onEnter,\n onLeave,\n onEnd,\n onEndX,\n onEndY,\n onClickCapture,\n usePointerHover,\n slideThreshold = 5,\n useCapture = false,\n Component = 'div',\n getRootRef,\n noSlideClick = false,\n stopPropagation = false,\n ...restProps\n}: TouchProps) => {\n const hostRef = useExternRef(getRootRef);\n const [isTouchEnabled] = React.useState(touchEnabled);\n const gestureRef = React.useRef<Gesture | null>(null);\n const didSlide = React.useRef(false);\n const disposeTargetNativeGestureEvents = React.useRef<VoidFunction | null>(null);\n\n const cleanupTargetNativeGestureEvents = () => {\n gestureRef.current = null;\n if (disposeTargetNativeGestureEvents.current) {\n disposeTargetNativeGestureEvents.current();\n disposeTargetNativeGestureEvents.current = null;\n }\n };\n\n React.useEffect(() => cleanupTargetNativeGestureEvents, []);\n\n const isTouchEvent = (event: MouseEvent | TouchEvent) => {\n return event.type.startsWith('touch');\n };\n\n /**\n * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onEnd`/`onEndX`/`onEndY`.\n */\n const handleNativePointerUp = useStableCallback((event: MouseEvent | TouchEvent) => {\n const gesture = gestureRef.current;\n\n /* istanbul ignore if: нужно для Typescript */\n if (!gesture) {\n return;\n }\n\n if (gesture.isPressed) {\n dispatchUserHandlers(event, gesture, [onEnd, onEndX, onEndY], stopPropagation);\n }\n\n if (isTouchEvent(event)) {\n // https://github.com/VKCOM/VKUI/issues/4414\n // если тач-устройство и был зафиксирован touchmove,\n // то событие клика не вызывается\n if (gesture.isSlide) {\n didSlide.current = false;\n }\n // Если это был тач-евент, симулируем отмену hover\n if (onLeave) {\n onLeave(event as MouseEvent);\n }\n } else {\n didSlide.current = Boolean(gesture.isSlide);\n }\n\n cleanupTargetNativeGestureEvents();\n });\n\n /**\n * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onMove`/`onMoveX`/`onMoveY`.\n */\n const handleNativePointerMove = useStableCallback((event: MouseEvent | TouchEvent) => {\n const gesture = gestureRef.current;\n\n /* istanbul ignore if: нужно для Typescript */\n if (!gesture) {\n return;\n }\n\n const clientX = coordX(event);\n const clientY = coordY(event);\n\n // смещения\n const shiftX = clientX - gesture.startX;\n const shiftY = clientY - gesture.startY;\n\n // абсолютные значения смещений\n const shiftXAbs = Math.abs(shiftX);\n const shiftYAbs = Math.abs(shiftY);\n\n // Если определяем мультитач, то прерываем жест\n if ('touches' in event && event.touches.length > 1) {\n return handleNativePointerUp(event);\n }\n\n // если мы ещё не определились\n if (!gesture.isX && !gesture.isY) {\n const willBeX = shiftXAbs >= slideThreshold && shiftXAbs > shiftYAbs;\n const willBeY = shiftYAbs >= slideThreshold && shiftYAbs > shiftXAbs;\n const willBeSlidedX = willBeX && (!!onMoveX || !!onMove);\n const willBeSlidedY = willBeY && (!!onMoveY || !!onMove);\n\n gesture.isY = willBeY;\n gesture.isX = willBeX;\n gesture.isSlideX = willBeSlidedX;\n gesture.isSlideY = willBeSlidedY;\n gesture.isSlide = willBeSlidedX || willBeSlidedY;\n }\n\n if (gesture.isSlide) {\n gesture.clientX = clientX;\n gesture.clientY = clientY;\n gesture.shiftX = shiftX;\n gesture.shiftY = shiftY;\n gesture.shiftXAbs = shiftXAbs;\n gesture.shiftYAbs = shiftYAbs;\n\n dispatchUserHandlers(event, gesture, [onMove, onMoveX, onMoveY], stopPropagation);\n }\n });\n\n const handlePointerDown = useStableCallback(\n (event: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement> | TouchEvent) => {\n // Если touchstart сэмулировало mousedown, то заканчиваем обработку\n if (gestureRef.current !== null) {\n return;\n }\n\n const nativeEvent = 'nativeEvent' in event ? event.nativeEvent : event;\n\n gestureRef.current = initGesture(coordX(nativeEvent), coordY(nativeEvent));\n\n const shouldCallDirectionHandlerOnlyIsSlide = false;\n dispatchUserHandlers(\n event,\n gestureRef.current,\n [onStart, onStartX, onStartY],\n stopPropagation,\n shouldCallDirectionHandlerOnlyIsSlide,\n );\n\n const eventOptions = { capture: useCapture, passive: false };\n\n // FIXME: заменить touch/mouse-события ниже на pointer-события после того, как бразуеры из\n // .browserslistrc начнут поддерживать его (см. https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#browser_compatibility).\n if (isTouchEvent(nativeEvent)) {\n if (isHTMLElement(event.target) || isSVGElement(event.target)) {\n // Тач-события не всплывают, поэтому навешиваем события на целевой элемент\n // см. #235, #1968, https://stackoverflow.com/a/45760014\n const target: HTMLorSVGElementWithEvents = event.target;\n\n target.addEventListener('touchmove', handleNativePointerMove, eventOptions);\n target.addEventListener('touchend', handleNativePointerUp, eventOptions);\n target.addEventListener('touchcancel', handleNativePointerUp, eventOptions);\n\n disposeTargetNativeGestureEvents.current = () => {\n target.removeEventListener('touchmove', handleNativePointerMove, eventOptions);\n target.removeEventListener('touchend', handleNativePointerUp, eventOptions);\n target.removeEventListener('touchcancel', handleNativePointerUp, eventOptions);\n };\n }\n } else {\n // Используем события на Document, т.к. mouse-события на целевом элементе могут теряться при\n // выходе за границы этого элемента.\n const doc = getWindow(event.currentTarget).document;\n\n doc.addEventListener('mousemove', handleNativePointerMove, eventOptions);\n doc.addEventListener('mouseup', handleNativePointerUp, eventOptions);\n doc.addEventListener('mouseleave', handleNativePointerUp, eventOptions);\n\n disposeTargetNativeGestureEvents.current = () => {\n doc.removeEventListener('mousemove', handleNativePointerMove, eventOptions);\n doc.removeEventListener('mouseup', handleNativePointerUp, eventOptions);\n doc.removeEventListener('mouseleave', handleNativePointerUp, eventOptions);\n };\n }\n },\n );\n\n const handlePointerEnter = onEnter\n ? (event: React.MouseEvent<HTMLElement>) => onEnter(event.nativeEvent)\n : undefined;\n\n const handlePointerLeave = onLeave\n ? (event: React.MouseEvent<HTMLElement>) => onLeave(event.nativeEvent)\n : undefined;\n\n /**\n * Отменяет нативное браузерное поведение для вложенных ссылок и изображений.\n */\n const handleDragStart = (event: React.DragEvent<HTMLElement>) => {\n const target = event.target as HTMLElement;\n if (target.tagName === 'A' || target.tagName === 'IMG') {\n event.preventDefault();\n }\n };\n\n /**\n * Отменяет переход по вложенной ссылке, если был зафиксирован свайп.\n */\n const handleClickCapture: typeof onClickCapture = (event) => {\n if (!didSlide.current) {\n return onClickCapture && onClickCapture(event);\n }\n\n if (noSlideClick) {\n event.stopPropagation();\n\n // https://github.com/VKCOM/VKUI/issues/1977\n // https://github.com/VKCOM/VKUI/issues/3892\n event.preventDefault();\n } else {\n onClickCapture && onClickCapture(event);\n }\n\n didSlide.current = false;\n };\n\n useIsomorphicLayoutEffect(\n function initializeNativeTouchStartEventWithPassiveFalse() {\n const hostEl = hostRef.current;\n if (!hostEl || !isTouchEnabled) {\n return;\n }\n\n const options = { capture: useCapture, passive: false };\n hostEl.addEventListener('touchstart', handlePointerDown, options);\n\n return () => {\n hostEl.removeEventListener('touchstart', handlePointerDown, options);\n };\n },\n [hostRef, isTouchEnabled, useCapture, handlePointerDown],\n );\n\n return (\n <Component\n {...restProps}\n ref={hostRef}\n onDragStart={handleDragStart}\n onClickCapture={handleClickCapture}\n // onEnter\n onPointerEnter={usePointerHover ? handlePointerEnter : undefined}\n onMouseEnter={!usePointerHover ? handlePointerEnter : undefined}\n // onLeave\n onPointerLeave={usePointerHover ? handlePointerLeave : undefined}\n onMouseLeave={!usePointerHover ? handlePointerLeave : undefined}\n // handlePointerDown(onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)\n onMouseDownCapture={useCapture ? handlePointerDown : undefined}\n onMouseDown={!useCapture ? handlePointerDown : undefined}\n />\n );\n};\n\nfunction initGesture(startX: number, startY: number): Gesture {\n return {\n startX,\n startY,\n startT: new Date(),\n duration: 0,\n isPressed: true,\n isY: false,\n isX: false,\n isSlideX: false,\n isSlideY: false,\n isSlide: false,\n clientX: 0,\n clientY: 0,\n shiftX: 0,\n shiftY: 0,\n shiftXAbs: 0,\n shiftYAbs: 0,\n };\n}\n\ntype Handlers = [\n CustomTouchEventHandler | undefined,\n CustomTouchEventHandler | undefined,\n CustomTouchEventHandler | undefined,\n];\n\nfunction dispatchUserHandlers(\n event: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent,\n gesture: Gesture,\n [handler, handlerX, handlerY]: Handlers,\n stopPropagation?: boolean,\n shouldCallDirectionHandlerOnlyIsSlide = true,\n) {\n if (stopPropagation) {\n event.stopPropagation();\n }\n\n const data = {\n ...gesture,\n originalEvent: event as unknown as VKUITouchEvent,\n duration: Date.now() - gesture.startT.getTime(),\n };\n\n if (handler) {\n handler(data);\n }\n\n if (handlerX) {\n if (shouldCallDirectionHandlerOnlyIsSlide) {\n if (gesture.isSlideX) {\n handlerX(data);\n }\n } else {\n handlerX(data);\n }\n }\n\n if (handlerY) {\n if (shouldCallDirectionHandlerOnlyIsSlide) {\n if (gesture.isSlideY) {\n handlerY(data);\n }\n } else {\n handlerY(data);\n }\n }\n}\n"],"names":["React","useExternRef","useStableCallback","getWindow","isHTMLElement","isSVGElement","coordX","coordY","touchEnabled","useIsomorphicLayoutEffect","Touch","onStart","onStartX","onStartY","onMove","onMoveX","onMoveY","onEnter","onLeave","onEnd","onEndX","onEndY","onClickCapture","usePointerHover","slideThreshold","useCapture","Component","getRootRef","noSlideClick","stopPropagation","restProps","hostRef","isTouchEnabled","useState","gestureRef","useRef","didSlide","disposeTargetNativeGestureEvents","cleanupTargetNativeGestureEvents","current","useEffect","isTouchEvent","event","type","startsWith","handleNativePointerUp","gesture","isPressed","dispatchUserHandlers","isSlide","Boolean","handleNativePointerMove","clientX","clientY","shiftX","startX","shiftY","startY","shiftXAbs","Math","abs","shiftYAbs","touches","length","isX","isY","willBeX","willBeY","willBeSlidedX","willBeSlidedY","isSlideX","isSlideY","handlePointerDown","nativeEvent","initGesture","shouldCallDirectionHandlerOnlyIsSlide","eventOptions","capture","passive","target","addEventListener","removeEventListener","doc","currentTarget","document","handlePointerEnter","undefined","handlePointerLeave","handleDragStart","tagName","preventDefault","handleClickCapture","initializeNativeTouchStartEventWithPassiveFalse","hostEl","options","ref","onDragStart","onPointerEnter","onMouseEnter","onPointerLeave","onMouseLeave","onMouseDownCapture","onMouseDown","startT","Date","duration","handler","handlerX","handlerY","data","originalEvent","now","getTime"],"mappings":"AAAA;;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,YAAY,QAAQ,8BAA2B;AACxD,SAASC,iBAAiB,QAAQ,mCAAgC;AAClE,SAASC,SAAS,EAAEC,aAAa,EAAEC,YAAY,QAAQ,mBAAgB;AACvE,SAASC,MAAM,EAAEC,MAAM,EAAEC,YAAY,QAA6B,2BAAkB;AACpF,SAASC,yBAAyB,QAAQ,yCAAsC;AAwMhF;;CAEC,GACD,OAAO,MAAMC,QAAQ,CAAC,EACpBC,OAAO,EACPC,QAAQ,EACRC,QAAQ,EACRC,MAAM,EACNC,OAAO,EACPC,OAAO,EACPC,OAAO,EACPC,OAAO,EACPC,KAAK,EACLC,MAAM,EACNC,MAAM,EACNC,cAAc,EACdC,eAAe,EACfC,iBAAiB,CAAC,EAClBC,aAAa,KAAK,EAClBC,YAAY,KAAK,EACjBC,UAAU,EACVC,eAAe,KAAK,EACpBC,kBAAkB,KAAK,EACvB,GAAGC,WACQ;IACX,MAAMC,UAAU9B,aAAa0B;IAC7B,MAAM,CAACK,eAAe,GAAGhC,MAAMiC,QAAQ,CAACzB;IACxC,MAAM0B,aAAalC,MAAMmC,MAAM,CAAiB;IAChD,MAAMC,WAAWpC,MAAMmC,MAAM,CAAC;IAC9B,MAAME,mCAAmCrC,MAAMmC,MAAM,CAAsB;IAE3E,MAAMG,mCAAmC;QACvCJ,WAAWK,OAAO,GAAG;QACrB,IAAIF,iCAAiCE,OAAO,EAAE;YAC5CF,iCAAiCE,OAAO;YACxCF,iCAAiCE,OAAO,GAAG;QAC7C;IACF;IAEAvC,MAAMwC,SAAS,CAAC,IAAMF,kCAAkC,EAAE;IAE1D,MAAMG,eAAe,CAACC;QACpB,OAAOA,MAAMC,IAAI,CAACC,UAAU,CAAC;IAC/B;IAEA;;GAEC,GACD,MAAMC,wBAAwB3C,kBAAkB,CAACwC;QAC/C,MAAMI,UAAUZ,WAAWK,OAAO;QAElC,4CAA4C,GAC5C,IAAI,CAACO,SAAS;YACZ;QACF;QAEA,IAAIA,QAAQC,SAAS,EAAE;YACrBC,qBAAqBN,OAAOI,SAAS;gBAAC3B;gBAAOC;gBAAQC;aAAO,EAAEQ;QAChE;QAEA,IAAIY,aAAaC,QAAQ;YACvB,4CAA4C;YAC5C,oDAAoD;YACpD,iCAAiC;YACjC,IAAII,QAAQG,OAAO,EAAE;gBACnBb,SAASG,OAAO,GAAG;YACrB;YACA,kDAAkD;YAClD,IAAIrB,SAAS;gBACXA,QAAQwB;YACV;QACF,OAAO;YACLN,SAASG,OAAO,GAAGW,QAAQJ,QAAQG,OAAO;QAC5C;QAEAX;IACF;IAEA;;GAEC,GACD,MAAMa,0BAA0BjD,kBAAkB,CAACwC;QACjD,MAAMI,UAAUZ,WAAWK,OAAO;QAElC,4CAA4C,GAC5C,IAAI,CAACO,SAAS;YACZ;QACF;QAEA,MAAMM,UAAU9C,OAAOoC;QACvB,MAAMW,UAAU9C,OAAOmC;QAEvB,WAAW;QACX,MAAMY,SAASF,UAAUN,QAAQS,MAAM;QACvC,MAAMC,SAASH,UAAUP,QAAQW,MAAM;QAEvC,+BAA+B;QAC/B,MAAMC,YAAYC,KAAKC,GAAG,CAACN;QAC3B,MAAMO,YAAYF,KAAKC,GAAG,CAACJ;QAE3B,+CAA+C;QAC/C,IAAI,aAAad,SAASA,MAAMoB,OAAO,CAACC,MAAM,GAAG,GAAG;YAClD,OAAOlB,sBAAsBH;QAC/B;QAEA,8BAA8B;QAC9B,IAAI,CAACI,QAAQkB,GAAG,IAAI,CAAClB,QAAQmB,GAAG,EAAE;YAChC,MAAMC,UAAUR,aAAalC,kBAAkBkC,YAAYG;YAC3D,MAAMM,UAAUN,aAAarC,kBAAkBqC,YAAYH;YAC3D,MAAMU,gBAAgBF,WAAY,CAAA,CAAC,CAACnD,WAAW,CAAC,CAACD,MAAK;YACtD,MAAMuD,gBAAgBF,WAAY,CAAA,CAAC,CAACnD,WAAW,CAAC,CAACF,MAAK;YAEtDgC,QAAQmB,GAAG,GAAGE;YACdrB,QAAQkB,GAAG,GAAGE;YACdpB,QAAQwB,QAAQ,GAAGF;YACnBtB,QAAQyB,QAAQ,GAAGF;YACnBvB,QAAQG,OAAO,GAAGmB,iBAAiBC;QACrC;QAEA,IAAIvB,QAAQG,OAAO,EAAE;YACnBH,QAAQM,OAAO,GAAGA;YAClBN,QAAQO,OAAO,GAAGA;YAClBP,QAAQQ,MAAM,GAAGA;YACjBR,QAAQU,MAAM,GAAGA;YACjBV,QAAQY,SAAS,GAAGA;YACpBZ,QAAQe,SAAS,GAAGA;YAEpBb,qBAAqBN,OAAOI,SAAS;gBAAChC;gBAAQC;gBAASC;aAAQ,EAAEa;QACnE;IACF;IAEA,MAAM2C,oBAAoBtE,kBACxB,CAACwC;QACC,mEAAmE;QACnE,IAAIR,WAAWK,OAAO,KAAK,MAAM;YAC/B;QACF;QAEA,MAAMkC,cAAc,iBAAiB/B,QAAQA,MAAM+B,WAAW,GAAG/B;QAEjER,WAAWK,OAAO,GAAGmC,YAAYpE,OAAOmE,cAAclE,OAAOkE;QAE7D,MAAME,wCAAwC;QAC9C3B,qBACEN,OACAR,WAAWK,OAAO,EAClB;YAAC5B;YAASC;YAAUC;SAAS,EAC7BgB,iBACA8C;QAGF,MAAMC,eAAe;YAAEC,SAASpD;YAAYqD,SAAS;QAAM;QAE3D,0FAA0F;QAC1F,uIAAuI;QACvI,IAAIrC,aAAagC,cAAc;YAC7B,IAAIrE,cAAcsC,MAAMqC,MAAM,KAAK1E,aAAaqC,MAAMqC,MAAM,GAAG;gBAC7D,0EAA0E;gBAC1E,wDAAwD;gBACxD,MAAMA,SAAqCrC,MAAMqC,MAAM;gBAEvDA,OAAOC,gBAAgB,CAAC,aAAa7B,yBAAyByB;gBAC9DG,OAAOC,gBAAgB,CAAC,YAAYnC,uBAAuB+B;gBAC3DG,OAAOC,gBAAgB,CAAC,eAAenC,uBAAuB+B;gBAE9DvC,iCAAiCE,OAAO,GAAG;oBACzCwC,OAAOE,mBAAmB,CAAC,aAAa9B,yBAAyByB;oBACjEG,OAAOE,mBAAmB,CAAC,YAAYpC,uBAAuB+B;oBAC9DG,OAAOE,mBAAmB,CAAC,eAAepC,uBAAuB+B;gBACnE;YACF;QACF,OAAO;YACL,4FAA4F;YAC5F,oCAAoC;YACpC,MAAMM,MAAM/E,UAAUuC,MAAMyC,aAAa,EAAEC,QAAQ;YAEnDF,IAAIF,gBAAgB,CAAC,aAAa7B,yBAAyByB;YAC3DM,IAAIF,gBAAgB,CAAC,WAAWnC,uBAAuB+B;YACvDM,IAAIF,gBAAgB,CAAC,cAAcnC,uBAAuB+B;YAE1DvC,iCAAiCE,OAAO,GAAG;gBACzC2C,IAAID,mBAAmB,CAAC,aAAa9B,yBAAyByB;gBAC9DM,IAAID,mBAAmB,CAAC,WAAWpC,uBAAuB+B;gBAC1DM,IAAID,mBAAmB,CAAC,cAAcpC,uBAAuB+B;YAC/D;QACF;IACF;IAGF,MAAMS,qBAAqBpE,UACvB,CAACyB,QAAyCzB,QAAQyB,MAAM+B,WAAW,IACnEa;IAEJ,MAAMC,qBAAqBrE,UACvB,CAACwB,QAAyCxB,QAAQwB,MAAM+B,WAAW,IACnEa;IAEJ;;GAEC,GACD,MAAME,kBAAkB,CAAC9C;QACvB,MAAMqC,SAASrC,MAAMqC,MAAM;QAC3B,IAAIA,OAAOU,OAAO,KAAK,OAAOV,OAAOU,OAAO,KAAK,OAAO;YACtD/C,MAAMgD,cAAc;QACtB;IACF;IAEA;;GAEC,GACD,MAAMC,qBAA4C,CAACjD;QACjD,IAAI,CAACN,SAASG,OAAO,EAAE;YACrB,OAAOjB,kBAAkBA,eAAeoB;QAC1C;QAEA,IAAId,cAAc;YAChBc,MAAMb,eAAe;YAErB,4CAA4C;YAC5C,4CAA4C;YAC5Ca,MAAMgD,cAAc;QACtB,OAAO;YACLpE,kBAAkBA,eAAeoB;QACnC;QAEAN,SAASG,OAAO,GAAG;IACrB;IAEA9B,0BACE,SAASmF;QACP,MAAMC,SAAS9D,QAAQQ,OAAO;QAC9B,IAAI,CAACsD,UAAU,CAAC7D,gBAAgB;YAC9B;QACF;QAEA,MAAM8D,UAAU;YAAEjB,SAASpD;YAAYqD,SAAS;QAAM;QACtDe,OAAOb,gBAAgB,CAAC,cAAcR,mBAAmBsB;QAEzD,OAAO;YACLD,OAAOZ,mBAAmB,CAAC,cAAcT,mBAAmBsB;QAC9D;IACF,GACA;QAAC/D;QAASC;QAAgBP;QAAY+C;KAAkB;IAG1D,qBACE,KAAC9C;QACE,GAAGI,SAAS;QACbiE,KAAKhE;QACLiE,aAAaR;QACblE,gBAAgBqE;QAChB,UAAU;QACVM,gBAAgB1E,kBAAkB8D,qBAAqBC;QACvDY,cAAc,CAAC3E,kBAAkB8D,qBAAqBC;QACtD,UAAU;QACVa,gBAAgB5E,kBAAkBgE,qBAAqBD;QACvDc,cAAc,CAAC7E,kBAAkBgE,qBAAqBD;QACtD,iHAAiH;QACjHe,oBAAoB5E,aAAa+C,oBAAoBc;QACrDgB,aAAa,CAAC7E,aAAa+C,oBAAoBc;;AAGrD,EAAE;AAEF,SAASZ,YAAYnB,MAAc,EAAEE,MAAc;IACjD,OAAO;QACLF;QACAE;QACA8C,QAAQ,IAAIC;QACZC,UAAU;QACV1D,WAAW;QACXkB,KAAK;QACLD,KAAK;QACLM,UAAU;QACVC,UAAU;QACVtB,SAAS;QACTG,SAAS;QACTC,SAAS;QACTC,QAAQ;QACRE,QAAQ;QACRE,WAAW;QACXG,WAAW;IACb;AACF;AAQA,SAASb,qBACPN,KAAoE,EACpEI,OAAgB,EAChB,CAAC4D,SAASC,UAAUC,SAAmB,EACvC/E,eAAyB,EACzB8C,wCAAwC,IAAI;IAE5C,IAAI9C,iBAAiB;QACnBa,MAAMb,eAAe;IACvB;IAEA,MAAMgF,OAAO;QACX,GAAG/D,OAAO;QACVgE,eAAepE;QACf+D,UAAUD,KAAKO,GAAG,KAAKjE,QAAQyD,MAAM,CAACS,OAAO;IAC/C;IAEA,IAAIN,SAAS;QACXA,QAAQG;IACV;IAEA,IAAIF,UAAU;QACZ,IAAIhC,uCAAuC;YACzC,IAAI7B,QAAQwB,QAAQ,EAAE;gBACpBqC,SAASE;YACX;QACF,OAAO;YACLF,SAASE;QACX;IACF;IAEA,IAAID,UAAU;QACZ,IAAIjC,uCAAuC;YACzC,IAAI7B,QAAQyB,QAAQ,EAAE;gBACpBqC,SAASC;YACX;QACF,OAAO;YACLD,SAASC;QACX;IACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "type": "module",
3
- "version": "7.6.2",
3
+ "version": "7.6.3",
4
4
  "name": "@vkontakte/vkui",
5
5
  "description": "VKUI library",
6
6
  "module": "./dist/index.js",
@@ -246,6 +246,10 @@ export const Touch = ({
246
246
 
247
247
  React.useEffect(() => cleanupTargetNativeGestureEvents, []);
248
248
 
249
+ const isTouchEvent = (event: MouseEvent | TouchEvent) => {
250
+ return event.type.startsWith('touch');
251
+ };
252
+
249
253
  /**
250
254
  * Note: используем `useStableCallback()`, чтобы не терялась область видимости `onEnd`/`onEndX`/`onEndY`.
251
255
  */
@@ -261,7 +265,7 @@ export const Touch = ({
261
265
  dispatchUserHandlers(event, gesture, [onEnd, onEndX, onEndY], stopPropagation);
262
266
  }
263
267
 
264
- if (isTouchEnabled) {
268
+ if (isTouchEvent(event)) {
265
269
  // https://github.com/VKCOM/VKUI/issues/4414
266
270
  // если тач-устройство и был зафиксирован touchmove,
267
271
  // то событие клика не вызывается
@@ -334,6 +338,11 @@ export const Touch = ({
334
338
 
335
339
  const handlePointerDown = useStableCallback(
336
340
  (event: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement> | TouchEvent) => {
341
+ // Если touchstart сэмулировало mousedown, то заканчиваем обработку
342
+ if (gestureRef.current !== null) {
343
+ return;
344
+ }
345
+
337
346
  const nativeEvent = 'nativeEvent' in event ? event.nativeEvent : event;
338
347
 
339
348
  gestureRef.current = initGesture(coordX(nativeEvent), coordY(nativeEvent));
@@ -351,7 +360,7 @@ export const Touch = ({
351
360
 
352
361
  // FIXME: заменить touch/mouse-события ниже на pointer-события после того, как бразуеры из
353
362
  // .browserslistrc начнут поддерживать его (см. https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#browser_compatibility).
354
- if (isTouchEnabled) {
363
+ if (isTouchEvent(nativeEvent)) {
355
364
  if (isHTMLElement(event.target) || isSVGElement(event.target)) {
356
365
  // Тач-события не всплывают, поэтому навешиваем события на целевой элемент
357
366
  // см. #235, #1968, https://stackoverflow.com/a/45760014
@@ -453,9 +462,9 @@ export const Touch = ({
453
462
  // onLeave
454
463
  onPointerLeave={usePointerHover ? handlePointerLeave : undefined}
455
464
  onMouseLeave={!usePointerHover ? handlePointerLeave : undefined}
456
- // handlePointerDown (onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)
457
- onMouseDownCapture={!isTouchEnabled && useCapture ? handlePointerDown : undefined}
458
- onMouseDown={!isTouchEnabled && !useCapture ? handlePointerDown : undefined}
465
+ // handlePointerDown(onTouchStart устанавливается отдельно через initializeNativeTouchEventStartWithPassiveFalse)
466
+ onMouseDownCapture={useCapture ? handlePointerDown : undefined}
467
+ onMouseDown={!useCapture ? handlePointerDown : undefined}
459
468
  />
460
469
  );
461
470
  };