diff --git a/packages/react-events/src/Drag.js b/packages/react-events/src/Drag.js
index 54498760ff305..ed11c4260c270 100644
--- a/packages/react-events/src/Drag.js
+++ b/packages/react-events/src/Drag.js
@@ -37,7 +37,7 @@ type EventData = {
diffX: number,
diffY: number,
};
-type DragEventType = 'dragend' | 'dragchange' | 'dragmove';
+type DragEventType = 'dragstart' | 'dragend' | 'dragchange' | 'dragmove';
type DragEvent = {|
listener: DragEvent => void,
@@ -99,6 +99,9 @@ const DragResponder = {
case 'mousedown':
case 'pointerdown': {
if (!state.isDragging) {
+ if (props.onShouldClaimOwnership) {
+ context.releaseOwnership(state.dragTarget);
+ }
const obj =
eventType === 'touchstart' ? (event: any).changedTouches[0] : event;
const x = (state.startX = (obj: any).screenX);
@@ -107,6 +110,17 @@ const DragResponder = {
state.y = y;
state.dragTarget = eventTarget;
state.isPointerDown = true;
+
+ if (props.onDragStart) {
+ dispatchDragEvent(
+ context,
+ 'dragstart',
+ props.onDragStart,
+ state,
+ true,
+ );
+ }
+
context.addRootEventTypes(rootEventTypes);
}
break;
diff --git a/packages/react-events/src/__tests__/Drag-test.internal.js b/packages/react-events/src/__tests__/Drag-test.internal.js
new file mode 100644
index 0000000000000..96196242c83d0
--- /dev/null
+++ b/packages/react-events/src/__tests__/Drag-test.internal.js
@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+let React;
+let ReactFeatureFlags;
+let ReactDOM;
+let Drag;
+describe('Drag event responder', () => {
+ let container;
+
+ beforeEach(() => {
+ jest.resetModules();
+ ReactFeatureFlags = require('shared/ReactFeatureFlags');
+ ReactFeatureFlags.enableEventAPI = true;
+ React = require('react');
+ ReactDOM = require('react-dom');
+ Drag = require('react-events/drag');
+
+ container = document.createElement('div');
+ document.body.appendChild(container);
+ });
+
+ afterEach(() => {
+ document.body.removeChild(container);
+ container = null;
+ });
+
+ it('should support onDragChange', () => {
+ let divRef = React.createRef();
+ let events = [];
+
+ function handleOnDrag() {
+ events.push({isChanged: true});
+ }
+
+ function Component() {
+ return (
+
+ Drag me!
+
+ );
+ }
+
+ ReactDOM.render(, container);
+
+ const mouseOverEvent = document.createEvent('MouseEvents');
+ mouseOverEvent.initEvent('mousedown', true, true);
+ divRef.current.dispatchEvent(mouseOverEvent);
+
+ const mouseMoveEvent = document.createEvent('MouseEvents');
+ for (let index = 0; index <= 20; index++) {
+ mouseMoveEvent.initMouseEvent(
+ 'mousemove',
+ true,
+ true,
+ window,
+ 1,
+ index,
+ index,
+ 50,
+ 50,
+ );
+ divRef.current.dispatchEvent(mouseMoveEvent);
+ }
+ divRef.current.dispatchEvent(mouseMoveEvent);
+
+ const mouseUpEvent = document.createEvent('MouseEvents');
+ mouseUpEvent.initEvent('mouseup', true, true);
+ divRef.current.dispatchEvent(mouseUpEvent);
+
+ expect(events).toHaveLength(2);
+ expect(events).toEqual(
+ expect.arrayContaining([expect.objectContaining({isChanged: true})]),
+ );
+ });
+
+ it('should support onDragStart and onDragEnd', () => {
+ let divRef = React.createRef();
+ let events = [];
+
+ function handleDragStart() {
+ events.push('dragstart');
+ }
+
+ function handleDragEnd() {
+ events.push('dragend');
+ }
+
+ function Component() {
+ return (
+
+ Drag me!
+
+ );
+ }
+
+ ReactDOM.render(, container);
+
+ const mouseOverEvent = document.createEvent('MouseEvents');
+ mouseOverEvent.initEvent('mousedown', true, true);
+ divRef.current.dispatchEvent(mouseOverEvent);
+
+ const mouseMoveEvent = document.createEvent('MouseEvents');
+ for (let index = 0; index <= 20; index++) {
+ mouseMoveEvent.initMouseEvent(
+ 'mousemove',
+ true,
+ true,
+ window,
+ 1,
+ index,
+ index,
+ 50,
+ 50,
+ );
+ divRef.current.dispatchEvent(mouseMoveEvent);
+ }
+ divRef.current.dispatchEvent(mouseMoveEvent);
+
+ const mouseUpEvent = document.createEvent('MouseEvents');
+ mouseUpEvent.initEvent('mouseup', true, true);
+ divRef.current.dispatchEvent(mouseUpEvent);
+
+ expect(events).toEqual(['dragstart', 'dragend']);
+ });
+
+ it('should support onDragMove', () => {
+ let divRef = React.createRef();
+ let events = [];
+
+ function handleDragMove(e) {
+ events.push({
+ diffX: e.diffX,
+ diffY: e.diffY,
+ });
+ }
+
+ function Component() {
+ return (
+
+ Drag me!
+
+ );
+ }
+
+ ReactDOM.render(, container);
+
+ const mouseOverEvent = document.createEvent('MouseEvents');
+ mouseOverEvent.initEvent('mousedown', true, true);
+ divRef.current.dispatchEvent(mouseOverEvent);
+
+ const mouseMoveEvent = document.createEvent('MouseEvents');
+ for (let index = 0; index <= 20; index++) {
+ mouseMoveEvent.initMouseEvent(
+ 'mousemove',
+ true,
+ true,
+ window,
+ 1,
+ index,
+ index,
+ 50,
+ 50,
+ );
+ divRef.current.dispatchEvent(mouseMoveEvent);
+ }
+
+ const mouseUpEvent = document.createEvent('MouseEvents');
+ mouseUpEvent.initEvent('mouseup', true, true);
+ divRef.current.dispatchEvent(mouseUpEvent);
+ expect(events).toHaveLength(20);
+ let index = 0;
+ expect(events).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ diffX: index,
+ diffY: index++,
+ }),
+ ]),
+ );
+ });
+});