[react-interactions] fix Press/Tap behavior for virtual middle clicks (#17554)
Tools like BetterTouchTool for macOS trigger middle-clicks with a 'buttons' value that doesn't correspond to the middle-mouse button. To account for this we also inspect the value of 'button'. Close #17367
Nicolas Gallagher committed
Dec 9, 2019 at 13:04 UTC
9e937e7e86be4af829bd7be2045bf3601928c9b5
9 files changed
+292
-65
packages/react-interactions/events/src/dom/PressLegacy.js
+3
@@ -626,6 +626,9 @@ const pressResponderImpl = {
626
state.responderRegionOnDeactivation = null;
627
state.isPressWithinResponderRegion = true;
628
state.buttons = nativeEvent.buttons;
629
+ if (nativeEvent.button === 1) {
630
+ state.buttons = 4;
631
+ }
632
dispatchPressStartEvents(event, context, props, state);
633
addRootEventTypes(context, state);
634
} else {
packages/react-interactions/events/src/dom/Tap.js
+6
-2
@@ -520,10 +520,14 @@ const responderImpl = {
520
}
521
522
const activate = shouldActivate(event);
523
- const activateAuxiliary = isAuxiliary(nativeEvent.buttons, event);
523
+ const buttons =
524
+ nativeEvent.button === 1
525
+ ? buttonsEnum.auxiliary
526
+ : nativeEvent.buttons;
527
+ const activateAuxiliary = isAuxiliary(buttons, event);
528
529
if (activate || activateAuxiliary) {
526
- state.buttons = nativeEvent.buttons;
530
+ state.buttons = buttons;
531
state.pointerType = event.pointerType;
532
state.responderTarget = context.getResponderNode();
533
addRootEventTypes(rootEventTypes, context, state);
packages/react-interactions/events/src/dom/__tests__/Press-test.internal.js
+56
-1
@@ -10,6 +10,7 @@
10
'use strict';
11
12
import {
13
+ buttonType,
14
buttonsType,
15
createEventTarget,
16
describeWithPointerEvent,
@@ -126,7 +127,30 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
127
it('is called after middle-button pointer down', () => {
128
const target = createEventTarget(ref.current);
129
const pointerType = 'mouse';
129
- target.pointerdown({buttons: buttonsType.auxiliary, pointerType});
130
+ target.pointerdown({
131
+ button: buttonType.auxiliary,
132
+ buttons: buttonsType.auxiliary,
133
+ pointerType,
134
+ });
135
+ target.pointerup({pointerType});
136
+ expect(onPressStart).toHaveBeenCalledTimes(1);
137
+ expect(onPressStart).toHaveBeenCalledWith(
138
+ expect.objectContaining({
139
+ buttons: buttonsType.auxiliary,
140
+ pointerType: 'mouse',
141
+ type: 'pressstart',
142
+ }),
143
+ );
144
+ });
145
+
146
+ it('is called after virtual middle-button pointer down', () => {
147
+ const target = createEventTarget(ref.current);
148
+ const pointerType = 'mouse';
149
+ target.pointerdown({
150
+ button: buttonType.auxiliary,
151
+ buttons: 0,
152
+ pointerType,
153
+ });
154
target.pointerup({pointerType});
155
expect(onPressStart).toHaveBeenCalledTimes(1);
156
expect(onPressStart).toHaveBeenCalledWith(
@@ -212,6 +236,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
236
it('is called after middle-button pointer up', () => {
237
const target = createEventTarget(ref.current);
238
target.pointerdown({
239
+ button: buttonType.auxiliary,
240
buttons: buttonsType.auxiliary,
241
pointerType: 'mouse',
242
});
@@ -226,6 +251,24 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
251
);
252
});
253
254
+ it('is called after virtual middle-button pointer up', () => {
255
+ const target = createEventTarget(ref.current);
256
+ target.pointerdown({
257
+ button: buttonType.auxiliary,
258
+ buttons: 0,
259
+ pointerType: 'mouse',
260
+ });
261
+ target.pointerup({pointerType: 'mouse'});
262
+ expect(onPressEnd).toHaveBeenCalledTimes(1);
263
+ expect(onPressEnd).toHaveBeenCalledWith(
264
+ expect.objectContaining({
265
+ buttons: buttonsType.auxiliary,
266
+ pointerType: 'mouse',
267
+ type: 'pressend',
268
+ }),
269
+ );
270
+ });
271
+
272
it('is called after "keyup" event for Enter', () => {
273
const target = createEventTarget(ref.current);
274
target.keydown({key: 'Enter'});
@@ -356,6 +399,7 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
399
it('is not called after middle-button press', () => {
400
const target = createEventTarget(ref.current);
401
target.pointerdown({
402
+ button: buttonType.auxiliary,
403
buttons: buttonsType.auxiliary,
404
pointerType: 'mouse',
405
});
@@ -363,6 +407,17 @@ describeWithPointerEvent('Press responder', hasPointerEvents => {
407
expect(onPress).not.toHaveBeenCalled();
408
});
409
410
+ it('is not called after virtual middle-button press', () => {
411
+ const target = createEventTarget(ref.current);
412
+ target.pointerdown({
413
+ button: buttonType.auxiliary,
414
+ buttons: 0,
415
+ pointerType: 'mouse',
416
+ });
417
+ target.pointerup({pointerType: 'mouse'});
418
+ expect(onPress).not.toHaveBeenCalled();
419
+ });
420
+
421
it('is called after valid "keyup" event', () => {
422
const target = createEventTarget(ref.current);
423
target.keydown({key: 'Enter'});
packages/react-interactions/events/src/dom/__tests__/PressLegacy-test.internal.js
+14
@@ -10,6 +10,7 @@
10
'use strict';
11
12
import {
13
+ buttonType,
14
buttonsType,
15
createEventTarget,
16
setPointerEvent,
@@ -122,6 +123,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
123
it('is called after middle-button pointer down', () => {
124
const target = createEventTarget(ref.current);
125
target.pointerdown({
126
+ button: buttonType.auxiliary,
127
buttons: buttonsType.auxiliary,
128
pointerType: 'mouse',
129
});
@@ -140,6 +142,7 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
142
const target = createEventTarget(node);
143
target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
144
target.pointerdown({
145
+ button: buttonType.auxiliary,
146
buttons: buttonsType.auxiliary,
147
pointerType: 'mouse',
148
});
@@ -374,6 +377,17 @@ describe.each(environmentTable)('Press responder', hasPointerEvents => {
377
expect(onPress).not.toHaveBeenCalled();
378
});
379
380
+ it('is not called after virtual middle-button press', () => {
381
+ const target = createEventTarget(ref.current);
382
+ target.pointerdown({
383
+ button: buttonType.auxiliary,
384
+ buttons: 0,
385
+ pointerType: 'mouse',
386
+ });
387
+ target.pointerup({pointerType: 'mouse'});
388
+ expect(onPress).not.toHaveBeenCalled();
389
+ });
390
+
391
it('is called after valid "keyup" event', () => {
392
const target = createEventTarget(ref.current);
393
target.keydown({key: 'Enter'});
packages/react-interactions/events/src/dom/__tests__/Tap-test.internal.js
+127
-47
@@ -10,6 +10,7 @@
10
'use strict';
11
12
import {
13
+ buttonType,
14
buttonsType,
15
createEventTarget,
16
describeWithPointerEvent,
@@ -209,19 +210,21 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
210
211
test('auxiliary-button pointer up', () => {
212
const pointerType = 'mouse';
213
+ const button = buttonType.auxiliary;
214
const buttons = buttonsType.auxiliary;
215
const target = createEventTarget(ref.current);
214
- target.pointerdown({buttons, pointerType});
215
- target.pointerup({buttons, pointerType});
216
+ target.pointerdown({button, buttons, pointerType});
217
+ target.pointerup({button, buttons, pointerType});
218
expect(onAuxiliaryTap).toHaveBeenCalledTimes(1);
219
});
220
221
test('modifier-button pointer up', () => {
222
const pointerType = 'mouse';
223
+ const button = buttonType.primary;
224
const buttons = buttonsType.primary;
225
const target = createEventTarget(ref.current);
223
- target.pointerdown({buttons, pointerType});
224
- target.pointerup({buttons, metaKey: true, pointerType});
226
+ target.pointerdown({button, buttons, pointerType});
227
+ target.pointerup({button, buttons, metaKey: true, pointerType});
228
expect(onAuxiliaryTap).toHaveBeenCalledTimes(1);
229
});
230
});
@@ -243,6 +246,7 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
246
testWithPointerType('pointer down', pointerType => {
247
const target = createEventTarget(ref.current);
248
const nativeEvent = {
249
+ button: buttonType.primary,
250
buttons: buttonsType.primary,
251
pageX: 10,
252
pageY: 10,
@@ -287,11 +291,12 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
291
test('second pointer on target', () => {
292
const pointerType = 'touch';
293
const target = createEventTarget(ref.current);
294
+ const button = buttonType.primary;
295
const buttons = buttonsType.primary;
291
- target.pointerdown({buttons, pointerId: 1, pointerType});
296
+ target.pointerdown({button, buttons, pointerId: 1, pointerType});
297
expect(onTapStart).toHaveBeenCalledTimes(1);
298
if (hasPointerEvents) {
294
- target.pointerdown({buttons, pointerId: 2, pointerType});
299
+ target.pointerdown({button, buttons, pointerId: 2, pointerType});
300
} else {
301
// TouchEvents
302
target.pointerdown([{pointerId: 1}, {pointerId: 2}]);
@@ -301,29 +306,67 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
306
307
testWithPointerType('ignored buttons and modifiers', pointerType => {
308
const target = createEventTarget(ref.current);
304
- const {auxiliary, eraser, primary, secondary} = buttonsType;
309
if (pointerType !== 'touch') {
310
// right-click
307
- target.pointerdown({buttons: secondary, pointerType});
311
+ target.pointerdown({
312
+ button: buttonType.secondary,
313
+ buttons: buttonsType.secondary,
314
+ pointerType,
315
+ });
316
target.pointerup();
317
// middle-click
310
- target.pointerdown({buttons: auxiliary, pointerType});
318
+ target.pointerdown({
319
+ button: buttonType.auxiliary,
320
+ buttons: buttonsType.auxiliary,
321
+ pointerType,
322
+ });
323
+ target.pointerup();
324
+ // virtual middle-click with misleading 'buttons' value
325
+ target.pointerdown({
326
+ button: buttonType.auxiliary,
327
+ buttons: 0,
328
+ pointerType,
329
+ });
330
target.pointerup();
331
// pen eraser
313
- target.pointerdown({buttons: eraser, pointerType});
332
+ target.pointerdown({
333
+ button: buttonType.eraser,
334
+ buttons: buttonsType.eraser,
335
+ pointerType,
336
+ });
337
target.pointerup();
338
}
339
// alt-click
317
- target.pointerdown({buttons: primary, altKey: true, pointerType});
340
+ target.pointerdown({
341
+ button: buttonType.primary,
342
+ buttons: buttonsType.primary,
343
+ altKey: true,
344
+ pointerType,
345
+ });
346
target.pointerup();
347
// ctrl-click
320
- target.pointerdown({buttons: primary, ctrlKey: true, pointerType});
348
+ target.pointerdown({
349
+ button: buttonType.primary,
350
+ buttons: buttonsType.primary,
351
+ ctrlKey: true,
352
+ pointerType,
353
+ });
354
target.pointerup();
355
// meta-click
323
- target.pointerdown({buttons: primary, metaKey: true, pointerType});
356
+ target.pointerdown({
357
+ button: buttonType.primary,
358
+ buttons: buttonsType.primary,
359
+ metaKey: true,
360
+ pointerType,
361
+ });
362
target.pointerup();
363
// shift-click
326
- target.pointerdown({buttons: primary, shiftKey: true, pointerType});
364
+ target.pointerdown({
365
+ button: buttonType.primary,
366
+ buttons: buttonsType.primary,
367
+ shiftKey: true,
368
+ pointerType,
369
+ });
370
target.pointerup();
371
372
expect(onTapStart).toHaveBeenCalledTimes(0);
@@ -346,9 +389,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
389
390
testWithPointerType('pointer up', pointerType => {
391
const target = createEventTarget(ref.current);
392
+ const button = buttonType.primary;
393
const buttons = buttonsType.primary;
350
- target.pointerdown({buttons, pointerType});
394
+ target.pointerdown({button, buttons, pointerType});
395
target.pointerup({
396
+ button,
397
buttons,
398
pageX: 10,
399
pageY: 10,
@@ -424,11 +469,13 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
469
const pointerType = 'touch';
470
const target = createEventTarget(ref.current);
471
const offTarget = createEventTarget(container);
472
+ const button = buttonType.primary;
473
const buttons = buttonsType.primary;
474
429
- target.pointerdown({buttons, pointerId: 1, pointerType});
430
- offTarget.pointerdown({buttons, pointerId: 2, pointerType});
475
+ target.pointerdown({button, buttons, pointerId: 1, pointerType});
476
+ offTarget.pointerdown({button, buttons, pointerId: 2, pointerType});
477
offTarget.pointerup({
478
+ button,
479
buttons,
480
pageX: 10,
481
pageY: 10,
@@ -443,28 +490,57 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
490
491
test('ignored buttons and modifiers', () => {
492
const target = createEventTarget(ref.current);
446
- const primary = buttonsType.primary;
493
// right-click
448
- target.pointerdown({buttons: buttonsType.secondary});
449
- target.pointerup({buttons: buttonsType.secondary});
494
+ target.pointerdown({
495
+ button: buttonType.secondary,
496
+ buttons: buttonsType.secondary,
497
+ });
498
+ target.pointerup({
499
+ button: buttonType.secondary,
500
+ buttons: buttonsType.secondary,
501
+ });
502
// middle-click
451
- target.pointerdown({buttons: buttonsType.auxiliary});
452
- target.pointerup({buttons: buttonsType.auxiliary});
503
+ target.pointerdown({
504
+ button: buttonType.auxiliary,
505
+ buttons: buttonsType.auxiliary,
506
+ });
507
+ target.pointerup({
508
+ button: buttonType.auxiliary,
509
+ buttons: buttonsType.auxiliary,
510
+ });
511
// pen eraser
454
- target.pointerdown({buttons: buttonsType.eraser});
455
- target.pointerup({buttons: buttonsType.eraser});
512
+ target.pointerdown({
513
+ button: buttonType.eraser,
514
+ buttons: buttonsType.eraser,
515
+ });
516
+ target.pointerup({
517
+ button: buttonType.eraser,
518
+ buttons: buttonsType.eraser,
519
+ });
520
// alt-click
457
- target.pointerdown({buttons: primary});
458
- target.pointerup({altKey: true});
521
+ target.pointerdown({
522
+ button: buttonType.primary,
523
+ buttons: buttonsType.primary,
524
+ });
525
+ target.pointerup({altKey: true, button: buttonType.primary});
526
// ctrl-click
460
- target.pointerdown({buttons: primary});
461
- target.pointerup({ctrlKey: true});
527
+ target.pointerdown({
528
+ button: buttonType.primary,
529
+ buttons: buttonsType.primary,
530
+ });
531
+ target.pointerup({ctrlKey: true, button: buttonType.primary});
532
// meta-click
463
- target.pointerdown({buttons: primary});
464
- target.pointerup({metaKey: true});
533
+ target.pointerdown({
534
+ button: buttonType.primary,
535
+ buttons: buttonsType.primary,
536
+ });
537
+ target.pointerup({metaKey: true, button: buttonType.primary});
538
// shift-click
466
- target.pointerdown({buttons: primary});
467
- target.pointerup({shiftKey: true});
539
+ target.pointerdown({
540
+ button: buttonType.primary,
541
+ buttons: buttonsType.primary,
542
+ });
543
+ target.pointerup({shiftKey: true, button: buttonType.primary});
544
545
expect(onTapEnd).toHaveBeenCalledTimes(0);
546
});
@@ -560,9 +636,10 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
636
const pointerType = 'touch';
637
const target = createEventTarget(ref.current);
638
const offTarget = createEventTarget(container);
639
+ const button = buttonType.primary;
640
const buttons = buttonsType.primary;
564
- target.pointerdown({buttons, pointerId: 1, pointerType});
565
- offTarget.pointerdown({buttons, pointerId: 2, pointerType});
641
+ target.pointerdown({button, buttons, pointerId: 1, pointerType});
642
+ offTarget.pointerdown({button, buttons, pointerId: 2, pointerType});
643
target.pointermove({pointerId: 1, pointerType, x: 10, y: 10});
644
expect(onTapUpdate).toHaveBeenCalledTimes(1);
645
offTarget.pointermove({pointerId: 2, pointerType, x: 10, y: 10});
@@ -691,10 +768,11 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
768
test('second pointer on target', () => {
769
const pointerType = 'touch';
770
const target = createEventTarget(ref.current);
771
+ const button = buttonType.primary;
772
const buttons = buttonsType.primary;
695
- target.pointerdown({buttons, pointerId: 1, pointerType});
773
+ target.pointerdown({button, buttons, pointerId: 1, pointerType});
774
if (hasPointerEvents) {
697
- target.pointerdown({buttons, pointerId: 2, pointerType});
775
+ target.pointerdown({button, buttons, pointerId: 2, pointerType});
776
} else {
777
// TouchEvents
778
target.pointerdown([{pointerId: 1}, {pointerId: 2}]);
@@ -707,9 +785,10 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
785
const pointerType = 'touch';
786
const target = createEventTarget(ref.current);
787
const offTarget = createEventTarget(container);
788
+ const button = buttonType.primary;
789
const buttons = buttonsType.primary;
711
- target.pointerdown({buttons, pointerId: 1, pointerType});
712
- offTarget.pointerdown({buttons, pointerId: 2, pointerType});
790
+ target.pointerdown({button, buttons, pointerId: 1, pointerType});
791
+ offTarget.pointerdown({button, buttons, pointerId: 2, pointerType});
792
expect(onTapCancel).toHaveBeenCalledTimes(0);
793
});
794
}
@@ -728,19 +807,20 @@ describeWithPointerEvent('Tap responder', hasPointerEvents => {
807
808
test('ignored modifiers', () => {
809
const target = createEventTarget(ref.current);
731
- const primary = buttonsType.primary;
810
+ const button = buttonType.primary;
811
+ const buttons = buttonsType.primary;
812
// alt-click
733
- target.pointerdown({buttons: primary});
734
- target.pointerup({altKey: true});
813
+ target.pointerdown({button, buttons});
814
+ target.pointerup({altKey: true, button});
815
// ctrl-click
736
- target.pointerdown({buttons: primary});
737
- target.pointerup({ctrlKey: true});
816
+ target.pointerdown({button, buttons});
817
+ target.pointerup({ctrlKey: true, button});
818
// meta-click
739
- target.pointerdown({buttons: primary});
740
- target.pointerup({metaKey: true});
819
+ target.pointerdown({button, buttons});
820
+ target.pointerup({metaKey: true, button});
821
// shift-click
742
- target.pointerdown({buttons: primary});
743
- target.pointerup({shiftKey: true});
822
+ target.pointerdown({buttons});
823
+ target.pointerup({shiftKey: true, button});
824
825
expect(onTapCancel).toHaveBeenCalledTimes(4);
826
});
packages/react-interactions/events/src/dom/testing-library/domEnvironment.js
+28
@@ -64,6 +64,34 @@ export const platform = {
64
},
65
};
66
67
+/**
68
+ * Button property
69
+ * This property only guarantees to indicate which buttons are pressed during events caused by pressing or
70
+ * releasing one or multiple buttons. As such, it is not reliable for events such as 'mouseenter', 'mouseleave',
71
+ * 'mouseover', 'mouseout' or 'mousemove'. Furthermore, the semantics differ for PointerEvent, where the value
72
+ * for 'pointermove' will always be -1.
73
+ */
74
+
75
+export const buttonType = {
76
+ // no change since last event
77
+ none: -1,
78
+ // left-mouse
79
+ // touch contact
80
+ // pen contact
81
+ primary: 0,
82
+ // right-mouse
83
+ // pen barrel button
84
+ secondary: 2,
85
+ // middle mouse
86
+ auxiliary: 1,
87
+ // back mouse
88
+ back: 3,
89
+ // forward mouse
90
+ forward: 4,
91
+ // pen eraser
92
+ eraser: 5,
93
+};
94
+
95
/**
96
* Buttons bitmask
97
*/
packages/react-interactions/events/src/dom/testing-library/domEventSequences.js
+33
-10
@@ -10,7 +10,12 @@
10
'use strict';
11
12
import * as domEvents from './domEvents';
13
-import {buttonsType, hasPointerEvent, platform} from './domEnvironment';
13
+import {
14
+ buttonType,
15
+ buttonsType,
16
+ hasPointerEvent,
17
+ platform,
18
+} from './domEnvironment';
19
20
function emptyFunction() {}
21
@@ -33,31 +38,45 @@ export function contextmenu(
38
if (pointerType === 'touch') {
39
if (hasPointerEvent()) {
40
dispatch(
36
- domEvents.pointerdown({buttons: buttonsType.primary, pointerType}),
41
+ domEvents.pointerdown({
42
+ button: buttonType.primary,
43
+ buttons: buttonsType.primary,
44
+ pointerType,
45
+ }),
46
);
47
}
48
dispatch(domEvents.touchstart());
49
dispatch(
41
- domEvents.contextmenu({buttons: buttonsType.none, preventDefault}),
50
+ domEvents.contextmenu({
51
+ button: buttonType.primary,
52
+ buttons: buttonsType.none,
53
+ preventDefault,
54
+ }),
55
);
56
} else if (pointerType === 'mouse') {
57
if (modified === true) {
58
+ const button = buttonType.primary;
59
const buttons = buttonsType.primary;
60
const ctrlKey = true;
61
if (hasPointerEvent()) {
48
- dispatch(domEvents.pointerdown({buttons, ctrlKey, pointerType}));
62
+ dispatch(
63
+ domEvents.pointerdown({button, buttons, ctrlKey, pointerType}),
64
+ );
65
}
50
- dispatch(domEvents.mousedown({buttons, ctrlKey}));
66
+ dispatch(domEvents.mousedown({button, buttons, ctrlKey}));
67
if (platform.get() === 'mac') {
52
- dispatch(domEvents.contextmenu({buttons, ctrlKey, preventDefault}));
68
+ dispatch(
69
+ domEvents.contextmenu({button, buttons, ctrlKey, preventDefault}),
70
+ );
71
}
72
} else {
73
+ const button = buttonType.secondary;
74
const buttons = buttonsType.secondary;
75
if (hasPointerEvent()) {
57
- dispatch(domEvents.pointerdown({buttons, pointerType}));
76
+ dispatch(domEvents.pointerdown({button, buttons, pointerType}));
77
}
59
- dispatch(domEvents.mousedown({buttons}));
60
- dispatch(domEvents.contextmenu({buttons, preventDefault}));
78
+ dispatch(domEvents.mousedown({button, buttons}));
79
+ dispatch(domEvents.contextmenu({button, buttons, preventDefault}));
80
}
81
}
82
}
@@ -84,7 +103,11 @@ export function pointerdown(target, defaultPayload) {
103
// Arrays are for multi-touch only
104
dispatch(domEvents.touchstart(defaultPayload));
105
} else {
87
- const payload = {buttons: buttonsType.primary, ...defaultPayload};
106
+ const payload = {
107
+ button: buttonType.primary,
108
+ buttons: buttonsType.primary,
109
+ ...defaultPayload,
110
+ };
111
if (pointerType === 'mouse') {
112
if (hasPointerEvent()) {
113
dispatch(domEvents.pointerover(payload));
packages/react-interactions/events/src/dom/testing-library/domEvents.js
+23
-5
@@ -9,7 +9,7 @@
9
10
'use strict';
11
12
-import {buttonsType} from './domEnvironment';
12
+import {buttonType, buttonsType} from './domEnvironment';
13
14
/**
15
* Native event object mocks for higher-level events.
@@ -65,6 +65,7 @@ function createPointerEvent(
65
type,
66
{
67
altKey = false,
68
+ button = buttonType.none,
69
buttons = buttonsType.none,
70
ctrlKey = false,
71
detail = 1,
@@ -98,6 +99,7 @@ function createPointerEvent(
99
100
return createEvent(type, {
101
altKey,
102
+ button,
103
buttons,
104
clientX: x,
105
clientY: y,
@@ -164,6 +166,7 @@ function createMouseEvent(
166
type,
167
{
168
altKey = false,
169
+ button = buttonType.none,
170
buttons = buttonsType.none,
171
ctrlKey = false,
172
detail = 1,
@@ -187,6 +190,7 @@ function createMouseEvent(
190
191
return createEvent(type, {
192
altKey,
193
+ button,
194
buttons,
195
clientX: x,
196
clientY: y,
@@ -297,7 +301,10 @@ export function blur({relatedTarget} = {}) {
301
}
302
303
export function click(payload) {
300
- return createMouseEvent('click', payload);
304
+ return createMouseEvent('click', {
305
+ button: buttonType.primary,
306
+ ...payload,
307
+ });
308
}
309
310
export function contextmenu(payload) {
@@ -383,6 +390,7 @@ export function pointercancel(payload) {
390
export function pointerdown(payload) {
391
const isTouch = payload != null && payload.pointerType === 'touch';
392
return createPointerEvent('pointerdown', {
393
+ button: buttonType.primary,
394
buttons: buttonsType.primary,
395
pressure: isTouch ? 1 : 0.5,
396
...payload,
@@ -398,7 +406,10 @@ export function pointerleave(payload) {
406
}
407
408
export function pointermove(payload) {
401
- return createPointerEvent('pointermove', payload);
409
+ return createPointerEvent('pointermove', {
410
+ ...payload,
411
+ button: buttonType.none,
412
+ });
413
}
414
415
export function pointerout(payload) {
@@ -411,6 +422,7 @@ export function pointerover(payload) {
422
423
export function pointerup(payload) {
424
return createPointerEvent('pointerup', {
425
+ button: buttonType.primary,
426
...payload,
427
buttons: buttonsType.none,
428
pressure: 0,
@@ -422,13 +434,18 @@ export function pointerup(payload) {
434
*/
435
436
export function mousedown(payload) {
425
- // The value of 'buttons' for 'mousedown' must not be 0
437
+ // The value of 'button' and 'buttons' for 'mousedown' must not be none.
438
+ const button =
439
+ payload == null || payload.button === buttonType.none
440
+ ? buttonType.primary
441
+ : payload.button;
442
const buttons =
427
- payload == null || payload.buttons === 0
443
+ payload == null || payload.buttons === buttonsType.none
444
? buttonsType.primary
445
: payload.buttons;
446
return createMouseEvent('mousedown', {
447
...payload,
448
+ button,
449
buttons,
450
});
451
}
@@ -455,6 +472,7 @@ export function mouseover(payload) {
472
473
export function mouseup(payload) {
474
return createMouseEvent('mouseup', {
475
+ button: buttonType.primary,
476
...payload,
477
buttons: buttonsType.none,
478
});
packages/react-interactions/events/src/dom/testing-library/index.js
+2
@@ -12,6 +12,7 @@
12
import * as domEvents from './domEvents';
13
import * as domEventSequences from './domEventSequences';
14
import {
15
+ buttonType,
16
buttonsType,
17
hasPointerEvent,
18
setPointerEvent,
@@ -160,6 +161,7 @@ function testWithPointerType(message, testFn) {
161
}
162
163
export {
164
+ buttonType,
165
buttonsType,
166
createEventTarget,
167
describeWithPointerEvent,