Skip to content

Commit 87eaa90

Browse files
authored
[react-events] Keyboard calls preventDefault on 'click' events (#16779)
Make sure to call preventDefault for any 'click' events that follow a 'keydown' event that matches 'preventKeys'
1 parent 0c0b30b commit 87eaa90

File tree

4 files changed

+237
-223
lines changed

4 files changed

+237
-223
lines changed

packages/react-events/src/dom/Keyboard.js

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,32 @@ import React from 'react';
1616
import {DiscreteEvent} from 'shared/ReactTypes';
1717
import type {ReactEventResponderListener} from 'shared/ReactTypes';
1818

19-
type KeyboardEventType = 'keydown' | 'keyup';
19+
type KeyboardEventType = 'keyboard:keydown' | 'keyboard:keyup';
2020

21-
type KeyboardProps = {
21+
type KeyboardProps = {|
2222
disabled?: boolean,
2323
onKeyDown?: (e: KeyboardEvent) => ?boolean,
2424
onKeyUp?: (e: KeyboardEvent) => ?boolean,
2525
preventKeys?: PreventKeysArray,
26-
};
26+
|};
27+
28+
type KeyboardState = {|
29+
defaultPrevented: boolean,
30+
isActive: boolean,
31+
|};
2732

2833
export type KeyboardEvent = {|
2934
altKey: boolean,
3035
ctrlKey: boolean,
36+
defaultPrevented: boolean,
3137
isComposing: boolean,
3238
key: string,
3339
metaKey: boolean,
40+
pointerType: 'keyboard',
3441
shiftKey: boolean,
3542
target: Element | Document,
3643
type: KeyboardEventType,
3744
timeStamp: number,
38-
defaultPrevented: boolean,
3945
|};
4046

4147
type ModifiersObject = {|
@@ -48,7 +54,7 @@ type ModifiersObject = {|
4854
type PreventKeysArray = Array<string | Array<string | ModifiersObject>>;
4955

5056
const isArray = Array.isArray;
51-
const targetEventTypes = ['keydown_active', 'keyup'];
57+
const targetEventTypes = ['click_active', 'keydown_active', 'keyup'];
5258
const modifiers = ['altKey', 'ctrlKey', 'metaKey', 'shiftKey'];
5359

5460
/**
@@ -150,6 +156,7 @@ function createKeyboardEvent(
150156
isComposing,
151157
key: getEventKey(nativeEvent),
152158
metaKey,
159+
pointerType: 'keyboard',
153160
shiftKey,
154161
target: event.target,
155162
timeStamp: context.getTimeStamp(),
@@ -182,21 +189,30 @@ function dispatchKeyboardEvent(
182189

183190
const keyboardResponderImpl = {
184191
targetEventTypes,
192+
getInitialState(): KeyboardState {
193+
return {
194+
defaultPrevented: false,
195+
isActive: false,
196+
};
197+
},
185198
onEvent(
186199
event: ReactDOMResponderEvent,
187200
context: ReactDOMResponderContext,
188201
props: KeyboardProps,
202+
state: KeyboardState,
189203
): void {
190204
const {type} = event;
191205
const nativeEvent: any = event.nativeEvent;
192206

193207
if (props.disabled) {
194208
return;
195209
}
196-
let defaultPrevented = nativeEvent.defaultPrevented === true;
210+
197211
if (type === 'keydown') {
212+
state.defaultPrevented = nativeEvent.defaultPrevented === true;
213+
198214
const preventKeys = ((props.preventKeys: any): PreventKeysArray);
199-
if (!defaultPrevented && isArray(preventKeys)) {
215+
if (!state.defaultPrevented && isArray(preventKeys)) {
200216
preventKeyLoop: for (let i = 0; i < preventKeys.length; i++) {
201217
const preventKey = preventKeys[i];
202218
let key = preventKey;
@@ -216,32 +232,38 @@ const keyboardResponderImpl = {
216232
}
217233
}
218234
}
235+
219236
if (key === getEventKey(nativeEvent)) {
220-
defaultPrevented = true;
237+
state.defaultPrevented = true;
221238
nativeEvent.preventDefault();
222239
break;
223240
}
224241
}
225242
}
243+
state.isActive = true;
226244
const onKeyDown = props.onKeyDown;
227245
if (isFunction(onKeyDown)) {
228246
dispatchKeyboardEvent(
229247
event,
230248
((onKeyDown: any): (e: KeyboardEvent) => ?boolean),
231249
context,
232-
'keydown',
233-
defaultPrevented,
250+
'keyboard:keydown',
251+
state.defaultPrevented,
234252
);
235253
}
254+
} else if (type === 'click' && state.isActive && state.defaultPrevented) {
255+
// 'click' occurs before 'keyup' and may need native behavior prevented
256+
nativeEvent.preventDefault();
236257
} else if (type === 'keyup') {
258+
state.isActive = false;
237259
const onKeyUp = props.onKeyUp;
238260
if (isFunction(onKeyUp)) {
239261
dispatchKeyboardEvent(
240262
event,
241263
((onKeyUp: any): (e: KeyboardEvent) => ?boolean),
242264
context,
243-
'keyup',
244-
defaultPrevented,
265+
'keyboard:keyup',
266+
state.defaultPrevented,
245267
);
246268
}
247269
}

0 commit comments

Comments
 (0)