Fix movementX/Y polyfill with capture events (#19672)
* Fix movementX/Y polyfill with capture events * Remove unnecesary call for better inlining
Dan Abramov committed
Aug 21, 2020 at 16:55 UTC
90d212d326d8bb8f5ee414801db37e688d585712
2 files changed
+86
-25
packages/react-dom/src/events/SyntheticEvent.js
+22
-25
@@ -152,11 +152,22 @@ export const UIEventInterface: EventInterfaceType = {
152
detail: 0,
153
};
154
155
-let previousScreenX = 0;
156
-let previousScreenY = 0;
157
-// Use flags to signal movementX/Y has already been set
158
-let isMovementXSet = false;
159
-let isMovementYSet = false;
155
+let lastMovementX;
156
+let lastMovementY;
157
+let lastMouseEvent;
158
+
159
+function updateMouseMovementPolyfillState(event) {
160
+ if (event !== lastMouseEvent) {
161
+ if (lastMouseEvent && event.type === 'mousemove') {
162
+ lastMovementX = event.screenX - lastMouseEvent.screenX;
163
+ lastMovementY = event.screenY - lastMouseEvent.screenY;
164
+ } else {
165
+ lastMovementX = 0;
166
+ lastMovementY = 0;
167
+ }
168
+ lastMouseEvent = event;
169
+ }
170
+}
171
172
/**
173
* @interface MouseEvent
@@ -189,31 +200,17 @@ export const MouseEventInterface: EventInterfaceType = {
200
if ('movementX' in event) {
201
return event.movementX;
202
}
192
-
193
- const screenX = previousScreenX;
194
- previousScreenX = event.screenX;
195
-
196
- if (!isMovementXSet) {
197
- isMovementXSet = true;
198
- return 0;
199
- }
200
-
201
- return event.type === 'mousemove' ? event.screenX - screenX : 0;
203
+ updateMouseMovementPolyfillState(event);
204
+ return lastMovementX;
205
},
206
movementY: function(event) {
207
if ('movementY' in event) {
208
return event.movementY;
209
}
207
-
208
- const screenY = previousScreenY;
209
- previousScreenY = event.screenY;
210
-
211
- if (!isMovementYSet) {
212
- isMovementYSet = true;
213
- return 0;
214
- }
215
-
216
- return event.type === 'mousemove' ? event.screenY - screenY : 0;
210
+ // Don't need to call updateMouseMovementPolyfillState() here
211
+ // because it's guaranteed to have already run when movementX
212
+ // was copied.
213
+ return lastMovementY;
214
},
215
};
216
packages/react-dom/src/events/__tests__/SyntheticMouseEvent-test.js
+64
@@ -16,6 +16,7 @@ describe('SyntheticMouseEvent', () => {
16
let container;
17
18
beforeEach(() => {
19
+ jest.resetModules();
20
React = require('react');
21
ReactDOM = require('react-dom');
22
@@ -77,4 +78,67 @@ describe('SyntheticMouseEvent', () => {
78
expect(events[1]).toBe(6);
79
expect(events[2]).toBe(0); // mousedown event should have movementX at 0
80
});
81
+
82
+ it('should correctly calculate movementX/Y for capture phase', () => {
83
+ const events = [];
84
+ const onMouseMove = event => {
85
+ events.push(['move', false, event.movementX, event.movementY]);
86
+ };
87
+ const onMouseMoveCapture = event => {
88
+ events.push(['move', true, event.movementX, event.movementY]);
89
+ };
90
+ const onMouseDown = event => {
91
+ events.push(['down', false, event.movementX, event.movementY]);
92
+ };
93
+ const onMouseDownCapture = event => {
94
+ events.push(['down', true, event.movementX, event.movementY]);
95
+ };
96
+
97
+ const node = ReactDOM.render(
98
+ <div
99
+ onMouseMove={onMouseMove}
100
+ onMouseMoveCapture={onMouseMoveCapture}
101
+ onMouseDown={onMouseDown}
102
+ onMouseDownCapture={onMouseDownCapture}
103
+ />,
104
+ container,
105
+ );
106
+
107
+ let event = new MouseEvent('mousemove', {
108
+ relatedTarget: null,
109
+ bubbles: true,
110
+ screenX: 2,
111
+ screenY: 2,
112
+ });
113
+
114
+ node.dispatchEvent(event);
115
+
116
+ event = new MouseEvent('mousemove', {
117
+ relatedTarget: null,
118
+ bubbles: true,
119
+ screenX: 8,
120
+ screenY: 9,
121
+ });
122
+
123
+ node.dispatchEvent(event);
124
+
125
+ // Now trigger a mousedown event to see if movementX has changed back to 0
126
+ event = new MouseEvent('mousedown', {
127
+ relatedTarget: null,
128
+ bubbles: true,
129
+ screenX: 25,
130
+ screenY: 65,
131
+ });
132
+
133
+ node.dispatchEvent(event);
134
+
135
+ expect(events).toEqual([
136
+ ['move', true, 0, 0],
137
+ ['move', false, 0, 0],
138
+ ['move', true, 6, 7],
139
+ ['move', false, 6, 7],
140
+ ['down', true, 0, 0],
141
+ ['down', false, 0, 0],
142
+ ]);
143
+ });
144
});