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++, + }), + ]), + ); + }); +});