Skip to content

Commit

Permalink
fix: onFocus/onBlur/onBeforeInput have a matching event type (#19561)
Browse files Browse the repository at this point in the history
* test: Add current behavior for event types of onFocus/onBlur

* fix: onFocus/onBlur have a matching event type

* fix useFocus

* fix: don't compare native event types with react event types

* Add FocusIn/FocusOutEventInterface

* A simpler alternative fix

* Add regression tests

* Always pass React event type and fix beforeinput

Co-authored-by: Dan Abramov <dan.abramov@me.com>
  • Loading branch information
eps1lon and gaearon committed Aug 10, 2020
1 parent 7c30fb3 commit 7f696bd
Show file tree
Hide file tree
Showing 13 changed files with 241 additions and 41 deletions.
93 changes: 93 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMEventPropagation-test.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/react-dom/src/events/DOMPluginEventSystem.js
Expand Up @@ -709,7 +709,7 @@ export function accumulateSinglePhaseListeners(

let instance = targetFiber;
let lastHostComponent = null;
const targetType = event.type;
const targetType = event.nativeEvent.type;

// Accumulate all instances and listeners via the target -> root path.
while (instance !== null) {
Expand Down
1 change: 1 addition & 0 deletions packages/react-dom/src/events/ReactSyntheticEventType.js
Expand Up @@ -29,6 +29,7 @@ export type ReactSyntheticEvent = {|
_dispatchListeners?: null | Array<Function> | Function,
_reactName: string,
_targetInst: Fiber,
nativeEvent: Event,
type: string,
currentTarget: null | EventTarget,
|};
3 changes: 2 additions & 1 deletion packages/react-dom/src/events/SyntheticEvent.js
Expand Up @@ -14,7 +14,6 @@ import getEventCharCode from './getEventCharCode';
* @see http://www.w3.org/TR/DOM-Level-3-Events/
*/
const EventInterface = {
type: 0,
eventPhase: 0,
bubbles: 0,
cancelable: 0,
Expand Down Expand Up @@ -48,13 +47,15 @@ function functionThatReturnsFalse() {
*/
export function SyntheticEvent(
reactName,
reactEventType,
targetInst,
nativeEvent,
nativeEventTarget,
Interface = EventInterface,
) {
this._reactName = reactName;
this._targetInst = targetInst;
this.type = reactEventType;
this.nativeEvent = nativeEvent;
this.target = nativeEventTarget;
this.currentTarget = null;
Expand Down
@@ -0,0 +1,70 @@
/**
* 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.
*/

'use strict';

describe('SyntheticFocusEvent', () => {
let React;
let ReactDOM;
let container;

beforeEach(() => {
jest.resetModules();
React = require('react');
ReactDOM = require('react-dom');

container = document.createElement('div');
document.body.appendChild(container);
});

afterEach(() => {
document.body.removeChild(container);
container = null;
});

test('onFocus events have the focus type', () => {
const log = [];
ReactDOM.render(
<button
onFocus={event => log.push(`onFocus: ${event.type}`)}
onFocusCapture={event => log.push(`onFocusCapture: ${event.type}`)}
/>,
container,
);
const button = container.querySelector('button');

button.dispatchEvent(
new FocusEvent('focusin', {
bubbles: true,
cancelable: false,
}),
);

expect(log).toEqual(['onFocusCapture: focus', 'onFocus: focus']);
});

test('onBlur events have the blur type', () => {
const log = [];
ReactDOM.render(
<button
onBlur={event => log.push(`onBlur: ${event.type}`)}
onBlurCapture={event => log.push(`onBlurCapture: ${event.type}`)}
/>,
container,
);
const button = container.querySelector('button');

button.dispatchEvent(
new FocusEvent('focusout', {
bubbles: true,
cancelable: false,
}),
);

expect(log).toEqual(['onBlurCapture: blur', 'onBlur: blur']);
});
});
Expand Up @@ -229,6 +229,7 @@ function extractCompositionEvent(

const event = new SyntheticEvent(
eventType,
domEventName,
null,
nativeEvent,
nativeEventTarget,
Expand Down Expand Up @@ -397,6 +398,7 @@ function extractBeforeInputEvent(

const event = new SyntheticEvent(
'onBeforeInput',
'beforeinput',
null,
nativeEvent,
nativeEventTarget,
Expand Down
9 changes: 7 additions & 2 deletions packages/react-dom/src/events/plugins/ChangeEventPlugin.js
Expand Up @@ -49,8 +49,13 @@ function createAndAccumulateChangeEvent(
nativeEvent,
target,
) {
const event = new SyntheticEvent('onChange', null, nativeEvent, target);
event.type = 'change';
const event = new SyntheticEvent(
'onChange',
'change',
null,
nativeEvent,
target,
);
// Flag this event loop as needing state restore.
enqueueStateRestore(((target: any): Node));
accumulateTwoPhaseListeners(inst, dispatchQueue, event);
Expand Down
Expand Up @@ -133,23 +133,23 @@ function extractEvents(

const leave = new SyntheticEvent(
leaveEventType,
eventTypePrefix + 'leave',
from,
nativeEvent,
nativeEventTarget,
eventInterface,
);
leave.type = eventTypePrefix + 'leave';
leave.target = fromNode;
leave.relatedTarget = toNode;

let enter = new SyntheticEvent(
enterEventType,
eventTypePrefix + 'enter',
to,
nativeEvent,
nativeEventTarget,
eventInterface,
);
enter.type = eventTypePrefix + 'enter';
enter.target = toNode;
enter.relatedTarget = fromNode;

Expand Down
3 changes: 1 addition & 2 deletions packages/react-dom/src/events/plugins/SelectEventPlugin.js
Expand Up @@ -114,12 +114,11 @@ function constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget) {

const syntheticEvent = new SyntheticEvent(
'onSelect',
'select',
null,
nativeEvent,
nativeEventTarget,
);

syntheticEvent.type = 'select';
syntheticEvent.target = activeElement;

accumulateTwoPhaseListeners(
Expand Down
8 changes: 8 additions & 0 deletions packages/react-dom/src/events/plugins/SimpleEventPlugin.js
Expand Up @@ -63,6 +63,7 @@ function extractEvents(
return;
}
let EventInterface;
let reactEventType = domEventName;
switch (domEventName) {
case 'keypress':
// Firefox creates a keypress event for function keys too. This removes
Expand All @@ -77,7 +78,13 @@ function extractEvents(
EventInterface = KeyboardEventInterface;
break;
case 'focusin':
reactEventType = 'focus';
EventInterface = FocusEventInterface;
break;
case 'focusout':
reactEventType = 'blur';
EventInterface = FocusEventInterface;
break;
case 'beforeblur':
case 'afterblur':
EventInterface = FocusEventInterface;
Expand Down Expand Up @@ -152,6 +159,7 @@ function extractEvents(
}
const event = new SyntheticEvent(
reactName,
reactEventType,
null,
nativeEvent,
nativeEventTarget,
Expand Down

0 comments on commit 7f696bd

Please sign in to comment.