Skip to content

Commit 6c463f7

Browse files
authored
Use pointer events data grid (#1063)
* use pointer events instead of mouse + touch * fix tests to use pointer instead of mouse or touch * prefer pointer event for mouse args and defensively code against touchevent
1 parent ea0ff47 commit 6c463f7

File tree

7 files changed

+164
-165
lines changed

7 files changed

+164
-165
lines changed

packages/core/src/internal/click-outside-container/click-outside-container.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@ export default class ClickOutsideContainer extends React.PureComponent<Props> {
1212

1313
public componentDidMount() {
1414
const eventTarget = this.props.customEventTarget ?? document;
15-
eventTarget.addEventListener("touchend", this.clickOutside, true);
16-
eventTarget.addEventListener("mousedown", this.clickOutside, true);
15+
eventTarget.addEventListener("pointerdown", this.clickOutside, true);
1716
eventTarget.addEventListener("contextmenu", this.clickOutside, true);
1817
}
1918

2019
public componentWillUnmount() {
2120
const eventTarget = this.props.customEventTarget ?? document;
22-
eventTarget.removeEventListener("touchend", this.clickOutside, true);
23-
eventTarget.removeEventListener("mousedown", this.clickOutside, true);
21+
eventTarget.removeEventListener("pointerdown", this.clickOutside, true);
2422
eventTarget.removeEventListener("contextmenu", this.clickOutside, true);
2523
}
2624

packages/core/src/internal/data-grid/data-grid.tsx

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,12 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
507507
);
508508

509509
const getMouseArgsForPosition = React.useCallback(
510-
(canvas: HTMLCanvasElement, posX: number, posY: number, ev?: MouseEvent | TouchEvent): GridMouseEventArgs => {
510+
(
511+
canvas: HTMLCanvasElement,
512+
posX: number,
513+
posY: number,
514+
ev?: PointerEvent | MouseEvent | TouchEvent
515+
): GridMouseEventArgs => {
511516
const rect = canvas.getBoundingClientRect();
512517
const scale = rect.width / width;
513518
const x = (posX - rect.left) / scale;
@@ -518,7 +523,16 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
518523

519524
let button = 0;
520525
let buttons = 0;
521-
if (ev instanceof MouseEvent) {
526+
527+
const isMouse =
528+
(typeof PointerEvent !== "undefined" && ev instanceof PointerEvent && ev.pointerType === "mouse") ||
529+
(typeof MouseEvent !== "undefined" && ev instanceof MouseEvent);
530+
531+
const isTouch =
532+
(typeof PointerEvent !== "undefined" && ev instanceof PointerEvent && ev.pointerType === "touch") ||
533+
(typeof TouchEvent !== "undefined" && ev instanceof TouchEvent);
534+
535+
if (isMouse) {
522536
button = ev.button;
523537
buttons = ev.buttons;
524538
}
@@ -544,7 +558,6 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
544558
const shiftKey = ev?.shiftKey === true;
545559
const ctrlKey = ev?.ctrlKey === true;
546560
const metaKey = ev?.metaKey === true;
547-
const isTouch = (ev !== undefined && !(ev instanceof MouseEvent)) || (ev as any)?.pointerType === "touch";
548561

549562
const scrollEdge: GridMouseEventArgs["scrollEdge"] = [
550563
x < 0 ? -1 : width < x ? 1 : 0,
@@ -1037,22 +1050,16 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
10371050
const downTime = React.useRef(0);
10381051
const downPosition = React.useRef<Item>();
10391052
const mouseDown = React.useRef(false);
1040-
const onMouseDownImpl = React.useCallback(
1041-
(ev: MouseEvent | TouchEvent) => {
1053+
const onPointerDown = React.useCallback(
1054+
(ev: PointerEvent) => {
10421055
const canvas = ref.current;
10431056
const eventTarget = eventTargetRef?.current;
10441057
if (canvas === null || (ev.target !== canvas && ev.target !== eventTarget)) return;
10451058
mouseDown.current = true;
10461059

1047-
let clientX: number;
1048-
let clientY: number;
1049-
if (ev instanceof MouseEvent) {
1050-
clientX = ev.clientX;
1051-
clientY = ev.clientY;
1052-
} else {
1053-
clientX = ev.touches[0].clientX;
1054-
clientY = ev.touches[0].clientY;
1055-
}
1060+
const clientX = ev.clientX;
1061+
const clientY = ev.clientY;
1062+
10561063
if (ev.target === eventTarget && eventTarget !== null) {
10571064
const bounds = eventTarget.getBoundingClientRect();
10581065
if (clientX > bounds.right || clientY > bounds.bottom) return;
@@ -1101,13 +1108,12 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
11011108
onMouseDown,
11021109
]
11031110
);
1104-
useEventListener("touchstart", onMouseDownImpl, windowEventTarget, false);
1105-
useEventListener("mousedown", onMouseDownImpl, windowEventTarget, false);
1111+
useEventListener("pointerdown", onPointerDown, windowEventTarget, false);
11061112

11071113
const lastUpTime = React.useRef(0);
11081114

1109-
const onMouseUpImpl = React.useCallback(
1110-
(ev: MouseEvent | TouchEvent) => {
1115+
const onPointerUp = React.useCallback(
1116+
(ev: PointerEvent) => {
11111117
const lastUpTimeValue = lastUpTime.current;
11121118
lastUpTime.current = Date.now();
11131119
const canvas = ref.current;
@@ -1116,21 +1122,9 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
11161122
const eventTarget = eventTargetRef?.current;
11171123

11181124
const isOutside = ev.target !== canvas && ev.target !== eventTarget;
1119-
1120-
let clientX: number;
1121-
let clientY: number;
1122-
let canCancel = true;
1123-
if (ev instanceof MouseEvent) {
1124-
clientX = ev.clientX;
1125-
clientY = ev.clientY;
1126-
canCancel = ev.button < 3;
1127-
if ((ev as any).pointerType === "touch") {
1128-
return;
1129-
}
1130-
} else {
1131-
clientX = ev.changedTouches[0].clientX;
1132-
clientY = ev.changedTouches[0].clientY;
1133-
}
1125+
const clientX = ev.clientX;
1126+
const clientY = ev.clientY;
1127+
const canCancel = ev.pointerType === "mouse" ? ev.button < 3 : true;
11341128

11351129
let args = getMouseArgsForPosition(canvas, clientX, clientY, ev);
11361130

@@ -1178,8 +1172,7 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
11781172
},
11791173
[onMouseUp, eventTargetRef, getMouseArgsForPosition, isOverHeaderElement, groupHeaderActionForEvent]
11801174
);
1181-
useEventListener("mouseup", onMouseUpImpl, windowEventTarget, false);
1182-
useEventListener("touchend", onMouseUpImpl, windowEventTarget, false);
1175+
useEventListener("pointerup", onPointerUp, windowEventTarget, false);
11831176

11841177
const onClickImpl = React.useCallback(
11851178
(ev: MouseEvent | TouchEvent) => {
@@ -1284,7 +1277,7 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
12841277
}, [getCellContent, getCellRenderer, hoveredItem]);
12851278

12861279
const hoveredRef = React.useRef<GridMouseEventArgs>();
1287-
const onMouseMoveImpl = React.useCallback(
1280+
const onPointerMove = React.useCallback(
12881281
(ev: MouseEvent) => {
12891282
const canvas = ref.current;
12901283
if (canvas === null) return;
@@ -1367,7 +1360,7 @@ const DataGrid: React.ForwardRefRenderFunction<DataGridRef, DataGridProps> = (p,
13671360
damageInternal,
13681361
]
13691362
);
1370-
useEventListener("mousemove", onMouseMoveImpl, windowEventTarget, true);
1363+
useEventListener("pointermove", onPointerMove, windowEventTarget, true);
13711364

13721365
const onKeyDownImpl = React.useCallback(
13731366
(event: React.KeyboardEvent<HTMLCanvasElement>) => {

packages/core/test/data-editor-input.test.tsx

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import type { DataEditorRef } from "../src/data-editor/data-editor.js";
1313
import { CompactSelection } from "../src/internal/data-grid/data-grid-types.js";
1414
import { vi, expect, describe, test, beforeEach, afterEach } from "vitest";
15+
import { standardBeforeEach } from "./test-utils.js";
1516

1617
const makeCell = (cell: Item): GridCell => {
1718
const [col, row] = cell;
@@ -223,6 +224,8 @@ describe("data-editor-input", () => {
223224
});
224225

225226
beforeEach(() => {
227+
standardBeforeEach();
228+
226229
Element.prototype.scrollTo = vi.fn() as any;
227230
Element.prototype.scrollBy = vi.fn() as any;
228231
Object.assign(navigator, {
@@ -267,17 +270,17 @@ a new line char ""more quotes"" plus a tab ." https://google.com`)
267270
prep();
268271
const canvas = screen.getByTestId("data-grid-canvas");
269272

270-
fireEvent.mouseDown(canvas, {
273+
fireEvent.pointerDown(canvas, {
271274
clientX: 350,
272275
clientY: 36 + 32 * 2 + 16,
273276
});
274277

275-
fireEvent.mouseMove(canvas, {
278+
fireEvent.pointerMove(canvas, {
276279
clientX: 650,
277280
clientY: 36 + 32 * 12 + 16,
278281
});
279282

280-
fireEvent.mouseUp(canvas, {
283+
fireEvent.pointerUp(canvas, {
281284
clientX: 650,
282285
clientY: 36 + 32 * 12 + 16,
283286
});
@@ -316,19 +319,19 @@ a new line char ""more quotes"" plus a tab ." https://google.com`)
316319
prep();
317320
const canvas = screen.getByTestId("data-grid-canvas");
318321

319-
fireEvent.mouseDown(canvas, {
322+
fireEvent.pointerDown(canvas, {
320323
ctrlKey: true,
321324
clientX: 350,
322325
clientY: 36 + 32 * 2 + 16,
323326
});
324327

325-
fireEvent.mouseMove(canvas, {
328+
fireEvent.pointerMove(canvas, {
326329
ctrlKey: true,
327330
clientX: 650,
328331
clientY: 36 + 32 * 12 + 16,
329332
});
330333

331-
fireEvent.mouseUp(canvas, {
334+
fireEvent.pointerUp(canvas, {
332335
ctrlKey: true,
333336
clientX: 650,
334337
clientY: 36 + 32 * 12 + 16,
@@ -372,19 +375,19 @@ a new line char ""more quotes"" plus a tab ." https://google.com`)
372375
prep();
373376
const canvas = screen.getByTestId("data-grid-canvas");
374377

375-
fireEvent.mouseDown(canvas, {
378+
fireEvent.pointerDown(canvas, {
376379
ctrlKey: true,
377380
clientX: 20,
378381
clientY: 36 + 32 * 3 + 16,
379382
});
380383

381-
fireEvent.mouseMove(canvas, {
384+
fireEvent.pointerMove(canvas, {
382385
ctrlKey: true,
383386
clientX: 20,
384387
clientY: 36 + 32 * 3 + 16,
385388
});
386389

387-
fireEvent.mouseUp(canvas, {
390+
fireEvent.pointerUp(canvas, {
388391
ctrlKey: true,
389392
clientX: 20,
390393
clientY: 36 + 32 * 3 + 16,
@@ -429,19 +432,19 @@ a new line char ""more quotes"" plus a tab ." https://google.com`)
429432
prep();
430433
const canvas = screen.getByTestId("data-grid-canvas");
431434

432-
fireEvent.mouseDown(canvas, {
435+
fireEvent.pointerDown(canvas, {
433436
ctrlKey: true,
434437
clientX: 20,
435438
clientY: 36 + 32 * 3 + 16,
436439
});
437440

438-
fireEvent.mouseMove(canvas, {
441+
fireEvent.pointerMove(canvas, {
439442
ctrlKey: true,
440443
clientX: 20,
441444
clientY: 36 + 32 * 3 + 16,
442445
});
443446

444-
fireEvent.mouseUp(canvas, {
447+
fireEvent.pointerUp(canvas, {
445448
ctrlKey: true,
446449
clientX: 20,
447450
clientY: 36 + 32 * 3 + 16,
@@ -485,19 +488,19 @@ a new line char ""more quotes"" plus a tab ." https://google.com`)
485488
prep();
486489
const canvas = screen.getByTestId("data-grid-canvas");
487490

488-
fireEvent.mouseDown(canvas, {
491+
fireEvent.pointerDown(canvas, {
489492
ctrlKey: true,
490493
clientX: 220,
491494
clientY: 16,
492495
});
493496

494-
fireEvent.mouseMove(canvas, {
497+
fireEvent.pointerMove(canvas, {
495498
ctrlKey: true,
496499
clientX: 220,
497500
clientY: 16,
498501
});
499502

500-
fireEvent.mouseUp(canvas, {
503+
fireEvent.pointerUp(canvas, {
501504
ctrlKey: true,
502505
clientX: 220,
503506
clientY: 16,
@@ -542,19 +545,19 @@ a new line char ""more quotes"" plus a tab ." https://google.com`)
542545
prep();
543546
const canvas = screen.getByTestId("data-grid-canvas");
544547

545-
fireEvent.mouseDown(canvas, {
548+
fireEvent.pointerDown(canvas, {
546549
ctrlKey: true,
547550
clientX: 220,
548551
clientY: 16,
549552
});
550553

551-
fireEvent.mouseMove(canvas, {
554+
fireEvent.pointerMove(canvas, {
552555
ctrlKey: true,
553556
clientX: 220,
554557
clientY: 16,
555558
});
556559

557-
fireEvent.mouseUp(canvas, {
560+
fireEvent.pointerUp(canvas, {
558561
ctrlKey: true,
559562
clientX: 220,
560563
clientY: 16,

0 commit comments

Comments
 (0)