Add support for long press to context menu on iOS (#1769)

* Initial support for touch context menu

* Only deal with touch if it's available

* Fix touch checking

* Remove touch checking

* Added comments

* Combine onTouch with onPointer for mobile context menu support
This commit is contained in:
Mehedi Hassan 2020-07-02 22:12:56 +01:00 committed by GitHub
parent 8621ddb6a2
commit cc52ea4ac2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 5 deletions

View File

@ -125,6 +125,7 @@ import {
INITAL_SCENE_UPDATE_TIMEOUT,
TAP_TWICE_TIMEOUT,
SYNC_FULL_SCENE_INTERVAL_MS,
TOUCH_CTX_MENU_TIMEOUT,
} from "../time_constants";
import LayerUI from "./LayerUI";
@ -172,6 +173,8 @@ let isHoldingSpace: boolean = false;
let isPanning: boolean = false;
let isDraggingScrollBar: boolean = false;
let currentScrollBars: ScrollBars = { horizontal: null, vertical: null };
let touchTimeout = 0;
let touchMoving = false;
let lastPointerUp: ((event: any) => void) | null = null;
const gesture: Gesture = {
@ -256,6 +259,7 @@ class App extends React.Component<any, AppState> {
onPointerMove={this.handleCanvasPointerMove}
onPointerUp={this.removePointer}
onPointerCancel={this.removePointer}
onTouchMove={this.handleTouchMove}
onDrop={this.handleCanvasOnDrop}
>
{t("labels.drawingCanvas")}
@ -409,6 +413,8 @@ class App extends React.Component<any, AppState> {
this.unmounted = true;
this.removeSceneCallback!();
this.removeEventListeners();
clearTimeout(touchTimeout);
}
private onResize = withBatchedUpdates(() => {
@ -818,6 +824,12 @@ class App extends React.Component<any, AppState> {
};
removePointer = (event: React.PointerEvent<HTMLElement>) => {
// remove touch handler for context menu on touch devices
if (event.pointerType === "touch" && touchTimeout) {
clearTimeout(touchTimeout);
touchMoving = false;
}
gesture.pointers.delete(event.pointerId);
};
@ -1802,11 +1814,32 @@ class App extends React.Component<any, AppState> {
}
};
// set touch moving for mobile context menu
private handleTouchMove = (event: React.TouchEvent<HTMLCanvasElement>) => {
touchMoving = true;
};
private handleCanvasPointerDown = (
event: React.PointerEvent<HTMLCanvasElement>,
) => {
event.persist();
// deal with opening context menu on touch devices
if (event.pointerType === "touch") {
touchMoving = false;
// open the context menu with the first touch's clientX and clientY
// if the touch is not moving
touchTimeout = window.setTimeout(() => {
if (!touchMoving) {
this.openContextMenu({
clientX: event.clientX,
clientY: event.clientY,
});
}
}, TOUCH_CTX_MENU_TIMEOUT);
}
if (lastPointerUp !== null) {
// Unfortunately, sometimes we don't get a pointerup after a pointerdown,
// this can happen when a contextual menu or alert is triggered. In order to avoid
@ -2847,9 +2880,18 @@ class App extends React.Component<any, AppState> {
event: React.PointerEvent<HTMLCanvasElement>,
) => {
event.preventDefault();
this.openContextMenu(event);
};
private openContextMenu = ({
clientX,
clientY,
}: {
clientX: number;
clientY: number;
}) => {
const { x, y } = viewportCoordsToSceneCoords(
event,
{ clientX, clientY },
this.state,
this.canvas,
window.devicePixelRatio,
@ -2888,8 +2930,8 @@ class App extends React.Component<any, AppState> {
action: this.toggleGridMode,
},
],
top: event.clientY,
left: event.clientX,
top: clientY,
left: clientX,
});
return;
}
@ -2920,8 +2962,8 @@ class App extends React.Component<any, AppState> {
(action) => !CANVAS_ONLY_ACTIONS.includes(action.name),
),
],
top: event.clientY,
left: event.clientX,
top: clientY,
left: clientX,
});
};

View File

@ -2,3 +2,4 @@
export const TAP_TWICE_TIMEOUT = 300;
export const INITAL_SCENE_UPDATE_TIMEOUT = 5000;
export const SYNC_FULL_SCENE_INTERVAL_MS = 20000;
export const TOUCH_CTX_MENU_TIMEOUT = 500;