Prevent scroll on swipe and drag gestures

This commit is contained in:
Alexander Zinchuk 2021-08-21 13:33:11 +03:00
parent 69acc87529
commit 1450fa4631
8 changed files with 58 additions and 20 deletions

View File

@ -110,12 +110,17 @@ const ProfileInfo: FC<OwnProps & StateProps & DispatchProps> = ({
}
return captureEvents(element, {
selectorToPreventScroll: '.Profile, .settings-content',
onSwipe: IS_TOUCH_ENV ? (e, direction) => {
if (direction === SwipeDirection.Right) {
selectPreviousMedia();
return true;
} else if (direction === SwipeDirection.Left) {
selectNextMedia();
return true;
}
return false;
} : undefined,
});
}, [selectNextMedia, selectPreviousMedia]);

View File

@ -137,12 +137,17 @@ const ChatFolders: FC<OwnProps & StateProps & DispatchProps> = ({
}
return captureEvents(transitionRef.current, {
selectorToPreventScroll: '.Profile',
onSwipe: ((e, direction) => {
if (direction === SwipeDirection.Left) {
setActiveChatFolder(Math.min(activeChatFolder + 1, folderTabs.length - 1));
return true;
} else if (direction === SwipeDirection.Right) {
setActiveChatFolder(Math.max(0, activeChatFolder - 1));
return true;
}
return false;
}),
});
}, [activeChatFolder, folderTabs, setActiveChatFolder]);

View File

@ -10,7 +10,6 @@
.color-picker {
margin-top: 1rem;
height: 12rem;
touch-action: none;
}
.hue-picker {

View File

@ -109,6 +109,8 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
setHsb(positions2hsb({ colorPosition, huePosition }, rectsRef.current!));
markIsDragging();
return true;
}
captureEvents(colorPickerRef.current!, {
@ -116,6 +118,7 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
onDrag: handleColorDrag,
onRelease: unmarkIsDragging,
onClick: unmarkIsDragging,
selectorToPreventScroll: '.SettingsGeneralBackgroundColor',
withCursor: true,
});
@ -125,6 +128,8 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
setHsb(positions2hsb({ colorPosition, huePosition }, rectsRef.current!));
markIsDragging();
return true;
}
captureEvents(huePickerRef.current!, {
@ -132,6 +137,7 @@ const SettingsGeneralBackground: FC<OwnProps & StateProps & DispatchProps> = ({
onDrag: handleHueDrag,
onRelease: unmarkIsDragging,
onClick: unmarkIsDragging,
selectorToPreventScroll: '.SettingsGeneralBackgroundColor',
withCursor: true,
});
}, [markIsDragging, unmarkIsDragging]);

View File

@ -75,6 +75,7 @@ export default function useOuterHandlers(
let startedAt: number | undefined;
return captureEvents(containerRef.current!, {
selectorToPreventScroll: '.MessageList',
onSwipe: ((e, direction) => {
if (direction === SwipeDirection.Left) {
if (!startedAt) {
@ -82,11 +83,15 @@ export default function useOuterHandlers(
}
markSwiped();
return true;
} else if (direction === SwipeDirection.Right) {
startedAt = undefined;
unmarkSwiped();
}
return false;
}),
onRelease: () => {
if (!startedAt) {

View File

@ -5,11 +5,6 @@
overflow-y: scroll;
overflow-x: hidden;
@supports (overflow-y: overlay) {
overflow-y: overlay !important;
}
> .profile-info > .ChatInfo {
grid-area: chat_info;

View File

@ -211,12 +211,17 @@ const Profile: FC<OwnProps & StateProps & DispatchProps> = ({
}
return captureEvents(transitionRef.current, {
selectorToPreventScroll: '.Profile',
onSwipe: ((e, direction) => {
if (direction === SwipeDirection.Left) {
setActiveTab(Math.min(activeTab + 1, tabs.length - 1));
return true;
} else if (direction === SwipeDirection.Right) {
setActiveTab(Math.max(0, activeTab - 1));
return true;
}
return false;
}),
});
}, [activeTab, tabs.length]);

View File

@ -1,4 +1,4 @@
import { IS_IOS } from './environment';
import { IS_IOS, IS_TOUCH_ENV } from './environment';
export enum SwipeDirection {
Up,
@ -17,10 +17,11 @@ interface CaptureOptions {
dragOffsetX: number;
dragOffsetY: number;
},
) => void;
onSwipe?: (e: Event, direction: SwipeDirection) => void;
) => boolean | void;
onSwipe?: (e: Event, direction: SwipeDirection) => boolean | void;
onClick?: (e: MouseEvent | TouchEvent) => void;
excludedClosestSelector?: string;
selectorToPreventScroll?: string;
withCursor?: boolean;
}
@ -100,6 +101,12 @@ export function captureEvents(element: HTMLElement, options: CaptureOptions) {
captureEvent = undefined;
if (hasMoved) {
if (IS_TOUCH_ENV && options.selectorToPreventScroll) {
Array.from(document.querySelectorAll<HTMLElement>(options.selectorToPreventScroll)).forEach((scrollable) => {
scrollable.style.overflow = '';
});
}
if (options.onRelease) {
options.onRelease(e);
}
@ -131,13 +138,22 @@ export function captureEvents(element: HTMLElement, options: CaptureOptions) {
hasMoved = true;
}
let shouldPreventScroll: boolean | void;
if (options.onDrag) {
e.preventDefault();
options.onDrag(e, captureEvent, { dragOffsetX, dragOffsetY });
shouldPreventScroll = options.onDrag(e, captureEvent, { dragOffsetX, dragOffsetY });
}
if (options.onSwipe) {
onSwipe(e, dragOffsetX, dragOffsetY);
shouldPreventScroll = onSwipe(e, dragOffsetX, dragOffsetY);
}
if (IS_TOUCH_ENV && shouldPreventScroll && options.selectorToPreventScroll) {
if (options.selectorToPreventScroll) {
Array.from(document.querySelectorAll<HTMLElement>(options.selectorToPreventScroll)).forEach((scrollable) => {
scrollable.style.overflow = 'hidden';
});
}
}
}
}
@ -147,7 +163,7 @@ export function captureEvents(element: HTMLElement, options: CaptureOptions) {
if (IS_IOS) {
const x = (e as RealTouchEvent).touches[0].pageX;
if (x <= IOS_SCREEN_EDGE_THRESHOLD || x >= window.innerWidth - IOS_SCREEN_EDGE_THRESHOLD) {
return;
return undefined;
}
}
@ -159,7 +175,7 @@ export function captureEvents(element: HTMLElement, options: CaptureOptions) {
const ratio = Math.max(xAbs, yAbs) / Math.min(xAbs, yAbs);
// Diagonal swipe
if (ratio < 2) {
return;
return undefined;
}
}
@ -170,7 +186,7 @@ export function captureEvents(element: HTMLElement, options: CaptureOptions) {
}
}
processSwipe(e, currentSwipeAxis, dragOffsetX, dragOffsetY, options.onSwipe!);
return processSwipe(e, currentSwipeAxis, dragOffsetX, dragOffsetY, options.onSwipe!);
}
element.addEventListener('mousedown', onCapture);
@ -187,19 +203,21 @@ function processSwipe(
currentSwipeAxis: TSwipeAxis,
dragOffsetX: number,
dragOffsetY: number,
onSwipe: (e: Event, direction: SwipeDirection) => void,
onSwipe: (e: Event, direction: SwipeDirection) => boolean | void,
) {
if (currentSwipeAxis === 'x') {
if (dragOffsetX < 0) {
onSwipe(e, SwipeDirection.Left);
return onSwipe(e, SwipeDirection.Left);
} else {
onSwipe(e, SwipeDirection.Right);
return onSwipe(e, SwipeDirection.Right);
}
} else if (currentSwipeAxis === 'y') {
if (dragOffsetY < 0) {
onSwipe(e, SwipeDirection.Up);
return onSwipe(e, SwipeDirection.Up);
} else {
onSwipe(e, SwipeDirection.Down);
return onSwipe(e, SwipeDirection.Down);
}
}
return undefined;
}