From 8c2994273167bdf9363ece80a249f07dec0331fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bert?= Date: Fri, 1 Mar 2024 16:04:24 +0100 Subject: [PATCH 1/5] Add new prop --- src/handlers/gestureHandlerCommon.ts | 19 +++++++++++++++++++ src/handlers/gestures/GestureDetector.tsx | 15 +++++++++++++++ src/web/interfaces.ts | 8 +++++++- src/web/tools/GestureHandlerWebDelegate.ts | 2 ++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/handlers/gestureHandlerCommon.ts b/src/handlers/gestureHandlerCommon.ts index 5c0dfe72c1..d8732c6483 100644 --- a/src/handlers/gestureHandlerCommon.ts +++ b/src/handlers/gestureHandlerCommon.ts @@ -25,6 +25,7 @@ const commonProps = [ 'activeCursor', 'mouseButton', 'enableContextMenu', + 'touchAction', ] as const; const componentInteractionProps = [ @@ -113,6 +114,23 @@ export type ActiveCursor = | 'zoom-in' | 'zoom-out'; +export type TouchAction = + | 'auto' + | 'none' + | 'pan-x' + | 'pan-left' + | 'pan-right' + | 'pan-y' + | 'pan-up' + | 'pan-down' + | 'pinch-zoom' + | 'manipulation' + | 'inherit' + | 'initial' + | 'revert' + | 'revert-layer' + | 'unset'; + //TODO(TS) events in handlers export interface GestureEvent> { @@ -156,6 +174,7 @@ export type CommonGestureConfig = { activeCursor?: ActiveCursor; mouseButton?: MouseButton; enableContextMenu?: boolean; + touchAction?: TouchAction; }; // Events payloads are types instead of interfaces due to TS limitation. diff --git a/src/handlers/gestures/GestureDetector.tsx b/src/handlers/gestures/GestureDetector.tsx index 5f55b5eeab..569b0b76e1 100644 --- a/src/handlers/gestures/GestureDetector.tsx +++ b/src/handlers/gestures/GestureDetector.tsx @@ -19,6 +19,7 @@ import { HandlerStateChangeEvent, scheduleFlushOperations, UserSelect, + TouchAction, } from '../gestureHandlerCommon'; import { GestureStateManager, @@ -614,11 +615,21 @@ const applyEnableContextMenuProp = ( } }; +const applyTouchActionProp = ( + touchAction: TouchAction, + gesture: ComposedGesture | GestureType +): void => { + for (const g of gesture.toGestureArray()) { + g.config.touchAction = touchAction; + } +}; + interface GestureDetectorProps { gesture: ComposedGesture | GestureType; children?: React.ReactNode; userSelect?: UserSelect; enableContextMenu?: boolean; + touchAction?: TouchAction; } interface GestureDetectorState { firstRender: boolean; @@ -644,6 +655,10 @@ export const GestureDetector = (props: GestureDetectorProps) => { applyEnableContextMenuProp(props.enableContextMenu, gestureConfig); } + if (props.touchAction !== undefined) { + applyTouchActionProp(props.touchAction, gestureConfig); + } + const gesture = gestureConfig.toGestureArray(); const useReanimatedHook = gesture.some((g) => g.shouldUseReanimated); diff --git a/src/web/interfaces.ts b/src/web/interfaces.ts index 9f3ef3d1d8..0b83e4641e 100644 --- a/src/web/interfaces.ts +++ b/src/web/interfaces.ts @@ -1,4 +1,8 @@ -import { UserSelect, ActiveCursor } from '../handlers/gestureHandlerCommon'; +import { + UserSelect, + ActiveCursor, + TouchAction, +} from '../handlers/gestureHandlerCommon'; import { Directions } from '../Directions'; import { State } from '../State'; import { PointerType } from '../PointerType'; @@ -23,6 +27,7 @@ type ConfigArgs = | boolean | HitSlop | UserSelect + | TouchAction | ActiveCursor | Directions | Handler[] @@ -40,6 +45,7 @@ export interface Config extends Record { activeCursor?: ActiveCursor; mouseButton?: MouseButton; enableContextMenu?: boolean; + touchAction?: TouchAction; activateAfterLongPress?: number; failOffsetXStart?: number; diff --git a/src/web/tools/GestureHandlerWebDelegate.ts b/src/web/tools/GestureHandlerWebDelegate.ts index fad27df38c..864b784425 100644 --- a/src/web/tools/GestureHandlerWebDelegate.ts +++ b/src/web/tools/GestureHandlerWebDelegate.ts @@ -48,6 +48,8 @@ export class GestureHandlerWebDelegate this.view.style['userSelect'] = config.userSelect; } + this.view.style['touchAction'] = config.touchAction ?? 'none'; + this.eventManagers.push(new PointerEventManager(this.view)); this.eventManagers.push(new TouchEventManager(this.view)); From bfbbf838209340c9df9fe5bdc464342c180db774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bert?= Date: Mon, 4 Mar 2024 08:50:33 +0100 Subject: [PATCH 2/5] Restore webkit-touch-callout --- src/web/tools/GestureHandlerWebDelegate.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/web/tools/GestureHandlerWebDelegate.ts b/src/web/tools/GestureHandlerWebDelegate.ts index 864b784425..5e10e445e8 100644 --- a/src/web/tools/GestureHandlerWebDelegate.ts +++ b/src/web/tools/GestureHandlerWebDelegate.ts @@ -32,10 +32,6 @@ export class GestureHandlerWebDelegate this.gestureHandler = handler; this.view = findNodeHandle(viewRef) as unknown as HTMLElement; - this.view.style['touchAction'] = 'none'; - //@ts-ignore This one disables default events on Safari - this.view.style['WebkitTouchCallout'] = 'none'; - const config = handler.getConfig(); this.addContextMenuListeners(config); @@ -49,6 +45,8 @@ export class GestureHandlerWebDelegate } this.view.style['touchAction'] = config.touchAction ?? 'none'; + //@ts-ignore This one disables default events on Safari + this.view.style['WebkitTouchCallout'] = 'none'; this.eventManagers.push(new PointerEventManager(this.view)); this.eventManagers.push(new TouchEventManager(this.view)); From af2e7f2f46fd686758ceaa02a935c37b39badaea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bert?= Date: Mon, 4 Mar 2024 08:51:14 +0100 Subject: [PATCH 3/5] Add default touchAction to Swipeables --- src/components/Swipeable.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/Swipeable.tsx b/src/components/Swipeable.tsx index b3ae488ab2..76b8c077b8 100644 --- a/src/components/Swipeable.tsx +++ b/src/components/Swipeable.tsx @@ -541,6 +541,7 @@ export default class Swipeable extends Component< return ( @@ -551,6 +552,7 @@ export default class Swipeable extends Component< {right} Date: Mon, 4 Mar 2024 09:08:21 +0100 Subject: [PATCH 4/5] Remove curly braces --- src/components/Swipeable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Swipeable.tsx b/src/components/Swipeable.tsx index 76b8c077b8..e464540e5a 100644 --- a/src/components/Swipeable.tsx +++ b/src/components/Swipeable.tsx @@ -541,7 +541,7 @@ export default class Swipeable extends Component< return ( @@ -552,7 +552,7 @@ export default class Swipeable extends Component< {right} Date: Mon, 4 Mar 2024 09:34:54 +0100 Subject: [PATCH 5/5] Cancel handlers by Native --- src/web/handlers/NativeViewGestureHandler.ts | 11 +++++------ src/web/tools/InteractionManager.ts | 11 ++++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/web/handlers/NativeViewGestureHandler.ts b/src/web/handlers/NativeViewGestureHandler.ts index 767a385e6d..f3718af76b 100644 --- a/src/web/handlers/NativeViewGestureHandler.ts +++ b/src/web/handlers/NativeViewGestureHandler.ts @@ -28,15 +28,10 @@ export default class NativeViewGestureHandler extends GestureHandler { const view = this.delegate.getView() as HTMLElement; view.style['touchAction'] = 'auto'; - //@ts-ignore Turns on defualt touch behavior on Safari view.style['WebkitTouchCallout'] = 'auto'; - if (view.hasAttribute('role')) { - this.buttonRole = true; - } else { - this.buttonRole = false; - } + this.buttonRole = view.getAttribute('role') === 'button'; } public updateGestureConfig({ enabled = true, ...props }: Config): void { @@ -164,4 +159,8 @@ export default class NativeViewGestureHandler extends GestureHandler { public disallowsInterruption(): boolean { return this.disallowInterruption; } + + public isButton(): boolean { + return this.buttonRole; + } } diff --git a/src/web/tools/InteractionManager.ts b/src/web/tools/InteractionManager.ts index 55df13b033..1443939f12 100644 --- a/src/web/tools/InteractionManager.ts +++ b/src/web/tools/InteractionManager.ts @@ -1,4 +1,6 @@ +import { State } from '../../State'; import GestureHandler from '../handlers/GestureHandler'; +import NativeViewGestureHandler from '../handlers/NativeViewGestureHandler'; import { Config, Handler } from '../interfaces'; export default class InteractionManager { @@ -102,10 +104,13 @@ export default class InteractionManager { public shouldHandlerBeCancelledBy( _handler: GestureHandler, - _otherHandler: GestureHandler + otherHandler: GestureHandler ): boolean { - //TODO: Implement logic - return false; + return ( + otherHandler instanceof NativeViewGestureHandler && + otherHandler.getState() === State.ACTIVE && + !otherHandler.isButton() + ); } public dropRelationsForHandlerWithTag(handlerTag: number): void {