diff --git a/packages/react-events/src/dom/Press.js b/packages/react-events/src/dom/Press.js
index aa39d91a35ca8..40251331f94bc 100644
--- a/packages/react-events/src/dom/Press.js
+++ b/packages/react-events/src/dom/Press.js
@@ -95,10 +95,14 @@ type PressEvent = {|
shiftKey: boolean,
|};
+const hasPointerEvents =
+ typeof window !== 'undefined' && window.PointerEvent !== undefined;
+
const isMac =
typeof window !== 'undefined' && window.navigator != null
? /^Mac/.test(window.navigator.platform)
: false;
+
const DEFAULT_PRESS_RETENTION_OFFSET = {
bottom: 20,
top: 20,
@@ -106,37 +110,32 @@ const DEFAULT_PRESS_RETENTION_OFFSET = {
right: 20,
};
-const targetEventTypes = [
- 'keydown_active',
- // We need to preventDefault on pointerdown for mouse/pen events
- // that are in hit target area but not the element area.
- 'pointerdown_active',
- 'click_active',
-];
-const rootEventTypes = [
- 'click',
- 'keyup',
- 'pointerup',
- 'pointermove',
- 'scroll',
- 'pointercancel',
- // We listen to this here so stopPropagation can
- // block other mouseup events used internally
- 'mouseup_active',
- 'touchend',
-];
-
-// If PointerEvents is not supported (e.g., Safari), also listen to touch and mouse events.
-if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
- targetEventTypes.push('touchstart', 'mousedown');
- rootEventTypes.push(
- 'mousemove',
- 'touchmove',
- 'touchcancel',
- // Used as a 'cancel' signal for mouse interactions
- 'dragstart',
- );
-}
+const targetEventTypes = hasPointerEvents
+ ? [
+ 'keydown_active',
+ // We need to preventDefault on pointerdown for mouse/pen events
+ // that are in hit target area but not the element area.
+ 'pointerdown_active',
+ 'click_active',
+ ]
+ : ['keydown_active', 'touchstart', 'mousedown', 'click_active'];
+
+const rootEventTypes = hasPointerEvents
+ ? ['pointerup', 'pointermove', 'pointercancel', 'click', 'keyup', 'scroll']
+ : [
+ 'click',
+ 'keyup',
+ 'scroll',
+ 'mousemove',
+ 'touchmove',
+ 'touchcancel',
+ // Used as a 'cancel' signal for mouse interactions
+ 'dragstart',
+ // We listen to this here so stopPropagation can
+ // block other mouseup events used internally
+ 'mouseup_active',
+ 'touchend',
+ ];
function isFunction(obj): boolean {
return typeof obj === 'function';
@@ -539,7 +538,7 @@ const pressResponderImpl = {
}
state.shouldPreventClick = false;
- if (isPointerEvent || isTouchEvent) {
+ if (isTouchEvent) {
state.ignoreEmulatedMouseEvents = true;
} else if (isKeyboardEvent) {
// Ignore unrelated key events
@@ -676,6 +675,7 @@ const pressResponderImpl = {
if (state.isPressWithinResponderRegion) {
if (isPressed) {
const onPressMove = props.onPressMove;
+
if (isFunction(onPressMove)) {
dispatchEvent(
event,
@@ -777,6 +777,7 @@ const pressResponderImpl = {
);
}
}
+
if (state.isPressWithinResponderRegion && button !== 1) {
dispatchEvent(
event,
diff --git a/packages/react-events/src/dom/__tests__/Focus-test.internal.js b/packages/react-events/src/dom/__tests__/Focus-test.internal.js
index a432f64091cfb..316bc9f19dcde 100644
--- a/packages/react-events/src/dom/__tests__/Focus-test.internal.js
+++ b/packages/react-events/src/dom/__tests__/Focus-test.internal.js
@@ -15,8 +15,8 @@ import {
keydown,
setPointerEvent,
platform,
- dispatchPointerPressDown,
- dispatchPointerPressRelease,
+ dispatchPointerDown,
+ dispatchPointerUp,
} from '../test-utils';
let React;
@@ -138,8 +138,8 @@ describe.each(table)('Focus responder', hasPointerEvents => {
it('is called with the correct pointerType: mouse', () => {
const target = ref.current;
- dispatchPointerPressDown(target, {pointerType: 'mouse'});
- dispatchPointerPressRelease(target, {pointerType: 'mouse'});
+ dispatchPointerDown(target, {pointerType: 'mouse'});
+ dispatchPointerUp(target, {pointerType: 'mouse'});
expect(onFocus).toHaveBeenCalledTimes(1);
expect(onFocus).toHaveBeenCalledWith(
expect.objectContaining({pointerType: 'mouse'}),
@@ -148,8 +148,8 @@ describe.each(table)('Focus responder', hasPointerEvents => {
it('is called with the correct pointerType: touch', () => {
const target = ref.current;
- dispatchPointerPressDown(target, {pointerType: 'touch'});
- dispatchPointerPressRelease(target, {pointerType: 'touch'});
+ dispatchPointerDown(target, {pointerType: 'touch'});
+ dispatchPointerUp(target, {pointerType: 'touch'});
expect(onFocus).toHaveBeenCalledTimes(1);
expect(onFocus).toHaveBeenCalledWith(
expect.objectContaining({pointerType: 'touch'}),
@@ -159,8 +159,8 @@ describe.each(table)('Focus responder', hasPointerEvents => {
if (hasPointerEvents) {
it('is called with the correct pointerType: pen', () => {
const target = ref.current;
- dispatchPointerPressDown(target, {pointerType: 'pen'});
- dispatchPointerPressRelease(target, {pointerType: 'pen'});
+ dispatchPointerDown(target, {pointerType: 'pen'});
+ dispatchPointerUp(target, {pointerType: 'pen'});
expect(onFocus).toHaveBeenCalledTimes(1);
expect(onFocus).toHaveBeenCalledWith(
expect.objectContaining({pointerType: 'pen'}),
@@ -278,7 +278,7 @@ describe.each(table)('Focus responder', hasPointerEvents => {
expect(onFocusVisibleChange).toHaveBeenCalledTimes(1);
expect(onFocusVisibleChange).toHaveBeenCalledWith(true);
// then use pointer on the target, focus should no longer be visible
- dispatchPointerPressDown(target);
+ dispatchPointerDown(target);
expect(onFocusVisibleChange).toHaveBeenCalledTimes(2);
expect(onFocusVisibleChange).toHaveBeenCalledWith(false);
// onFocusVisibleChange should not be called again
@@ -288,9 +288,9 @@ describe.each(table)('Focus responder', hasPointerEvents => {
it('is not called after "focus" and "blur" events without keyboard', () => {
const target = ref.current;
- dispatchPointerPressDown(target);
- dispatchPointerPressRelease(target);
- dispatchPointerPressDown(container);
+ dispatchPointerDown(target);
+ dispatchPointerUp(target);
+ dispatchPointerDown(container);
target.dispatchEvent(blur({relatedTarget: container}));
expect(onFocusVisibleChange).toHaveBeenCalledTimes(0);
});
diff --git a/packages/react-events/src/dom/__tests__/FocusWithin-test.internal.js b/packages/react-events/src/dom/__tests__/FocusWithin-test.internal.js
index e2340a21f669f..ff54b6f3838e1 100644
--- a/packages/react-events/src/dom/__tests__/FocusWithin-test.internal.js
+++ b/packages/react-events/src/dom/__tests__/FocusWithin-test.internal.js
@@ -14,8 +14,8 @@ import {
focus,
keydown,
setPointerEvent,
- dispatchPointerPressDown,
- dispatchPointerPressRelease,
+ dispatchPointerDown,
+ dispatchPointerUp,
} from '../test-utils';
let React;
@@ -203,7 +203,7 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
// then use pointer on the next target, focus should no longer be visible
- dispatchPointerPressDown(innerTarget2);
+ dispatchPointerDown(innerTarget2);
innerTarget1.dispatchEvent(blur({relatedTarget: innerTarget2}));
innerTarget2.dispatchEvent(focus());
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
@@ -215,7 +215,7 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(3);
expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
// then use pointer on the target, focus should no longer be visible
- dispatchPointerPressDown(innerTarget1);
+ dispatchPointerDown(innerTarget1);
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(4);
expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
// onFocusVisibleChange should not be called again
@@ -225,8 +225,8 @@ describe.each(table)('FocusWithin responder', hasPointerEvents => {
it('is not called after "focus" and "blur" events without keyboard', () => {
const innerTarget = innerRef.current;
- dispatchPointerPressDown(innerTarget);
- dispatchPointerPressRelease(innerTarget);
+ dispatchPointerDown(innerTarget);
+ dispatchPointerUp(innerTarget);
innerTarget.dispatchEvent(blur({relatedTarget: container}));
expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(0);
});
diff --git a/packages/react-events/src/dom/__tests__/Hover-test.internal.js b/packages/react-events/src/dom/__tests__/Hover-test.internal.js
index eb9eab90c3029..2198e74551156 100644
--- a/packages/react-events/src/dom/__tests__/Hover-test.internal.js
+++ b/packages/react-events/src/dom/__tests__/Hover-test.internal.js
@@ -213,7 +213,8 @@ describe.each(table)('Hover responder', hasPointerEvents => {
const target = ref.current;
dispatchPointerHoverEnter(target);
- dispatchPointerHoverMove(target, {from: {x: 0, y: 0}, to: {x: 1, y: 1}});
+ dispatchPointerHoverMove(target, {x: 0, y: 0});
+ dispatchPointerHoverMove(target, {x: 1, y: 1});
expect(onHoverMove).toHaveBeenCalledTimes(2);
expect(onHoverMove).toHaveBeenCalledWith(
expect.objectContaining({type: 'hovermove'}),
@@ -317,10 +318,8 @@ describe.each(table)('Hover responder', hasPointerEvents => {
const target = ref.current;
dispatchPointerHoverEnter(target, {x: 10, y: 10});
- dispatchPointerHoverMove(target, {
- from: {x: 10, y: 10},
- to: {x: 20, y: 20},
- });
+ dispatchPointerHoverMove(target, {x: 10, y: 10});
+ dispatchPointerHoverMove(target, {x: 20, y: 20});
dispatchPointerHoverExit(target, {x: 20, y: 20});
expect(eventLog).toEqual([
diff --git a/packages/react-events/src/dom/__tests__/Press-test.internal.js b/packages/react-events/src/dom/__tests__/Press-test.internal.js
index de87adde0dc53..a6a42a5d011a3 100644
--- a/packages/react-events/src/dom/__tests__/Press-test.internal.js
+++ b/packages/react-events/src/dom/__tests__/Press-test.internal.js
@@ -9,6 +9,21 @@
'use strict';
+import {
+ click,
+ dispatchPointerCancel,
+ dispatchPointerDown,
+ dispatchPointerUp,
+ dispatchPointerHoverMove,
+ dispatchPointerMove,
+ keydown,
+ keyup,
+ scroll,
+ pointerdown,
+ pointerup,
+ setPointerEvent,
+} from '../test-utils';
+
let React;
let ReactFeatureFlags;
let ReactDOM;
@@ -16,39 +31,9 @@ let PressResponder;
let usePressResponder;
let Scheduler;
-const createEvent = (type, data) => {
- const event = document.createEvent('CustomEvent');
- event.initCustomEvent(type, true, true);
- if (data != null) {
- Object.entries(data).forEach(([key, value]) => {
- event[key] = value;
- });
- }
- return event;
-};
-
-function createTouchEvent(type, id, data) {
- return createEvent(type, {
- changedTouches: [
- {
- ...data,
- identifier: id,
- },
- ],
- targetTouches: [
- {
- ...data,
- identifier: id,
- },
- ],
- });
-}
-
-const createKeyboardEvent = (type, data) => {
- return createEvent(type, data);
-};
-
-function init() {
+function initializeModules(hasPointerEvents) {
+ jest.resetModules();
+ setPointerEvent(hasPointerEvents);
ReactFeatureFlags = require('shared/ReactFeatureFlags');
ReactFeatureFlags.enableFlareAPI = true;
React = require('react');
@@ -58,12 +43,23 @@ function init() {
Scheduler = require('scheduler');
}
-describe('Event responder: Press', () => {
+function removePressMoveStrings(eventString) {
+ if (eventString === 'onPressMove') {
+ return false;
+ }
+ return true;
+}
+
+const forcePointerEvents = true;
+const environmentTable = [[forcePointerEvents], [!forcePointerEvents]];
+
+const pointerTypesTable = [['mouse'], ['touch']];
+
+describe.each(environmentTable)('Press responder', hasPointerEvents => {
let container;
beforeEach(() => {
- jest.resetModules();
- init();
+ initializeModules(hasPointerEvents);
container = document.createElement('div');
document.body.appendChild(container);
});
@@ -92,11 +88,13 @@ describe('Event responder: Press', () => {
return
;
};
ReactDOM.render(, container);
+ document.elementFromPoint = () => ref.current;
});
- it('prevents custom events being dispatched', () => {
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(createEvent('pointerup'));
+ it('does not call callbacks', () => {
+ const target = ref.current;
+ dispatchPointerDown(target);
+ dispatchPointerUp(target);
expect(onPressStart).not.toBeCalled();
expect(onPress).not.toBeCalled();
expect(onPressEnd).not.toBeCalled();
@@ -116,27 +114,22 @@ describe('Event responder: Press', () => {
return ;
};
ReactDOM.render(, container);
+ document.elementFromPoint = () => ref.current;
});
- it('is called after "pointerdown" event', () => {
- ref.current.dispatchEvent(
- createEvent('pointerdown', {pointerType: 'pen'}),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- expect(onPressStart).toHaveBeenCalledTimes(1);
- expect(onPressStart).toHaveBeenCalledWith(
- expect.objectContaining({pointerType: 'pen', type: 'pressstart'}),
- );
- });
+ it.each(pointerTypesTable)(
+ 'is called after pointer down: %s',
+ pointerType => {
+ dispatchPointerDown(ref.current, {pointerType});
+ expect(onPressStart).toHaveBeenCalledTimes(1);
+ expect(onPressStart).toHaveBeenCalledWith(
+ expect.objectContaining({pointerType, type: 'pressstart'}),
+ );
+ },
+ );
- it('is called after auxillary-button "pointerdown" event', () => {
- ref.current.dispatchEvent(
- createEvent('pointerdown', {button: 1, pointerType: 'mouse'}),
- );
+ it('is called after auxillary-button pointer down', () => {
+ dispatchPointerDown(ref.current, {button: 1, pointerType: 'mouse'});
expect(onPressStart).toHaveBeenCalledTimes(1);
expect(onPressStart).toHaveBeenCalledWith(
expect.objectContaining({
@@ -148,64 +141,38 @@ describe('Event responder: Press', () => {
});
it('is not called after "pointermove" following auxillary-button press', () => {
- ref.current.getBoundingClientRect = () => ({
+ const target = ref.current;
+ target.getBoundingClientRect = () => ({
top: 0,
left: 0,
bottom: 100,
right: 100,
});
- ref.current.dispatchEvent(
- createEvent('pointerdown', {
- button: 1,
- pointerType: 'mouse',
- clientX: 50,
- clientY: 50,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointerup', {
- button: 1,
- pointerType: 'mouse',
- clientX: 50,
- clientY: 50,
- }),
- );
- container.dispatchEvent(
- createEvent('pointermove', {
- button: 1,
- pointerType: 'mouse',
- clientX: 110,
- clientY: 110,
- }),
- );
- container.dispatchEvent(
- createEvent('pointermove', {
- button: 1,
- pointerType: 'mouse',
- clientX: 50,
- clientY: 50,
- }),
- );
- expect(onPressStart).toHaveBeenCalledTimes(1);
- });
-
- it('ignores browser emulated events', () => {
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(createEvent('touchstart'));
- ref.current.dispatchEvent(createEvent('mousedown'));
+ dispatchPointerDown(target, {
+ button: 1,
+ pointerType: 'mouse',
+ });
+ dispatchPointerUp(target, {
+ button: 1,
+ pointerType: 'mouse',
+ });
+ dispatchPointerHoverMove(target, {x: 110, y: 110});
+ dispatchPointerHoverMove(target, {x: 50, y: 50});
expect(onPressStart).toHaveBeenCalledTimes(1);
});
it('ignores any events not caused by primary/auxillary-click or touch/pen contact', () => {
- ref.current.dispatchEvent(createEvent('pointerdown', {button: 5}));
- ref.current.dispatchEvent(createEvent('mousedown', {button: 2}));
+ const target = ref.current;
+ dispatchPointerDown(target, {button: 2});
+ dispatchPointerDown(target, {button: 5});
expect(onPressStart).toHaveBeenCalledTimes(0);
});
it('is called once after "keydown" events for Enter', () => {
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
+ const target = ref.current;
+ target.dispatchEvent(keydown({key: 'Enter'}));
+ target.dispatchEvent(keydown({key: 'Enter'}));
+ target.dispatchEvent(keydown({key: 'Enter'}));
expect(onPressStart).toHaveBeenCalledTimes(1);
expect(onPressStart).toHaveBeenCalledWith(
expect.objectContaining({pointerType: 'keyboard', type: 'pressstart'}),
@@ -213,14 +180,11 @@ describe('Event responder: Press', () => {
});
it('is called once after "keydown" events for Spacebar', () => {
+ const target = ref.current;
const preventDefault = jest.fn();
- ref.current.dispatchEvent(
- createKeyboardEvent('keydown', {key: ' ', preventDefault}),
- );
+ target.dispatchEvent(keydown({key: ' ', preventDefault}));
expect(preventDefault).toBeCalled();
- ref.current.dispatchEvent(createKeyboardEvent('keypress', {key: ' '}));
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: ' '}));
- ref.current.dispatchEvent(createKeyboardEvent('keypress', {key: ' '}));
+ target.dispatchEvent(keydown({key: ' ', preventDefault}));
expect(onPressStart).toHaveBeenCalledTimes(1);
expect(onPressStart).toHaveBeenCalledWith(
expect.objectContaining({
@@ -231,34 +195,9 @@ describe('Event responder: Press', () => {
});
it('is not called after "keydown" for other keys', () => {
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'a'}));
+ ref.current.dispatchEvent(keydown({key: 'a'}));
expect(onPressStart).not.toBeCalled();
});
-
- // No PointerEvent fallbacks
- it('is called after "mousedown" event', () => {
- ref.current.dispatchEvent(
- createEvent('mousedown', {
- button: 0,
- }),
- );
- expect(onPressStart).toHaveBeenCalledTimes(1);
- expect(onPressStart).toHaveBeenCalledWith(
- expect.objectContaining({pointerType: 'mouse', type: 'pressstart'}),
- );
- });
-
- it('is called after "touchstart" event', () => {
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- expect(onPressStart).toHaveBeenCalledTimes(1);
- expect(onPressStart).toHaveBeenCalledWith(
- expect.objectContaining({pointerType: 'touch', type: 'pressstart'}),
- );
- });
});
describe('onPressEnd', () => {
@@ -274,36 +213,26 @@ describe('Event responder: Press', () => {
return ;
};
ReactDOM.render(, container);
+ document.elementFromPoint = () => ref.current;
});
- it('is called after "pointerup" event', () => {
- ref.current.dispatchEvent(
- createEvent('pointerdown', {pointerType: 'pen'}),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(createEvent('pointerup', {pointerType: 'pen'}));
- expect(onPressEnd).toHaveBeenCalledTimes(1);
- expect(onPressEnd).toHaveBeenCalledWith(
- expect.objectContaining({pointerType: 'pen', type: 'pressend'}),
- );
- });
+ it.each(pointerTypesTable)(
+ 'is called after pointer up: %s',
+ pointerType => {
+ const target = ref.current;
+ dispatchPointerDown(target, {pointerType});
+ dispatchPointerUp(target, {pointerType});
+ expect(onPressEnd).toHaveBeenCalledTimes(1);
+ expect(onPressEnd).toHaveBeenCalledWith(
+ expect.objectContaining({pointerType, type: 'pressend'}),
+ );
+ },
+ );
- it('is called after auxillary-button "pointerup" event', () => {
- ref.current.dispatchEvent(
- createEvent('pointerdown', {button: 1, pointerType: 'mouse'}),
- );
- ref.current.dispatchEvent(
- createEvent('pointerup', {button: 1, pointerType: 'mouse'}),
- );
+ it('is called after auxillary-button pointer up', () => {
+ const target = ref.current;
+ dispatchPointerDown(target, {button: 1, pointerType: 'mouse'});
+ dispatchPointerUp(target, {button: 1, pointerType: 'mouse'});
expect(onPressEnd).toHaveBeenCalledTimes(1);
expect(onPressEnd).toHaveBeenCalledWith(
expect.objectContaining({
@@ -314,37 +243,12 @@ describe('Event responder: Press', () => {
);
});
- it('ignores browser emulated events', () => {
- ref.current.dispatchEvent(
- createEvent('pointerdown', {pointerType: 'touch'}),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointerup', {pointerType: 'touch'}),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(createEvent('mousedown'));
- ref.current.dispatchEvent(createEvent('mouseup'));
- ref.current.dispatchEvent(createEvent('click'));
- expect(onPressEnd).toHaveBeenCalledTimes(1);
- expect(onPressEnd).toHaveBeenCalledWith(
- expect.objectContaining({pointerType: 'touch', type: 'pressend'}),
- );
- });
-
it('is called after "keyup" event for Enter', () => {
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
+ const target = ref.current;
+ target.dispatchEvent(keydown({key: 'Enter'}));
// click occurs before keyup
- ref.current.dispatchEvent(createKeyboardEvent('click'));
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: 'Enter'}));
+ target.dispatchEvent(click());
+ target.dispatchEvent(keyup({key: 'Enter'}));
expect(onPressEnd).toHaveBeenCalledTimes(1);
expect(onPressEnd).toHaveBeenCalledWith(
expect.objectContaining({pointerType: 'keyboard', type: 'pressend'}),
@@ -352,8 +256,9 @@ describe('Event responder: Press', () => {
});
it('is called after "keyup" event for Spacebar', () => {
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: ' '}));
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: ' '}));
+ const target = ref.current;
+ target.dispatchEvent(keydown({key: ' '}));
+ target.dispatchEvent(keyup({key: ' '}));
expect(onPressEnd).toHaveBeenCalledTimes(1);
expect(onPressEnd).toHaveBeenCalledWith(
expect.objectContaining({pointerType: 'keyboard', type: 'pressend'}),
@@ -361,15 +266,17 @@ describe('Event responder: Press', () => {
});
it('is not called after "keyup" event for other keys', () => {
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: 'a'}));
+ const target = ref.current;
+ target.dispatchEvent(keydown({key: 'Enter'}));
+ target.dispatchEvent(keyup({key: 'a'}));
expect(onPressEnd).not.toBeCalled();
});
it('is called with keyboard modifiers', () => {
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
- ref.current.dispatchEvent(
- createKeyboardEvent('keyup', {
+ const target = ref.current;
+ target.dispatchEvent(keydown({key: 'Enter'}));
+ target.dispatchEvent(
+ keyup({
key: 'Enter',
metaKey: true,
ctrlKey: true,
@@ -388,41 +295,6 @@ describe('Event responder: Press', () => {
}),
);
});
-
- // No PointerEvent fallbacks
- it('is called after "mouseup" event', () => {
- ref.current.dispatchEvent(
- createEvent('mousedown', {
- button: 0,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('mouseup', {
- button: 0,
- }),
- );
- expect(onPressEnd).toHaveBeenCalledTimes(1);
- expect(onPressEnd).toHaveBeenCalledWith(
- expect.objectContaining({pointerType: 'mouse', type: 'pressend'}),
- );
- });
- it('is called after "touchend" event', () => {
- document.elementFromPoint = () => ref.current;
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- target: ref.current,
- }),
- );
- expect(onPressEnd).toHaveBeenCalledTimes(1);
- expect(onPressEnd).toHaveBeenCalledWith(
- expect.objectContaining({pointerType: 'touch', type: 'pressend'}),
- );
- });
});
describe('onPressChange', () => {
@@ -438,22 +310,27 @@ describe('Event responder: Press', () => {
return ;
};
ReactDOM.render(, container);
+ document.elementFromPoint = () => ref.current;
});
- it('is called after "pointerdown" and "pointerup" events', () => {
- ref.current.dispatchEvent(createEvent('pointerdown'));
- expect(onPressChange).toHaveBeenCalledTimes(1);
- expect(onPressChange).toHaveBeenCalledWith(true);
- ref.current.dispatchEvent(createEvent('pointerup'));
- expect(onPressChange).toHaveBeenCalledTimes(2);
- expect(onPressChange).toHaveBeenCalledWith(false);
- });
+ it.each(pointerTypesTable)(
+ 'is called after pointer down and up: %s',
+ pointerType => {
+ const target = ref.current;
+ dispatchPointerDown(target, {pointerType});
+ expect(onPressChange).toHaveBeenCalledTimes(1);
+ expect(onPressChange).toHaveBeenCalledWith(true);
+ dispatchPointerUp(target, {pointerType});
+ expect(onPressChange).toHaveBeenCalledTimes(2);
+ expect(onPressChange).toHaveBeenCalledWith(false);
+ },
+ );
it('is called after valid "keydown" and "keyup" events', () => {
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
+ ref.current.dispatchEvent(keydown({key: 'Enter'}));
expect(onPressChange).toHaveBeenCalledTimes(1);
expect(onPressChange).toHaveBeenCalledWith(true);
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: 'Enter'}));
+ ref.current.dispatchEvent(keyup({key: 'Enter'}));
expect(onPressChange).toHaveBeenCalledTimes(2);
expect(onPressChange).toHaveBeenCalledWith(false);
});
@@ -478,58 +355,33 @@ describe('Event responder: Press', () => {
bottom: 100,
right: 100,
});
+ document.elementFromPoint = () => ref.current;
});
- it('is called after "pointerup" event', () => {
- ref.current.dispatchEvent(
- createEvent('pointerdown', {pointerType: 'pen'}),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- clientX: 0,
- clientY: 0,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- target: ref.current,
- clientX: 0,
- clientY: 0,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointerup', {
- pointerType: 'pen',
- clientX: 0,
- clientY: 0,
- }),
- );
- expect(onPress).toHaveBeenCalledTimes(1);
- expect(onPress).toHaveBeenCalledWith(
- expect.objectContaining({pointerType: 'pen', type: 'press'}),
- );
- });
+ it.each(pointerTypesTable)(
+ 'is called after pointer up: %s',
+ pointerType => {
+ const target = ref.current;
+ dispatchPointerDown(target, {pointerType});
+ dispatchPointerUp(target, {pointerType, x: 10, y: 10});
+ expect(onPress).toHaveBeenCalledTimes(1);
+ expect(onPress).toHaveBeenCalledWith(
+ expect.objectContaining({pointerType, type: 'press'}),
+ );
+ },
+ );
it('is not called after auxillary-button press', () => {
- const Component = () => {
- const listener = usePressResponder({
- onPress,
- });
- return ;
- };
- ReactDOM.render(, container);
-
- ref.current.dispatchEvent(createEvent('pointerdown', {button: 1}));
- ref.current.dispatchEvent(
- createEvent('pointerup', {button: 1, clientX: 10, clientY: 10}),
- );
+ const target = ref.current;
+ dispatchPointerDown(target, {button: 1, pointerType: 'mouse'});
+ dispatchPointerUp(target, {button: 1, pointerType: 'mouse'});
expect(onPress).not.toHaveBeenCalled();
});
it('is called after valid "keyup" event', () => {
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
- ref.current.dispatchEvent(createKeyboardEvent('keyup', {key: 'Enter'}));
+ const target = ref.current;
+ target.dispatchEvent(keydown({key: 'Enter'}));
+ target.dispatchEvent(keyup({key: 'Enter'}));
expect(onPress).toHaveBeenCalledTimes(1);
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({pointerType: 'keyboard', type: 'press'}),
@@ -545,26 +397,21 @@ describe('Event responder: Press', () => {
return ;
};
ReactDOM.render(, container);
- inputRef.current.dispatchEvent(
- createKeyboardEvent('keydown', {key: 'Enter'}),
- );
- inputRef.current.dispatchEvent(
- createKeyboardEvent('keyup', {key: 'Enter'}),
- );
- inputRef.current.dispatchEvent(
- createKeyboardEvent('keydown', {key: ' '}),
- );
- inputRef.current.dispatchEvent(createKeyboardEvent('keyup', {key: ' '}));
+ const target = inputRef.current;
+ target.dispatchEvent(keydown({key: 'Enter'}));
+ target.dispatchEvent(keyup({key: 'Enter'}));
+ target.dispatchEvent(keydown({key: ' '}));
+ target.dispatchEvent(keyup({key: ' '}));
expect(onPress).not.toBeCalled();
});
it('is called with modifier keys', () => {
- ref.current.dispatchEvent(
- createEvent('pointerdown', {metaKey: true, pointerType: 'mouse'}),
- );
- ref.current.dispatchEvent(
- createEvent('pointerup', {metaKey: true, pointerType: 'mouse'}),
- );
+ const target = ref.current;
+ dispatchPointerDown(target, {metaKey: true, pointerType: 'mouse'});
+ dispatchPointerUp(target, {
+ metaKey: true,
+ pointerType: 'mouse',
+ });
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({
pointerType: 'mouse',
@@ -596,28 +443,19 @@ describe('Event responder: Press', () => {
bottom: 0,
top: 0,
});
- buttonRef.current.dispatchEvent(
- createEvent('pointerdown', {pointerType: 'mouse'}),
- );
- buttonRef.current.dispatchEvent(
- createEvent('pointerup', {pointerType: 'mouse'}),
- );
+ const target = buttonRef.current;
+ dispatchPointerDown(target, {pointerType: 'mouse'});
+ dispatchPointerUp(target, {pointerType: 'mouse'});
expect(onPress).toBeCalled();
});
-
- // No PointerEvent fallbacks
- // TODO: jsdom missing APIs
- // it('is called after "touchend" event', () => {
- // ref.current.dispatchEvent(createEvent('touchstart'));
- // ref.current.dispatchEvent(createEvent('touchend'));
- // expect(onPress).toHaveBeenCalledTimes(1);
- // });
});
describe('onPressMove', () => {
- it('is called after "pointermove"', () => {
- const onPressMove = jest.fn();
- const ref = React.createRef();
+ let onPressMove, ref;
+
+ beforeEach(() => {
+ onPressMove = jest.fn();
+ ref = React.createRef();
const Component = () => {
const listener = usePressResponder({
onPressMove,
@@ -625,102 +463,90 @@ describe('Event responder: Press', () => {
return ;
};
ReactDOM.render(, container);
-
ref.current.getBoundingClientRect = () => ({
top: 0,
left: 0,
bottom: 100,
right: 100,
});
- ref.current.dispatchEvent(
- createEvent('pointerdown', {pointerType: 'mouse'}),
- );
- ref.current.dispatchEvent(
- createEvent('pointermove', {
- pointerType: 'mouse',
- clientX: 10,
- clientY: 10,
- }),
- );
- expect(onPressMove).toHaveBeenCalledTimes(1);
- expect(onPressMove).toHaveBeenCalledWith(
- expect.objectContaining({pointerType: 'mouse', type: 'pressmove'}),
- );
+ document.elementFromPoint = () => ref.current;
});
- it('is not called if "pointermove" occurs during keyboard press', () => {
- const onPressMove = jest.fn();
- const ref = React.createRef();
- const Component = () => {
- const listener = usePressResponder({
- onPressMove,
+ it.each(pointerTypesTable)(
+ 'is called after pointer move: %s',
+ pointerType => {
+ const target = ref.current;
+ target.getBoundingClientRect = () => ({
+ top: 0,
+ left: 0,
+ bottom: 100,
+ right: 100,
});
- return ;
- };
- ReactDOM.render(, container);
+ dispatchPointerDown(target, {pointerType});
+ dispatchPointerMove(target, {
+ pointerType,
+ x: 10,
+ y: 10,
+ });
+ dispatchPointerMove(target, {
+ pointerType,
+ x: 20,
+ y: 20,
+ });
+ expect(onPressMove).toHaveBeenCalledTimes(2);
+ expect(onPressMove).toHaveBeenCalledWith(
+ expect.objectContaining({pointerType, type: 'pressmove'}),
+ );
+ },
+ );
- ref.current.getBoundingClientRect = () => ({
+ it('is not called if pointer move occurs during keyboard press', () => {
+ const target = ref.current;
+ target.getBoundingClientRect = () => ({
top: 0,
left: 0,
bottom: 100,
right: 100,
});
- ref.current.dispatchEvent(createKeyboardEvent('keydown', {key: 'Enter'}));
- ref.current.dispatchEvent(
- createEvent('pointermove', {
- pointerType: 'mouse',
- clientX: 10,
- clientY: 10,
- }),
- );
+ target.dispatchEvent(keydown({key: 'Enter'}));
+ dispatchPointerMove(target, {
+ button: -1,
+ pointerType: 'mouse',
+ x: 10,
+ y: 10,
+ });
expect(onPressMove).not.toBeCalled();
});
+ });
- it('ignores browser emulated events', () => {
- const onPressMove = jest.fn();
- const ref = React.createRef();
+ describe.each(pointerTypesTable)('press with movement: %s', pointerType => {
+ let events, ref, outerRef;
+
+ beforeEach(() => {
+ events = [];
+ ref = React.createRef();
+ outerRef = React.createRef();
+ const createEventHandler = msg => () => {
+ events.push(msg);
+ };
const Component = () => {
const listener = usePressResponder({
- onPressMove,
+ onPress: createEventHandler('onPress'),
+ onPressChange: createEventHandler('onPressChange'),
+ onPressMove: createEventHandler('onPressMove'),
+ onPressStart: createEventHandler('onPressStart'),
+ onPressEnd: createEventHandler('onPressEnd'),
});
- return ;
+ return (
+
+ );
};
ReactDOM.render(, container);
-
- ref.current.getBoundingClientRect = () => ({
- top: 0,
- left: 0,
- bottom: 100,
- right: 100,
- });
- ref.current.dispatchEvent(
- createEvent('pointerdown', {pointerType: 'touch'}),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointermove', {
- pointerType: 'touch',
- clientX: 10,
- clientY: 10,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- target: ref.current,
- clientX: 10,
- clientY: 10,
- }),
- );
- ref.current.dispatchEvent(createEvent('mousemove'));
- expect(onPressMove).toHaveBeenCalledTimes(1);
+ document.elementFromPoint = () => ref.current;
});
- });
- describe('press with movement (pointer events)', () => {
const rectMock = {
width: 100,
height: 100,
@@ -732,12 +558,12 @@ describe('Event responder: Press', () => {
const pressRectOffset = 20;
const getBoundingClientRectMock = () => rectMock;
const coordinatesInside = {
- clientX: rectMock.left - pressRectOffset,
- clientY: rectMock.top - pressRectOffset,
+ x: rectMock.left - pressRectOffset,
+ y: rectMock.top - pressRectOffset,
};
const coordinatesOutside = {
- clientX: rectMock.left - pressRectOffset - 1,
- clientY: rectMock.top - pressRectOffset - 1,
+ x: rectMock.left - pressRectOffset - 1,
+ y: rectMock.top - pressRectOffset - 1,
};
describe('within bounds of hit rect', () => {
@@ -749,32 +575,12 @@ describe('Event responder: Press', () => {
* └──────────────────┘
*/
it('"onPress*" events are called immediately', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(
- createEvent('pointermove', coordinatesInside),
- );
- ref.current.dispatchEvent(createEvent('pointerup', coordinatesInside));
+ const target = ref.current;
+ target.getBoundingClientRect = getBoundingClientRectMock;
+ dispatchPointerDown(target, {pointerType});
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
+ dispatchPointerUp(target, {pointerType, ...coordinatesInside});
jest.runAllTimers();
-
expect(events).toEqual([
'onPressStart',
'onPressChange',
@@ -786,12 +592,41 @@ describe('Event responder: Press', () => {
});
it('"onPress*" events are correctly called with target change', () => {
- let events = [];
- const outerRef = React.createRef();
- const innerRef = React.createRef();
+ const target = ref.current;
+ const outer = outerRef.current;
+ target.getBoundingClientRect = getBoundingClientRectMock;
+ dispatchPointerDown(target, {pointerType});
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
+ // TODO: this sequence may differ in the future between PointerEvent and mouse fallback when
+ // use 'setPointerCapture'.
+ if (pointerType === 'touch') {
+ dispatchPointerMove(target, {pointerType, ...coordinatesOutside});
+ } else {
+ dispatchPointerMove(outer, {pointerType, ...coordinatesOutside});
+ }
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
+ dispatchPointerUp(target, {pointerType, ...coordinatesInside});
+
+ expect(events.filter(removePressMoveStrings)).toEqual([
+ 'onPressStart',
+ 'onPressChange',
+ 'onPressEnd',
+ 'onPressChange',
+ 'onPressStart',
+ 'onPressChange',
+ 'onPressEnd',
+ 'onPressChange',
+ 'onPress',
+ ]);
+ });
+
+ it('press retention offset can be configured', () => {
+ let localEvents = [];
+ const localRef = React.createRef();
const createEventHandler = msg => () => {
- events.push(msg);
+ localEvents.push(msg);
};
+ const pressRetentionOffset = {top: 40, bottom: 40, left: 40, right: 40};
const Component = () => {
const listener = usePressResponder({
@@ -800,72 +635,22 @@ describe('Event responder: Press', () => {
onPressMove: createEventHandler('onPressMove'),
onPressStart: createEventHandler('onPressStart'),
onPressEnd: createEventHandler('onPressEnd'),
+ pressRetentionOffset,
});
- return (
-
- );
+ return ;
};
ReactDOM.render(, container);
- innerRef.current.getBoundingClientRect = getBoundingClientRectMock;
- innerRef.current.dispatchEvent(createEvent('pointerdown'));
- outerRef.current.dispatchEvent(
- createEvent('pointermove', coordinatesOutside),
- );
- innerRef.current.dispatchEvent(
- createEvent('pointermove', coordinatesInside),
- );
- innerRef.current.dispatchEvent(
- createEvent('pointerup', coordinatesInside),
- );
- jest.runAllTimers();
-
- expect(events).toEqual([
- 'onPressStart',
- 'onPressChange',
- 'onPressEnd',
- 'onPressChange',
- 'onPressStart',
- 'onPressChange',
- 'onPressEnd',
- 'onPressChange',
- 'onPress',
- ]);
- });
-
- it('press retention offset can be configured', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
- const pressRetentionOffset = {top: 40, bottom: 40, left: 40, right: 40};
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- pressRetentionOffset,
- });
- return ;
- };
- ReactDOM.render(, container);
-
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(
- createEvent('pointermove', {
- clientX: rectMock.left - pressRetentionOffset.left,
- clientY: rectMock.top - pressRetentionOffset.top,
- }),
- );
- ref.current.dispatchEvent(createEvent('pointerup', coordinatesInside));
- expect(events).toEqual([
+ const target = localRef.current;
+ target.getBoundingClientRect = getBoundingClientRectMock;
+ dispatchPointerDown(target, {pointerType});
+ dispatchPointerMove(target, {
+ pointerType,
+ x: rectMock.left,
+ y: rectMock.top,
+ });
+ dispatchPointerUp(target, {pointerType, ...coordinatesInside});
+ expect(localEvents).toEqual([
'onPressStart',
'onPressChange',
'onPressMove',
@@ -876,26 +661,11 @@ describe('Event responder: Press', () => {
});
it('responder region accounts for decrease in element dimensions', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(createEvent('pointerdown'));
+ const target = ref.current;
+ target.getBoundingClientRect = getBoundingClientRectMock;
+ dispatchPointerDown(target, {pointerType});
// emulate smaller dimensions change on activation
- ref.current.getBoundingClientRect = () => ({
+ target.getBoundingClientRect = () => ({
width: 80,
height: 80,
top: 60,
@@ -904,36 +674,28 @@ describe('Event responder: Press', () => {
bottom: 490,
});
const coordinates = {
- clientX: rectMock.left,
- clientY: rectMock.top,
+ x: rectMock.left,
+ y: rectMock.top,
};
// move to an area within the pre-activation region
- ref.current.dispatchEvent(createEvent('pointermove', coordinates));
- ref.current.dispatchEvent(createEvent('pointerup', coordinates));
- expect(events).toEqual(['onPressStart', 'onPressEnd', 'onPress']);
+ dispatchPointerMove(target, {pointerType, ...coordinates});
+ dispatchPointerUp(target, {pointerType, ...coordinates});
+ expect(events).toEqual([
+ 'onPressStart',
+ 'onPressChange',
+ 'onPressMove',
+ 'onPressEnd',
+ 'onPressChange',
+ 'onPress',
+ ]);
});
it('responder region accounts for increase in element dimensions', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(createEvent('pointerdown'));
+ const target = ref.current;
+ target.getBoundingClientRect = getBoundingClientRectMock;
+ dispatchPointerDown(target, {pointerType});
// emulate larger dimensions change on activation
- ref.current.getBoundingClientRect = () => ({
+ target.getBoundingClientRect = () => ({
width: 200,
height: 200,
top: 0,
@@ -942,397 +704,12 @@ describe('Event responder: Press', () => {
bottom: 550,
});
const coordinates = {
- clientX: rectMock.left - 50,
- clientY: rectMock.top - 50,
+ x: rectMock.left - 50,
+ y: rectMock.top - 50,
};
// move to an area within the post-activation region
- ref.current.dispatchEvent(createEvent('pointermove', coordinates));
- ref.current.dispatchEvent(createEvent('pointerup', coordinates));
- expect(events).toEqual(['onPressStart', 'onPressEnd', 'onPress']);
- });
- });
-
- describe('beyond bounds of hit rect', () => {
- /** ┌──────────────────┐
- * │ ┌────────────┐ │
- * │ │ VisualRect │ │
- * │ └────────────┘ │
- * │ HitRect │
- * └──────────────────┘
- * X <= Move to X and release
- */
-
- it('"onPress" is not called on release', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(
- createEvent('pointermove', coordinatesInside),
- );
- container.dispatchEvent(createEvent('pointermove', coordinatesOutside));
- container.dispatchEvent(createEvent('pointerup', coordinatesOutside));
- jest.runAllTimers();
-
- expect(events).toEqual([
- 'onPressStart',
- 'onPressChange',
- 'onPressMove',
- 'onPressEnd',
- 'onPressChange',
- ]);
- });
- });
-
- it('"onPress" is not called on release with mouse', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(
- createEvent('pointerdown', {
- pointerType: 'mouse',
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointermove', {
- ...coordinatesInside,
- pointerType: 'mouse',
- }),
- );
- container.dispatchEvent(
- createEvent('pointermove', {
- ...coordinatesOutside,
- pointerType: 'mouse',
- }),
- );
- container.dispatchEvent(
- createEvent('pointerup', {
- ...coordinatesOutside,
- pointerType: 'mouse',
- }),
- );
- jest.runAllTimers();
-
- expect(events).toEqual([
- 'onPressStart',
- 'onPressChange',
- 'onPressMove',
- 'onPressEnd',
- 'onPressChange',
- ]);
- });
-
- it('"onPress" is called on re-entry to hit rect for mouse', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(
- createEvent('pointerdown', {
- pointerType: 'mouse',
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointermove', {
- ...coordinatesInside,
- pointerType: 'mouse',
- }),
- );
- container.dispatchEvent(
- createEvent('pointermove', {
- ...coordinatesOutside,
- pointerType: 'mouse',
- }),
- );
- container.dispatchEvent(
- createEvent('pointermove', {
- ...coordinatesInside,
- pointerType: 'mouse',
- }),
- );
- container.dispatchEvent(
- createEvent('pointerup', {
- ...coordinatesInside,
- pointerType: 'mouse',
- }),
- );
- jest.runAllTimers();
-
- expect(events).toEqual([
- 'onPressStart',
- 'onPressChange',
- 'onPressMove',
- 'onPressEnd',
- 'onPressChange',
- 'onPressStart',
- 'onPressChange',
- 'onPressEnd',
- 'onPressChange',
- 'onPress',
- ]);
- });
-
- it('"onPress" is called on re-entry to hit rect for touch', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(
- createEvent('pointerdown', {
- pointerType: 'touch',
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointermove', {
- ...coordinatesInside,
- pointerType: 'touch',
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
- container.dispatchEvent(
- createEvent('pointermove', {
- ...coordinatesOutside,
- pointerType: 'touch',
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinatesOutside,
- target: ref.current,
- }),
- );
- container.dispatchEvent(
- createEvent('pointermove', {
- ...coordinatesInside,
- pointerType: 'touch',
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
- container.dispatchEvent(
- createEvent('pointerup', {
- ...coordinatesInside,
- pointerType: 'touch',
- }),
- );
- jest.runAllTimers();
-
- expect(events).toEqual([
- 'onPressStart',
- 'onPressChange',
- 'onPressMove',
- 'onPressEnd',
- 'onPressChange',
- 'onPressStart',
- 'onPressChange',
- 'onPressEnd',
- 'onPressChange',
- 'onPress',
- ]);
- });
- });
-
- describe('press with movement (touch events fallback)', () => {
- const rectMock = {
- width: 100,
- height: 100,
- top: 50,
- left: 50,
- right: 150,
- bottom: 150,
- };
- const pressRectOffset = 20;
- const getBoundingClientRectMock = () => rectMock;
- const coordinatesInside = {
- clientX: rectMock.left - pressRectOffset,
- clientY: rectMock.top - pressRectOffset,
- };
- const coordinatesOutside = {
- clientX: rectMock.left - pressRectOffset - 1,
- clientY: rectMock.top - pressRectOffset - 1,
- };
-
- describe('within bounds of hit rect', () => {
- /** ┌──────────────────┐
- * │ ┌────────────┐ │
- * │ │ VisualRect │ │
- * │ └────────────┘ │
- * │ HitRect X │ <= Move to X and release
- * └──────────────────┘
- */
- it('"onPress*" events are called immediately', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- document.elementFromPoint = () => ref.current;
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
- jest.runAllTimers();
-
- expect(events).toEqual([
- 'onPressStart',
- 'onPressChange',
- 'onPressMove',
- 'onPressEnd',
- 'onPressChange',
- 'onPress',
- ]);
- });
-
- it('press retention offset can be configured', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
- const pressRetentionOffset = {top: 40, bottom: 40, left: 40, right: 40};
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- pressRetentionOffset,
- });
- return ;
- };
- ReactDOM.render(, container);
-
- document.elementFromPoint = () => ref.current;
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- clientX: rectMock.left - pressRetentionOffset.left,
- clientY: rectMock.top - pressRetentionOffset.top,
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
+ dispatchPointerMove(target, {pointerType, ...coordinates});
+ dispatchPointerUp(target, {pointerType, ...coordinates});
expect(events).toEqual([
'onPressStart',
'onPressChange',
@@ -1342,112 +719,6 @@ describe('Event responder: Press', () => {
'onPress',
]);
});
-
- it('responder region accounts for decrease in element dimensions', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- document.elementFromPoint = () => ref.current;
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- // emulate smaller dimensions change on activation
- ref.current.getBoundingClientRect = () => ({
- width: 80,
- height: 80,
- top: 60,
- left: 60,
- right: 140,
- bottom: 140,
- });
- const coordinates = {
- clientX: rectMock.left,
- clientY: rectMock.top,
- };
- // move to an area within the pre-activation region
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinates,
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- ...coordinates,
- target: ref.current,
- }),
- );
- expect(events).toEqual(['onPressStart', 'onPressEnd', 'onPress']);
- });
-
- it('responder region accounts for increase in element dimensions', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- document.elementFromPoint = () => ref.current;
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- // emulate larger dimensions change on activation
- ref.current.getBoundingClientRect = () => ({
- width: 200,
- height: 200,
- top: 0,
- left: 0,
- right: 200,
- bottom: 200,
- });
- const coordinates = {
- clientX: rectMock.left - 50,
- clientY: rectMock.top - 50,
- };
- // move to an area within the post-activation region
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinates,
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- ...coordinates,
- target: ref.current,
- }),
- );
- expect(events).toEqual(['onPressStart', 'onPressEnd', 'onPress']);
- });
});
describe('beyond bounds of hit rect', () => {
@@ -1459,117 +730,40 @@ describe('Event responder: Press', () => {
* └──────────────────┘
* X <= Move to X and release
*/
-
it('"onPress" is not called on release', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- document.elementFromPoint = () => ref.current;
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
- document.elementFromPoint = () => container;
- container.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinatesOutside,
- target: container,
- }),
- );
- container.dispatchEvent(
- createTouchEvent('touchend', 0, {
- ...coordinatesOutside,
- target: container,
- }),
- );
- jest.runAllTimers();
-
- expect(events).toEqual([
- 'onPressStart',
- 'onPressChange',
- 'onPressMove',
- 'onPressEnd',
- 'onPressChange',
- ]);
- });
- });
-
- it('"onPress" is called on re-entry to hit rect for touch', () => {
- let events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
-
- const Component = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('onPress'),
- onPressChange: createEventHandler('onPressChange'),
- onPressMove: createEventHandler('onPressMove'),
- onPressStart: createEventHandler('onPressStart'),
- onPressEnd: createEventHandler('onPressEnd'),
- });
- return ;
- };
- ReactDOM.render(, container);
-
- document.elementFromPoint = () => ref.current;
- ref.current.getBoundingClientRect = getBoundingClientRectMock;
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
- document.elementFromPoint = () => container;
- container.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinatesOutside,
- target: container,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchmove', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
- document.elementFromPoint = () => ref.current;
- ref.current.dispatchEvent(
- createTouchEvent('touchend', 0, {
- ...coordinatesInside,
- target: ref.current,
- }),
- );
- jest.runAllTimers();
+ const target = ref.current;
+ target.getBoundingClientRect = getBoundingClientRectMock;
+ dispatchPointerDown(target, {pointerType});
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
+ if (pointerType === 'mouse') {
+ // TODO: use setPointerCapture so this is only true for fallback mouse events.
+ dispatchPointerMove(container, {pointerType, ...coordinatesOutside});
+ } else {
+ dispatchPointerMove(target, {pointerType, ...coordinatesOutside});
+ }
+ dispatchPointerUp(container, {pointerType, ...coordinatesOutside});
+ expect(events.filter(removePressMoveStrings)).toEqual([
+ 'onPressStart',
+ 'onPressChange',
+ 'onPressEnd',
+ 'onPressChange',
+ ]);
+ });
+ });
+
+ it('"onPress" is called on re-entry to hit rect', () => {
+ const target = ref.current;
+ target.getBoundingClientRect = getBoundingClientRectMock;
+ dispatchPointerDown(target, {pointerType});
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
+ if (pointerType === 'mouse') {
+ // TODO: use setPointerCapture so this is only true for fallback mouse events.
+ dispatchPointerMove(container, {pointerType, ...coordinatesOutside});
+ } else {
+ dispatchPointerMove(target, {pointerType, ...coordinatesOutside});
+ }
+ dispatchPointerMove(target, {pointerType, ...coordinatesInside});
+ dispatchPointerUp(target, {pointerType, ...coordinatesInside});
expect(events).toEqual([
'onPressStart',
@@ -1587,71 +781,71 @@ describe('Event responder: Press', () => {
});
describe('nested responders', () => {
- it('dispatch events in the correct order', () => {
- const events = [];
- const ref = React.createRef();
- const createEventHandler = msg => () => {
- events.push(msg);
- };
+ if (hasPointerEvents) {
+ it('dispatch events in the correct order', () => {
+ const events = [];
+ const ref = React.createRef();
+ const createEventHandler = msg => () => {
+ events.push(msg);
+ };
- const Inner = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('inner: onPress'),
- onPressChange: createEventHandler('inner: onPressChange'),
- onPressMove: createEventHandler('inner: onPressMove'),
- onPressStart: createEventHandler('inner: onPressStart'),
- onPressEnd: createEventHandler('inner: onPressEnd'),
- stopPropagation: false,
- });
- return (
-
- );
- };
+ const Inner = () => {
+ const listener = usePressResponder({
+ onPress: createEventHandler('inner: onPress'),
+ onPressChange: createEventHandler('inner: onPressChange'),
+ onPressMove: createEventHandler('inner: onPressMove'),
+ onPressStart: createEventHandler('inner: onPressStart'),
+ onPressEnd: createEventHandler('inner: onPressEnd'),
+ stopPropagation: false,
+ });
+ return (
+
+ );
+ };
- const Outer = () => {
- const listener = usePressResponder({
- onPress: createEventHandler('outer: onPress'),
- onPressChange: createEventHandler('outer: onPressChange'),
- onPressMove: createEventHandler('outer: onPressMove'),
- onPressStart: createEventHandler('outer: onPressStart'),
- onPressEnd: createEventHandler('outer: onPressEnd'),
- });
- return (
-
-
-
- );
- };
- ReactDOM.render(, container);
+ const Outer = () => {
+ const listener = usePressResponder({
+ onPress: createEventHandler('outer: onPress'),
+ onPressChange: createEventHandler('outer: onPressChange'),
+ onPressMove: createEventHandler('outer: onPressMove'),
+ onPressStart: createEventHandler('outer: onPressStart'),
+ onPressEnd: createEventHandler('outer: onPressEnd'),
+ });
+ return (
+
+
+
+ );
+ };
+ ReactDOM.render(, container);
- ref.current.getBoundingClientRect = () => ({
- top: 0,
- left: 0,
- bottom: 100,
- right: 100,
+ const target = ref.current;
+ target.getBoundingClientRect = () => ({
+ top: 0,
+ left: 0,
+ bottom: 100,
+ right: 100,
+ });
+ dispatchPointerDown(target);
+ dispatchPointerUp(target);
+ expect(events).toEqual([
+ 'inner: onPressStart',
+ 'inner: onPressChange',
+ 'pointerdown',
+ 'inner: onPressEnd',
+ 'inner: onPressChange',
+ 'inner: onPress',
+ 'pointerup',
+ ]);
});
-
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(
- createEvent('pointerup', {clientX: 10, clientY: 10}),
- );
- expect(events).toEqual([
- 'inner: onPressStart',
- 'inner: onPressChange',
- 'pointerdown',
- 'inner: onPressEnd',
- 'inner: onPressChange',
- 'inner: onPress',
- 'pointerup',
- ]);
- });
+ }
describe('correctly not propagate', () => {
it('for onPress', () => {
@@ -1677,17 +871,15 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.getBoundingClientRect = () => ({
+ const target = ref.current;
+ target.getBoundingClientRect = () => ({
top: 0,
left: 0,
bottom: 100,
right: 100,
});
-
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(
- createEvent('pointerup', {clientX: 10, clientY: 10}),
- );
+ dispatchPointerDown(target);
+ dispatchPointerUp(target);
expect(fn).toHaveBeenCalledTimes(1);
});
@@ -1717,10 +909,11 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('pointerdown'));
+ const target = ref.current;
+ dispatchPointerDown(target);
expect(fn).toHaveBeenCalledTimes(1);
expect(fn2).toHaveBeenCalledTimes(0);
- ref.current.dispatchEvent(createEvent('pointerup'));
+ dispatchPointerUp(target);
expect(fn).toHaveBeenCalledTimes(1);
expect(fn2).toHaveBeenCalledTimes(1);
});
@@ -1748,16 +941,17 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('pointerdown'));
+ const target = ref.current;
+ dispatchPointerDown(target);
expect(fn).toHaveBeenCalledTimes(1);
- ref.current.dispatchEvent(createEvent('pointerup'));
+ dispatchPointerUp(target);
expect(fn).toHaveBeenCalledTimes(2);
});
});
});
describe('link components', () => {
- it('prevents native behaviour for pointer events by default', () => {
+ it('prevents native behavior by default', () => {
const onPress = jest.fn();
const preventDefault = jest.fn();
const ref = React.createRef();
@@ -1770,14 +964,9 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(
- createEvent('pointerup', {
- clientX: 0,
- clientY: 0,
- }),
- );
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
+ const target = ref.current;
+ dispatchPointerDown(target);
+ dispatchPointerUp(target, {preventDefault});
expect(preventDefault).toBeCalled();
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({defaultPrevented: true}),
@@ -1797,9 +986,10 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('keydown', {key: 'Enter'}));
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
- ref.current.dispatchEvent(createEvent('keyup', {key: 'Enter'}));
+ const target = ref.current;
+ target.dispatchEvent(keydown({key: 'Enter'}));
+ target.dispatchEvent(click({preventDefault}));
+ target.dispatchEvent(keyup({key: 'Enter'}));
expect(preventDefault).toBeCalled();
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({defaultPrevented: true}),
@@ -1823,14 +1013,9 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- buttonRef.current.dispatchEvent(createEvent('pointerdown'));
- buttonRef.current.dispatchEvent(
- createEvent('pointerup', {
- clientX: 0,
- clientY: 0,
- }),
- );
- buttonRef.current.dispatchEvent(createEvent('click', {preventDefault}));
+ const target = buttonRef.current;
+ dispatchPointerDown(target);
+ dispatchPointerUp(target, {preventDefault});
expect(preventDefault).toBeCalled();
});
@@ -1851,14 +1036,9 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(
- createEvent('pointerup', {
- clientX: 0,
- clientY: 0,
- }),
- );
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
+ const target = ref.current;
+ dispatchPointerDown(target);
+ dispatchPointerUp(target, {preventDefault});
expect(preventDefault).toBeCalled();
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({defaultPrevented: true}),
@@ -1879,19 +1059,9 @@ describe('Event responder: Press', () => {
ReactDOM.render(, container);
['metaKey', 'ctrlKey', 'shiftKey'].forEach(modifierKey => {
- ref.current.dispatchEvent(
- createEvent('pointerdown', {[modifierKey]: true}),
- );
- ref.current.dispatchEvent(
- createEvent('pointerup', {
- [modifierKey]: true,
- clientX: 0,
- clientY: 0,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('click', {[modifierKey]: true, preventDefault}),
- );
+ const target = ref.current;
+ dispatchPointerDown(target, {[modifierKey]: true});
+ dispatchPointerUp(target, {[modifierKey]: true, preventDefault});
expect(preventDefault).not.toBeCalled();
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({defaultPrevented: false}),
@@ -1913,14 +1083,9 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(
- createEvent('pointerup', {
- clientX: 0,
- clientY: 0,
- }),
- );
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
+ const target = ref.current;
+ dispatchPointerDown(target);
+ dispatchPointerUp(target, {preventDefault});
expect(preventDefault).not.toBeCalled();
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({defaultPrevented: false}),
@@ -1941,9 +1106,10 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('keydown', {key: 'Enter'}));
- ref.current.dispatchEvent(createEvent('click', {preventDefault}));
- ref.current.dispatchEvent(createEvent('keyup', {key: 'Enter'}));
+ const target = ref.current;
+ target.dispatchEvent(keydown({key: 'Enter'}));
+ target.dispatchEvent(click({preventDefault}));
+ target.dispatchEvent(keyup({key: 'Enter'}));
expect(preventDefault).not.toBeCalled();
expect(onPress).toHaveBeenCalledWith(
expect.objectContaining({defaultPrevented: false}),
@@ -1952,7 +1118,7 @@ describe('Event responder: Press', () => {
});
describe('responder cancellation', () => {
- it('ends on "pointercancel", "touchcancel", "scroll", and "dragstart"', () => {
+ it.each(pointerTypesTable)('ends on pointer cancel', pointerType => {
const onPressEnd = jest.fn();
const ref = React.createRef();
@@ -1964,64 +1130,14 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- // Should cancel for non-mouse events
- ref.current.dispatchEvent(
- createEvent('pointerdown', {
- pointerType: 'touch',
- }),
- );
- ref.current.dispatchEvent(createEvent('scroll'));
- expect(onPressEnd).toHaveBeenCalledTimes(1);
-
- onPressEnd.mockReset();
-
- // Should not cancel for mouse events
- ref.current.dispatchEvent(
- createEvent('pointerdown', {
- pointerType: 'mouse',
- }),
- );
- ref.current.dispatchEvent(createEvent('scroll'));
- expect(onPressEnd).toHaveBeenCalledTimes(0);
-
- // When pointer events are supported
- ref.current.dispatchEvent(
- createEvent('pointerdown', {
- pointerType: 'mouse',
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointercancel', {
- pointerType: 'mouse',
- }),
- );
- expect(onPressEnd).toHaveBeenCalledTimes(1);
-
- onPressEnd.mockReset();
-
- // Touch fallback
- ref.current.dispatchEvent(
- createTouchEvent('touchstart', 0, {
- target: ref.current,
- }),
- );
- ref.current.dispatchEvent(
- createTouchEvent('touchcancel', 0, {
- target: ref.current,
- }),
- );
- expect(onPressEnd).toHaveBeenCalledTimes(1);
-
- onPressEnd.mockReset();
-
- // Mouse fallback
- ref.current.dispatchEvent(createEvent('mousedown'));
- ref.current.dispatchEvent(createEvent('dragstart'));
+ const target = ref.current;
+ dispatchPointerDown(target, {pointerType});
+ dispatchPointerCancel(target, {pointerType});
expect(onPressEnd).toHaveBeenCalledTimes(1);
});
});
- it('does end on "scroll" to document', () => {
+ it('does end on "scroll" to document (not mouse)', () => {
const onPressEnd = jest.fn();
const ref = React.createRef();
@@ -2033,12 +1149,13 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('pointerdown'));
- document.dispatchEvent(createEvent('scroll'));
+ const target = ref.current;
+ dispatchPointerDown(target, {pointerType: 'touch'});
+ document.dispatchEvent(scroll());
expect(onPressEnd).toHaveBeenCalledTimes(1);
});
- it('does end on "scroll" to a parent container', () => {
+ it('does end on "scroll" to a parent container (not mouse)', () => {
const onPressEnd = jest.fn();
const ref = React.createRef();
const containerRef = React.createRef();
@@ -2055,8 +1172,8 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('pointerdown'));
- containerRef.current.dispatchEvent(createEvent('scroll'));
+ dispatchPointerDown(ref.current, {pointerType: 'touch'});
+ containerRef.current.dispatchEvent(scroll());
expect(onPressEnd).toHaveBeenCalledTimes(1);
});
@@ -2078,8 +1195,8 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('pointerdown'));
- outsideRef.current.dispatchEvent(createEvent('scroll'));
+ dispatchPointerDown(ref.current);
+ outsideRef.current.dispatchEvent(scroll());
expect(onPressEnd).not.toBeCalled();
});
@@ -2095,10 +1212,11 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.dispatchEvent(createEvent('pointerdown'));
- ref.current.dispatchEvent(createEvent('pointermove'));
- ref.current.dispatchEvent(createEvent('pointerup'));
- ref.current.dispatchEvent(createEvent('pointerdown'));
+ const target = ref.current;
+ dispatchPointerDown(target);
+ dispatchPointerMove(target);
+ dispatchPointerUp(target);
+ dispatchPointerDown(target);
});
it('should correctly pass through event properties', () => {
@@ -2133,57 +1251,49 @@ describe('Event responder: Press', () => {
};
ReactDOM.render(, container);
- ref.current.getBoundingClientRect = () => ({
+ const target = ref.current;
+ target.getBoundingClientRect = () => ({
top: 10,
left: 10,
bottom: 110,
right: 110,
});
-
- ref.current.dispatchEvent(
- createEvent('pointerdown', {
- pointerType: 'mouse',
- pageX: 15,
- pageY: 16,
- screenX: 20,
- screenY: 21,
- clientX: 30,
- clientY: 31,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointermove', {
- pointerType: 'mouse',
- pageX: 16,
- pageY: 17,
- screenX: 21,
- screenY: 22,
- clientX: 31,
- clientY: 32,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointerup', {
- pointerType: 'mouse',
- pageX: 17,
- pageY: 18,
- screenX: 22,
- screenY: 23,
- clientX: 32,
- clientY: 33,
- }),
- );
- ref.current.dispatchEvent(
- createEvent('pointerdown', {
- pointerType: 'mouse',
- pageX: 18,
- pageY: 19,
- screenX: 23,
- screenY: 24,
- clientX: 33,
- clientY: 34,
- }),
- );
+ dispatchPointerDown(target, {
+ pointerType: 'mouse',
+ pageX: 15,
+ pageY: 16,
+ screenX: 20,
+ screenY: 21,
+ clientX: 30,
+ clientY: 31,
+ });
+ dispatchPointerMove(target, {
+ pointerType: 'mouse',
+ pageX: 16,
+ pageY: 17,
+ screenX: 21,
+ screenY: 22,
+ clientX: 31,
+ clientY: 32,
+ });
+ dispatchPointerUp(target, {
+ pointerType: 'mouse',
+ pageX: 17,
+ pageY: 18,
+ screenX: 22,
+ screenY: 23,
+ clientX: 32,
+ clientY: 33,
+ });
+ dispatchPointerDown(target, {
+ pointerType: 'mouse',
+ pageX: 18,
+ pageY: 19,
+ screenX: 23,
+ screenY: 24,
+ clientX: 33,
+ clientY: 34,
+ });
expect(typeof timeStamps[0] === 'number').toBe(true);
expect(eventLog).toEqual([
{
@@ -2249,175 +1359,85 @@ describe('Event responder: Press', () => {
]);
});
- function dispatchEventWithTimeStamp(elem, name, timeStamp) {
- const event = createEvent(name, {
- clientX: 0,
- clientY: 0,
- });
- Object.defineProperty(event, 'timeStamp', {
- value: timeStamp,
- });
- elem.dispatchEvent(event);
- }
-
- it('should properly only flush sync once when the event systems are mixed', () => {
- const ref = React.createRef();
- let renderCounts = 0;
-
- function MyComponent() {
- const [, updateCounter] = React.useState(0);
- renderCounts++;
-
- function handlePress() {
- updateCounter(count => count + 1);
- }
-
- const listener = usePressResponder({
- onPress: handlePress,
- });
-
- return (
-
-
-
- );
- }
-
- const newContainer = document.createElement('div');
- const root = ReactDOM.unstable_createRoot(newContainer);
- document.body.appendChild(newContainer);
- root.render();
- Scheduler.unstable_flushAll();
-
- dispatchEventWithTimeStamp(ref.current, 'pointerdown', 100);
- dispatchEventWithTimeStamp(ref.current, 'pointerup', 100);
- dispatchEventWithTimeStamp(ref.current, 'click', 100);
-
- if (__DEV__) {
- expect(renderCounts).toBe(2);
- } else {
- expect(renderCounts).toBe(1);
- }
- Scheduler.unstable_flushAll();
- if (__DEV__) {
- expect(renderCounts).toBe(4);
- } else {
- expect(renderCounts).toBe(2);
- }
-
- dispatchEventWithTimeStamp(ref.current, 'pointerdown', 100);
- dispatchEventWithTimeStamp(ref.current, 'pointerup', 100);
- // Ensure the timeStamp logic works
- dispatchEventWithTimeStamp(ref.current, 'click', 101);
-
- if (__DEV__) {
- expect(renderCounts).toBe(6);
- } else {
- expect(renderCounts).toBe(3);
- }
+ if (hasPointerEvents) {
+ it('should properly only flush sync once when the event systems are mixed', () => {
+ const ref = React.createRef();
+ let renderCounts = 0;
- Scheduler.unstable_flushAll();
- document.body.removeChild(newContainer);
- });
+ function MyComponent() {
+ const [, updateCounter] = React.useState(0);
+ renderCounts++;
- it('should properly flush sync when the event systems are mixed with unstable_flushDiscreteUpdates', () => {
- const ref = React.createRef();
- let renderCounts = 0;
+ function handlePress() {
+ updateCounter(count => count + 1);
+ }
- function MyComponent() {
- const [, updateCounter] = React.useState(0);
- renderCounts++;
+ const listener = usePressResponder({
+ onPress: handlePress,
+ });
- function handlePress() {
- updateCounter(count => count + 1);
+ return (
+
+
+
+ );
}
- const listener = usePressResponder({
- onPress: handlePress,
- });
-
- return (
-
-
-
- );
- }
-
- const newContainer = document.createElement('div');
- const root = ReactDOM.unstable_createRoot(newContainer);
- document.body.appendChild(newContainer);
- root.render();
- Scheduler.unstable_flushAll();
-
- dispatchEventWithTimeStamp(ref.current, 'pointerdown', 100);
- dispatchEventWithTimeStamp(ref.current, 'pointerup', 100);
- dispatchEventWithTimeStamp(ref.current, 'click', 100);
-
- if (__DEV__) {
- expect(renderCounts).toBe(4);
- } else {
- expect(renderCounts).toBe(2);
- }
- Scheduler.unstable_flushAll();
- if (__DEV__) {
- expect(renderCounts).toBe(6);
- } else {
- expect(renderCounts).toBe(3);
- }
+ const newContainer = document.createElement('div');
+ const root = ReactDOM.unstable_createRoot(newContainer);
+ document.body.appendChild(newContainer);
+ root.render();
+ Scheduler.unstable_flushAll();
- dispatchEventWithTimeStamp(ref.current, 'pointerdown', 100);
- dispatchEventWithTimeStamp(ref.current, 'pointerup', 100);
- // Ensure the timeStamp logic works
- dispatchEventWithTimeStamp(ref.current, 'click', 101);
+ const target = ref.current;
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
+ target.dispatchEvent(pointerup({timeStamp: 100}));
+ target.dispatchEvent(click({timeStamp: 100}));
- if (__DEV__) {
- expect(renderCounts).toBe(8);
- } else {
- expect(renderCounts).toBe(4);
- }
+ if (__DEV__) {
+ expect(renderCounts).toBe(2);
+ } else {
+ expect(renderCounts).toBe(1);
+ }
+ Scheduler.unstable_flushAll();
+ if (__DEV__) {
+ expect(renderCounts).toBe(4);
+ } else {
+ expect(renderCounts).toBe(2);
+ }
- Scheduler.unstable_flushAll();
- document.body.removeChild(newContainer);
- });
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
+ target.dispatchEvent(pointerup({timeStamp: 100}));
+ // Ensure the timeStamp logic works
+ target.dispatchEvent(click({timeStamp: 101}));
- it(
- 'should only flush before outermost discrete event handler when mixing ' +
- 'event systems',
- async () => {
- const {useState} = React;
+ if (__DEV__) {
+ expect(renderCounts).toBe(6);
+ } else {
+ expect(renderCounts).toBe(3);
+ }
- const button = React.createRef();
+ Scheduler.unstable_flushAll();
+ document.body.removeChild(newContainer);
+ });
- const ops = [];
+ it('should properly flush sync when the event systems are mixed with unstable_flushDiscreteUpdates', () => {
+ const ref = React.createRef();
+ let renderCounts = 0;
function MyComponent() {
- const [pressesCount, updatePressesCount] = useState(0);
- const [clicksCount, updateClicksCount] = useState(0);
+ const [, updateCounter] = React.useState(0);
+ renderCounts++;
function handlePress() {
- // This dispatches a synchronous, discrete event in the legacy event
- // system. However, because it's nested inside the new event system,
- // its updates should not flush until the end of the outer handler.
- button.current.click();
- // Text context should not have changed
- ops.push(newContainer.textContent);
- updatePressesCount(pressesCount + 1);
+ updateCounter(count => count + 1);
}
const listener = usePressResponder({
@@ -2427,76 +1447,131 @@ describe('Event responder: Press', () => {
return (
);
}
const newContainer = document.createElement('div');
- document.body.appendChild(newContainer);
const root = ReactDOM.unstable_createRoot(newContainer);
-
+ document.body.appendChild(newContainer);
root.render();
Scheduler.unstable_flushAll();
- expect(newContainer.textContent).toEqual('Presses: 0, Clicks: 0');
- dispatchEventWithTimeStamp(button.current, 'pointerdown', 100);
- dispatchEventWithTimeStamp(button.current, 'pointerup', 100);
- dispatchEventWithTimeStamp(button.current, 'click', 100);
+ const target = ref.current;
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
+ target.dispatchEvent(pointerup({timeStamp: 100}));
+ target.dispatchEvent(click({timeStamp: 100}));
+
+ if (__DEV__) {
+ expect(renderCounts).toBe(4);
+ } else {
+ expect(renderCounts).toBe(2);
+ }
Scheduler.unstable_flushAll();
- expect(newContainer.textContent).toEqual('Presses: 1, Clicks: 1');
+ if (__DEV__) {
+ expect(renderCounts).toBe(6);
+ } else {
+ expect(renderCounts).toBe(3);
+ }
- expect(ops).toEqual(['Presses: 0, Clicks: 0']);
- },
- );
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
+ target.dispatchEvent(pointerup({timeStamp: 100}));
+ // Ensure the timeStamp logic works
+ target.dispatchEvent(click({timeStamp: 101}));
- it('should work correctly with stopPropagation set to true', () => {
- const ref = React.createRef();
- const pointerDownEvent = jest.fn();
+ if (__DEV__) {
+ expect(renderCounts).toBe(8);
+ } else {
+ expect(renderCounts).toBe(4);
+ }
- const Component = () => {
- const listener = usePressResponder({stopPropagation: true});
+ Scheduler.unstable_flushAll();
+ document.body.removeChild(newContainer);
+ });
- return ;
- };
+ it(
+ 'should only flush before outermost discrete event handler when mixing ' +
+ 'event systems',
+ async () => {
+ const {useState} = React;
- container.addEventListener('pointerdown', pointerDownEvent);
- ReactDOM.render(, container);
+ const button = React.createRef();
- ref.current.dispatchEvent(
- createEvent('pointerdown', {pointerType: 'mouse', button: 0}),
- );
- container.removeEventListener('pointerdown', pointerDownEvent);
- expect(pointerDownEvent).toHaveBeenCalledTimes(0);
- });
+ const ops = [];
- it('has the correct press target when used with event hook', () => {
- const ref = React.createRef();
- const onPress = jest.fn();
- const Component = () => {
- const listener = usePressResponder({onPress});
+ function MyComponent() {
+ const [pressesCount, updatePressesCount] = useState(0);
+ const [clicksCount, updateClicksCount] = useState(0);
- return (
-
- );
- };
- ReactDOM.render(, container);
+ function handlePress() {
+ // This dispatches a synchronous, discrete event in the legacy event
+ // system. However, because it's nested inside the new event system,
+ // its updates should not flush until the end of the outer handler.
+ button.current.click();
+ // Text context should not have changed
+ ops.push(newContainer.textContent);
+ updatePressesCount(pressesCount + 1);
+ }
- ref.current.dispatchEvent(
- createEvent('pointerdown', {pointerType: 'mouse', button: 0}),
- );
- ref.current.dispatchEvent(
- createEvent('pointerup', {pointerType: 'mouse', button: 0}),
- );
- expect(onPress).toHaveBeenCalledTimes(1);
- expect(onPress).toHaveBeenCalledWith(
- expect.objectContaining({target: ref.current}),
+ const listener = usePressResponder({
+ onPress: handlePress,
+ });
+
+ return (
+
+
+
+ );
+ }
+
+ const newContainer = document.createElement('div');
+ document.body.appendChild(newContainer);
+ const root = ReactDOM.unstable_createRoot(newContainer);
+
+ root.render();
+ Scheduler.unstable_flushAll();
+ expect(newContainer.textContent).toEqual('Presses: 0, Clicks: 0');
+
+ const target = button.current;
+ target.dispatchEvent(pointerdown({timeStamp: 100}));
+ target.dispatchEvent(pointerup({timeStamp: 100}));
+ target.dispatchEvent(click({timeStamp: 100}));
+
+ Scheduler.unstable_flushAll();
+ expect(newContainer.textContent).toEqual('Presses: 1, Clicks: 1');
+
+ expect(ops).toEqual(['Presses: 0, Clicks: 0']);
+ },
);
- });
+
+ it('should work correctly with stopPropagation set to true', () => {
+ const ref = React.createRef();
+ const pointerDownEvent = jest.fn();
+
+ const Component = () => {
+ const listener = usePressResponder({stopPropagation: true});
+ return ;
+ };
+
+ container.addEventListener('pointerdown', pointerDownEvent);
+ ReactDOM.render(, container);
+ dispatchPointerDown(ref.current);
+ container.removeEventListener('pointerdown', pointerDownEvent);
+ expect(pointerDownEvent).toHaveBeenCalledTimes(0);
+ });
+ }
});
diff --git a/packages/react-events/src/dom/test-utils.js b/packages/react-events/src/dom/test-utils.js
index 826ac219ce58f..9597af0781946 100644
--- a/packages/react-events/src/dom/test-utils.js
+++ b/packages/react-events/src/dom/test-utils.js
@@ -15,7 +15,7 @@
* Change environment support for PointerEvent.
*/
-function hasPointerEvent(bool) {
+function hasPointerEvent() {
return global != null && global.PointerEvent != null;
}
@@ -57,23 +57,38 @@ const platform = {
* Mock native events
*/
-function createEvent(type, data) {
+function createEvent(type, data = {}) {
const event = document.createEvent('CustomEvent');
event.initCustomEvent(type, true, true);
+ event.clientX = data.x || 0;
+ event.clientY = data.y || 0;
+ event.x = data.x || 0;
+ event.y = data.y || 0;
if (data != null) {
- Object.entries(data).forEach(([key, value]) => {
- event[key] = value;
+ Object.keys(data).forEach(key => {
+ const value = data[key];
+ Object.defineProperty(event, key, {value});
});
}
return event;
}
-function createTouchEvent(type, data, id) {
+function createTouchEvent(type, data = {}, id) {
return createEvent(type, {
changedTouches: [
{
+ identifier: id,
+ clientX: data.x || 0,
+ clientY: data.y || 0,
...data,
+ },
+ ],
+ targetTouches: [
+ {
identifier: id,
+ clientX: 0 || data.x,
+ clientY: 0 || data.y,
+ ...data,
},
],
});
@@ -112,17 +127,45 @@ function gotpointercapture(data) {
}
function keydown(data) {
- return createKeyboardEvent('keydown', data);
+ return createEvent('keydown', data);
}
function keyup(data) {
- return createKeyboardEvent('keyup', data);
+ return createEvent('keyup', data);
}
function lostpointercapture(data) {
return createEvent('lostpointercapture', data);
}
+function mousedown(data) {
+ return createEvent('mousedown', data);
+}
+
+function mouseenter(data) {
+ return createEvent('mouseenter', data);
+}
+
+function mouseleave(data) {
+ return createEvent('mouseleave', data);
+}
+
+function mousemove(data) {
+ return createEvent('mousemove', data);
+}
+
+function mouseout(data) {
+ return createEvent('mouseout', data);
+}
+
+function mouseover(data) {
+ return createEvent('mouseover', data);
+}
+
+function mouseup(data) {
+ return createEvent('mouseup', data);
+}
+
function pointercancel(data) {
return createEvent('pointercancel', data);
}
@@ -155,32 +198,8 @@ function pointerup(data) {
return createEvent('pointerup', data);
}
-function mousedown(data) {
- return createEvent('mousedown', data);
-}
-
-function mouseenter(data) {
- return createEvent('mouseenter', data);
-}
-
-function mouseleave(data) {
- return createEvent('mouseleave', data);
-}
-
-function mousemove(data) {
- return createEvent('mousemove', data);
-}
-
-function mouseout(data) {
- return createEvent('mouseout', data);
-}
-
-function mouseover(data) {
- return createEvent('mouseover', data);
-}
-
-function mouseup(data) {
- return createEvent('mouseup', data);
+function scroll(data) {
+ return createEvent('scroll', data);
}
function touchcancel(data, id) {
@@ -264,15 +283,15 @@ function dispatchPointerHoverEnter(target, {relatedTarget, x, y} = {}) {
dispatch(pointerenter({pointerType, ...event}));
}
dispatch(mouseover(event));
- dispatch(mouseover(event));
+ dispatch(mouseenter(event));
}
-function dispatchPointerHoverMove(target, {from, to} = {}) {
+function dispatchPointerHoverMove(target, {x, y} = {}) {
const dispatch = arg => target.dispatchEvent(arg);
const button = -1;
const pointerId = 1;
const pointerType = 'mouse';
- function dispatchMove({x, y}) {
+ function dispatchMove() {
const event = {
button,
clientX: x,
@@ -285,8 +304,7 @@ function dispatchPointerHoverMove(target, {from, to} = {}) {
}
dispatch(mousemove(event));
}
- dispatchMove({x: from.x, y: from.y});
- dispatchMove({x: to.x, y: to.y});
+ dispatchMove();
}
function dispatchPointerHoverExit(target, {relatedTarget, x, y} = {}) {
@@ -309,77 +327,135 @@ function dispatchPointerHoverExit(target, {relatedTarget, x, y} = {}) {
dispatch(mouseleave(event));
}
-function dispatchPointerCancel(target, options) {
+function dispatchPointerCancel(target, {pointerType = 'mouse', ...rest} = {}) {
const dispatchEvent = arg => target.dispatchEvent(arg);
- dispatchEvent(pointercancel({pointerType: 'mouse'}));
- dispatchEvent(dragstart({pointerType: 'mouse'}));
+ if (hasPointerEvent()) {
+ dispatchEvent(pointercancel({pointerType, ...rest}));
+ } else {
+ if (pointerType === 'mouse') {
+ dispatchEvent(dragstart({...rest}));
+ } else {
+ dispatchEvent(touchcancel({...rest}));
+ }
+ }
}
-function dispatchPointerPressDown(
+function dispatchPointerDown(
target,
- {button = 0, pointerType = 'mouse'} = {},
+ {button = 0, pointerType = 'mouse', ...rest} = {},
) {
const dispatch = arg => target.dispatchEvent(arg);
const pointerId = 1;
- if (pointerType !== 'mouse') {
+ const pointerEvent = {button, pointerId, pointerType, ...rest};
+ const mouseEvent = {button, ...rest};
+ const touch = {...rest};
+
+ if (pointerType === 'mouse') {
if (hasPointerEvent()) {
- dispatch(pointerover({button, pointerId, pointerType}));
- dispatch(pointerenter({button, pointerId, pointerType}));
- dispatch(pointerdown({button, pointerId, pointerType}));
+ dispatch(pointerover(pointerEvent));
+ dispatch(pointerenter(pointerEvent));
}
- dispatch(touchstart(null, pointerId));
+ dispatch(mouseover(mouseEvent));
+ dispatch(mouseenter(mouseEvent));
if (hasPointerEvent()) {
- dispatch(gotpointercapture({button, pointerId, pointerType}));
+ dispatch(pointerdown(pointerEvent));
+ }
+ dispatch(mousedown(mouseEvent));
+ if (document.activeElement !== target) {
+ dispatch(focus());
}
} else {
if (hasPointerEvent()) {
- dispatch(pointerdown({button, pointerId, pointerType}));
+ dispatch(pointerover(pointerEvent));
+ dispatch(pointerenter(pointerEvent));
+ dispatch(pointerdown(pointerEvent));
}
- dispatch(mousedown({button}));
- if (document.activeElement !== target) {
- dispatch(focus({button}));
+ dispatch(touchstart(touch, pointerId));
+ if (hasPointerEvent()) {
+ dispatch(gotpointercapture(pointerEvent));
}
}
}
-function dispatchPointerPressRelease(
+function dispatchPointerUp(
target,
- {button = 0, pointerType = 'mouse'} = {},
+ {button = 0, pointerType = 'mouse', ...rest} = {},
) {
const dispatch = arg => target.dispatchEvent(arg);
const pointerId = 1;
- if (pointerType !== 'mouse') {
+ const pointerEvent = {button, pointerId, pointerType, ...rest};
+ const mouseEvent = {button, ...rest};
+ const touch = {...rest};
+
+ if (pointerType === 'mouse') {
if (hasPointerEvent()) {
- dispatch(pointerup({button, pointerId, pointerType}));
- dispatch(lostpointercapture({button, pointerId, pointerType}));
- dispatch(pointerout({button, pointerId, pointerType}));
- dispatch(pointerleave({button, pointerId, pointerType}));
- }
- dispatch(touchend(null, pointerId));
- dispatch(mouseover({button}));
- dispatch(mousemove({button}));
- dispatch(mousedown({button}));
- if (document.activeElement !== target) {
- dispatch(focus({button}));
+ dispatch(pointerup(pointerEvent));
}
- dispatch(mouseup({button}));
- dispatch(click({button}));
+ dispatch(mouseup(mouseEvent));
+ dispatch(click(mouseEvent));
} else {
if (hasPointerEvent()) {
- dispatch(pointerup({button, pointerId, pointerType}));
+ dispatch(pointerup(pointerEvent));
+ dispatch(lostpointercapture(pointerEvent));
+ dispatch(pointerout(pointerEvent));
+ dispatch(pointerleave(pointerEvent));
}
- dispatch(mouseup({button}));
- dispatch(click({button}));
+ dispatch(touchend(touch, pointerId));
+ dispatch(mouseover(mouseEvent));
+ dispatch(mousemove(mouseEvent));
+ dispatch(mousedown(mouseEvent));
+ if (document.activeElement !== target) {
+ dispatch(focus());
+ }
+ dispatch(mouseup(mouseEvent));
+ dispatch(click(mouseEvent));
+ }
+}
+
+function dispatchPointerMove(
+ target,
+ {button = 0, pointerType = 'mouse', ...rest} = {},
+) {
+ const dispatch = arg => target.dispatchEvent(arg);
+ const pointerId = 1;
+ const pointerEvent = {
+ button,
+ pointerId,
+ pointerType,
+ ...rest,
+ };
+ const mouseEvent = {
+ button,
+ ...rest,
+ };
+ const touch = {
+ ...rest,
+ };
+
+ if (hasPointerEvent()) {
+ dispatch(pointermove(pointerEvent));
+ }
+ if (pointerType === 'mouse') {
+ dispatch(mousemove(mouseEvent));
+ }
+ if (pointerType === 'touch') {
+ dispatch(touchmove(touch, pointerId));
}
}
function dispatchTouchTap(target) {
- dispatchPointerPressDown(target, {pointerType: 'touch'});
- dispatchPointerPressRelease(target, {pointerType: 'touch'});
+ dispatchPointerDown(target, {pointerType: 'touch'});
+ dispatchPointerUp(target, {pointerType: 'touch'});
+}
+
+function dispatchMouseTap(target) {
+ dispatchPointerDown(target, {pointerType: 'mouse'});
+ dispatchPointerUp(target, {pointerType: 'mouse'});
}
module.exports = {
blur,
+ click,
focus,
createEvent,
dispatchLongPressContextMenu,
@@ -389,11 +465,16 @@ module.exports = {
dispatchPointerHoverEnter,
dispatchPointerHoverExit,
dispatchPointerHoverMove,
- dispatchPointerPressDown,
- dispatchPointerPressRelease,
+ dispatchPointerMove,
+ dispatchPointerDown,
+ dispatchPointerUp,
dispatchTouchTap,
+ dispatchMouseTap,
keydown,
keyup,
+ scroll,
+ pointerdown,
+ pointerup,
platform,
hasPointerEvent,
setPointerEvent,