From 9c28d8a6bd5cbca4536f1a309c245c551fe0c644 Mon Sep 17 00:00:00 2001 From: Lu Wilson Date: Fri, 19 May 2023 03:35:24 -0700 Subject: [PATCH] [firefox] Fix the pointer getting stuck down when you press the control key (#1390) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes a bug in firefox where the pointer can get stuck down while pressing the control key. It achieves this by taking a previous fix (specifically for `useShapeEvents`), and it applies the fix at a deeper level (within `app.dispatch`). ## Before ![2023-05-16 at 15 33 02 - Crimson Coyote](https://github.com/tldraw/tldraw/assets/15892272/7d4b5bb1-a2e5-400c-9935-fddcc9645e52) ## After ![2023-05-16 at 15 34 03 - Purple Panda](https://github.com/tldraw/tldraw/assets/15892272/34a598b2-bf6d-4847-8ce9-a3d52c418174) ### Change Type - [x] `patch` — Bug Fix ### Test Plan 1. Use firefox. 2. On the canvas... pointer down (to start a selection box). 3. Control key down. 4. Pointer up. 5. Make sure that that the selection box is gone. ^ Repeat the above for: Pointer down on a shape. Pointer down on a handle. ### Release Notes - [Firefox] Fixed a bug where the pointer could get stuck down when the control key is held down. --- packages/editor/api-report.md | 2 ++ packages/editor/src/lib/app/App.ts | 17 +++++++++ .../editor/src/lib/hooks/useCanvasEvents.ts | 2 +- .../editor/src/lib/hooks/useShapeEvents.ts | 35 ++++--------------- 4 files changed, 27 insertions(+), 29 deletions(-) diff --git a/packages/editor/api-report.md b/packages/editor/api-report.md index 899561fac..5f8ff5897 100644 --- a/packages/editor/api-report.md +++ b/packages/editor/api-report.md @@ -156,6 +156,8 @@ export class App extends EventEmitter { set canMoveCamera(canMove: boolean); get canRedo(): boolean; get canUndo(): boolean; + // @internal (undocumented) + capturedPointerId: null | number; centerOnPoint(x: number, y: number, opts?: AnimationOptions): this; // @internal protected _clickManager: ClickManager; diff --git a/packages/editor/src/lib/app/App.ts b/packages/editor/src/lib/app/App.ts index 93969314f..ab4968633 100644 --- a/packages/editor/src/lib/app/App.ts +++ b/packages/editor/src/lib/app/App.ts @@ -3527,6 +3527,9 @@ export class App extends EventEmitter { /** @internal */ private _selectedIdsAtPointerDown: TLShapeId[] = [] + /** @internal */ + capturedPointerId: number | null = null + /** * Dispatch an event to the app. * @@ -3742,6 +3745,12 @@ export class App extends EventEmitter { case 'pointer_down': { this._selectedIdsAtPointerDown = this.selectedIds.slice() + // Firefox bug fix... + // If it's a left-mouse-click, we store the pointer id for later user + if (info.button === 0) { + this.capturedPointerId = info.pointerId + } + // Add the button from the buttons set inputs.buttons.add(info.button) @@ -3833,6 +3842,14 @@ export class App extends EventEmitter { return } + // Firefox bug fix... + // If it's the same pointer that we stored earlier... + // ... then it's probably still a left-mouse-click! + if (this.capturedPointerId === info.pointerId) { + this.capturedPointerId = null + info.button = 0 + } + if (inputs.isPanning) { if (info.button === 1) { if (!this.inputs.keys.has(' ')) { diff --git a/packages/editor/src/lib/hooks/useCanvasEvents.ts b/packages/editor/src/lib/hooks/useCanvasEvents.ts index 78a9b0eea..9745060c4 100644 --- a/packages/editor/src/lib/hooks/useCanvasEvents.ts +++ b/packages/editor/src/lib/hooks/useCanvasEvents.ts @@ -43,7 +43,7 @@ export function useCanvasEvents() { function onPointerUp(e: React.PointerEvent) { if ((e as any).isKilled) return - if (e.button !== 0 && e.button !== 1 && e.button !== 5) return + if (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return lastX = e.clientX lastY = e.clientY diff --git a/packages/editor/src/lib/hooks/useShapeEvents.ts b/packages/editor/src/lib/hooks/useShapeEvents.ts index 65dd88e92..1e5049879 100644 --- a/packages/editor/src/lib/hooks/useShapeEvents.ts +++ b/packages/editor/src/lib/hooks/useShapeEvents.ts @@ -6,38 +6,18 @@ import { preventDefault, releasePointerCapture, setPointerCapture } from '../uti import { getPointerInfo } from '../utils/svg' import { useApp } from './useApp' -const pointerEventHandler = ( - app: App, - shapeId: TLShapeId, - name: TLPointerEventName, - capturedPointerIdLookup: Set -) => { +const pointerEventHandler = (app: App, shapeId: TLShapeId, name: TLPointerEventName) => { return (e: React.PointerEvent) => { if (name !== 'pointer_move' && app.pageState.editingId === shapeId) (e as any).isKilled = true if ((e as any).isKilled) return - let pointerInfo = getPointerInfo(e, app.getContainer()) - switch (name) { case 'pointer_down': { if (e.button !== 0 && e.button !== 1 && e.button !== 2) return setPointerCapture(e.currentTarget, e) - if (e.button === 0) { - capturedPointerIdLookup.add(`pointer_down:${e.pointerId}:0`) - } break } case 'pointer_up': { - const key = `pointer_down:${e.pointerId}:0` - // Due to an issue with how firefox handles click events, see - if (capturedPointerIdLookup.has(key)) { - // Because we've tracked the pointer event as a pointer_down with button 0, we can assume this is the invalid right click FF issue. - pointerInfo = { - ...pointerInfo, - button: 0, - } - capturedPointerIdLookup.delete(key) - } releasePointerCapture(e.currentTarget, e) break } @@ -55,7 +35,7 @@ const pointerEventHandler = ( target: 'shape', shape, name, - ...pointerInfo, + ...getPointerInfo(e, app.getContainer()), }) } } @@ -64,7 +44,6 @@ export function useShapeEvents(id: TLShapeId) { const app = useApp() return React.useMemo(() => { - const capturedPointerIdLookup = new Set() function onTouchStart(e: React.TouchEvent) { ;(e as any).isKilled = true preventDefault(e) @@ -75,7 +54,7 @@ export function useShapeEvents(id: TLShapeId) { preventDefault(e) } - const handlePointerMove = pointerEventHandler(app, id, 'pointer_move', capturedPointerIdLookup) + const handlePointerMove = pointerEventHandler(app, id, 'pointer_move') // Track the last screen point let lastX: number, lastY: number @@ -90,10 +69,10 @@ export function useShapeEvents(id: TLShapeId) { } return { - onPointerDown: pointerEventHandler(app, id, 'pointer_down', capturedPointerIdLookup), - onPointerUp: pointerEventHandler(app, id, 'pointer_up', capturedPointerIdLookup), - onPointerEnter: pointerEventHandler(app, id, 'pointer_enter', capturedPointerIdLookup), - onPointerLeave: pointerEventHandler(app, id, 'pointer_leave', capturedPointerIdLookup), + onPointerDown: pointerEventHandler(app, id, 'pointer_down'), + onPointerUp: pointerEventHandler(app, id, 'pointer_up'), + onPointerEnter: pointerEventHandler(app, id, 'pointer_enter'), + onPointerLeave: pointerEventHandler(app, id, 'pointer_leave'), onPointerMove, onTouchStart, onTouchEnd,