@samitouri / QOS-React-2 / commits / a59f899a1d

Modern Event System: use focusin/focusout for onFocus/onBlur (#19186)

Dominic Gannaway committed Jul 16, 2020 at 18:12 UTC a59f899a1d021b231f8bd830436708294d9022c0
11 files changed +45 -44
packages/react-dom/src/__tests__/ReactDOMInput-test.js
+5
@@ -183,6 +183,7 @@ describe('ReactDOMInput', () => {
183 // bypass the lazy event attachment system so we won't actually test this.
184 dispatchEventOnNode(instance.a, 'input');
185 dispatchEventOnNode(instance.a, 'blur');
186 + dispatchEventOnNode(instance.a, 'focusout');
187
188 expect(instance.a.value).toBe('giraffe');
189 expect(instance.switchedFocus).toBe(true);
@@ -684,6 +685,7 @@ describe('ReactDOMInput', () => {
685 expect(node.hasAttribute('value')).toBe(false);
686 } else {
687 dispatchEventOnNode(node, 'blur');
688 + dispatchEventOnNode(node, 'focusout');
689
690 expect(node.value).toBe('0.0');
691 expect(node.getAttribute('value')).toBe('0.0');
@@ -1771,6 +1773,7 @@ describe('ReactDOMInput', () => {
1773 // be the only way to remove focus in JSDOM
1774 node.blur();
1775 dispatchEventOnNode(node, 'blur');
1776 + dispatchEventOnNode(node, 'focusout');
1777
1778 if (disableInputAttributeSyncing) {
1779 expect(node.value).toBe('2');
@@ -1796,6 +1799,7 @@ describe('ReactDOMInput', () => {
1799 // be the only way to remove focus in JSDOM
1800 node.blur();
1801 dispatchEventOnNode(node, 'blur');
1802 + dispatchEventOnNode(node, 'focusout');
1803
1804 expect(node.getAttribute('value')).toBe('1');
1805 });
@@ -1815,6 +1819,7 @@ describe('ReactDOMInput', () => {
1819 // be the only way to remove focus in JSDOM
1820 node.blur();
1821 dispatchEventOnNode(node, 'blur');
1822 + dispatchEventOnNode(node, 'focusout');
1823
1824 expect(node.getAttribute('value')).toBe('1');
1825 });
packages/react-dom/src/events/DOMEventProperties.js
+2 -2
@@ -41,7 +41,6 @@ const eventPriorities = new Map();
41
42 // prettier-ignore
43 const discreteEventPairsForSimpleEventPlugin = [
44 - DOMTopLevelEventTypes.TOP_BLUR, 'blur',
44 DOMTopLevelEventTypes.TOP_CANCEL, 'cancel',
45 DOMTopLevelEventTypes.TOP_CLICK, 'click',
46 DOMTopLevelEventTypes.TOP_CLOSE, 'close',
@@ -53,7 +52,8 @@ const discreteEventPairsForSimpleEventPlugin = [
52 DOMTopLevelEventTypes.TOP_DRAG_END, 'dragEnd',
53 DOMTopLevelEventTypes.TOP_DRAG_START, 'dragStart',
54 DOMTopLevelEventTypes.TOP_DROP, 'drop',
56 - DOMTopLevelEventTypes.TOP_FOCUS, 'focus',
55 + DOMTopLevelEventTypes.TOP_FOCUS_IN, 'focus',
56 + DOMTopLevelEventTypes.TOP_FOCUS_OUT, 'blur',
57 DOMTopLevelEventTypes.TOP_INPUT, 'input',
58 DOMTopLevelEventTypes.TOP_INVALID, 'invalid',
59 DOMTopLevelEventTypes.TOP_KEY_DOWN, 'keyDown',
packages/react-dom/src/events/DOMModernPluginEventSystem.js
-4
@@ -37,12 +37,10 @@ import {
37
38 import getEventTarget from './getEventTarget';
39 import {
40 - TOP_FOCUS,
40 TOP_LOAD,
41 TOP_ABORT,
42 TOP_CANCEL,
43 TOP_INVALID,
45 - TOP_BLUR,
44 TOP_SCROLL,
45 TOP_CLOSE,
46 TOP_RESET,
@@ -215,8 +213,6 @@ function extractEvents(
213 }
214
215 export const capturePhaseEvents: Set<DOMTopLevelEventType> = new Set([
218 - TOP_FOCUS,
219 - TOP_BLUR,
216 TOP_SCROLL,
217 TOP_LOAD,
218 TOP_ABORT,
packages/react-dom/src/events/DOMTopLevelEventTypes.js
+3 -2
@@ -32,7 +32,6 @@ export const TOP_ANIMATION_ITERATION = unsafeCastStringToDOMTopLevelType(
32 export const TOP_ANIMATION_START = unsafeCastStringToDOMTopLevelType(
33 getVendorPrefixedEventName('animationstart'),
34 );
35 -export const TOP_BLUR = unsafeCastStringToDOMTopLevelType('blur');
35 export const TOP_CAN_PLAY = unsafeCastStringToDOMTopLevelType('canplay');
36 export const TOP_CAN_PLAY_THROUGH = unsafeCastStringToDOMTopLevelType(
37 'canplaythrough',
@@ -72,7 +71,6 @@ export const TOP_EMPTIED = unsafeCastStringToDOMTopLevelType('emptied');
71 export const TOP_ENCRYPTED = unsafeCastStringToDOMTopLevelType('encrypted');
72 export const TOP_ENDED = unsafeCastStringToDOMTopLevelType('ended');
73 export const TOP_ERROR = unsafeCastStringToDOMTopLevelType('error');
75 -export const TOP_FOCUS = unsafeCastStringToDOMTopLevelType('focus');
74 export const TOP_GOT_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType(
75 'gotpointercapture',
76 );
@@ -152,6 +150,9 @@ export const TOP_WHEEL = unsafeCastStringToDOMTopLevelType('wheel');
150 export const TOP_AFTER_BLUR = unsafeCastStringToDOMTopLevelType('afterblur');
151 export const TOP_BEFORE_BLUR = unsafeCastStringToDOMTopLevelType('beforeblur');
152
153 +export const TOP_FOCUS_IN = unsafeCastStringToDOMTopLevelType('focusin');
154 +export const TOP_FOCUS_OUT = unsafeCastStringToDOMTopLevelType('focusout');
155 +
156 // List of events that need to be individually attached to media elements.
157 // Note that events in this list will *not* be listened to at the top level
158 // unless they're explicitly listed in `ReactBrowserEventEmitter.listenTo`.
packages/react-dom/src/events/ReactDOMEventReplaying.js
+7 -7
@@ -131,8 +131,8 @@ import {
131 TOP_POINTER_OUT,
132 TOP_GOT_POINTER_CAPTURE,
133 TOP_LOST_POINTER_CAPTURE,
134 - TOP_FOCUS,
135 - TOP_BLUR,
134 + TOP_FOCUS_IN,
135 + TOP_FOCUS_OUT,
136 } from './DOMTopLevelEventTypes';
137 import {IS_REPLAYED, PLUGIN_EVENT_SYSTEM} from './EventSystemFlags';
138 import {
@@ -216,10 +216,10 @@ const discreteReplayableEvents = [
216 ];
217
218 const continuousReplayableEvents = [
219 - TOP_FOCUS,
220 - TOP_BLUR,
219 TOP_DRAG_ENTER,
220 TOP_DRAG_LEAVE,
221 + TOP_FOCUS_IN,
222 + TOP_FOCUS_OUT,
223 TOP_MOUSE_OVER,
224 TOP_MOUSE_OUT,
225 TOP_POINTER_OVER,
@@ -362,8 +362,8 @@ export function clearIfContinuousEvent(
362 nativeEvent: AnyNativeEvent,
363 ): void {
364 switch (topLevelType) {
365 - case TOP_FOCUS:
366 - case TOP_BLUR:
365 + case TOP_FOCUS_IN:
366 + case TOP_FOCUS_OUT:
367 queuedFocus = null;
368 break;
369 case TOP_DRAG_ENTER:
@@ -443,7 +443,7 @@ export function queueIfContinuousEvent(
443 // moved from outside the window (no target) onto the target once it hydrates.
444 // Instead of mutating we could clone the event.
445 switch (topLevelType) {
446 - case TOP_FOCUS: {
446 + case TOP_FOCUS_IN: {
447 const focusEvent = ((nativeEvent: any): FocusEvent);
448 queuedFocus = accumulateOrCreateContinuousQueuedReplayableEvent(
449 queuedFocus,
packages/react-dom/src/events/__tests__/DOMModernPluginEventSystem-test.internal.js
+3 -3
@@ -888,9 +888,9 @@ describe('DOMModernPluginEventSystem', () => {
888 expect(onFocus).toHaveBeenCalledTimes(3);
889 expect(onFocusCapture).toHaveBeenCalledTimes(3);
890 expect(log[2]).toEqual(['capture', buttonElement]);
891 - expect(log[3]).toEqual(['bubble', buttonElement]);
892 - expect(log[4]).toEqual(['capture', divElement]);
893 - expect(log[5]).toEqual(['bubble', divElement]);
891 + expect(log[3]).toEqual(['capture', divElement]);
892 + expect(log[4]).toEqual(['bubble', divElement]);
893 + expect(log[5]).toEqual(['bubble', buttonElement]);
894 });
895
896 it('handle propagation of focus events between portals', () => {
packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js
+5 -5
@@ -11,7 +11,7 @@ import {canUseDOM} from 'shared/ExecutionEnvironment';
11
12 import {registerTwoPhaseEvent} from '../EventRegistry';
13 import {
14 - TOP_BLUR,
14 + TOP_FOCUS_OUT,
15 TOP_COMPOSITION_START,
16 TOP_COMPOSITION_END,
17 TOP_COMPOSITION_UPDATE,
@@ -66,24 +66,24 @@ function registerEvents() {
66 TOP_PASTE,
67 ]);
68 registerTwoPhaseEvent('onCompositionEnd', [
69 - TOP_BLUR,
69 TOP_COMPOSITION_END,
70 + TOP_FOCUS_OUT,
71 TOP_KEY_DOWN,
72 TOP_KEY_PRESS,
73 TOP_KEY_UP,
74 TOP_MOUSE_DOWN,
75 ]);
76 registerTwoPhaseEvent('onCompositionStart', [
77 - TOP_BLUR,
77 TOP_COMPOSITION_START,
78 + TOP_FOCUS_OUT,
79 TOP_KEY_DOWN,
80 TOP_KEY_PRESS,
81 TOP_KEY_UP,
82 TOP_MOUSE_DOWN,
83 ]);
84 registerTwoPhaseEvent('onCompositionUpdate', [
85 - TOP_BLUR,
85 TOP_COMPOSITION_UPDATE,
86 + TOP_FOCUS_OUT,
87 TOP_KEY_DOWN,
88 TOP_KEY_PRESS,
89 TOP_KEY_UP,
@@ -154,7 +154,7 @@ function isFallbackCompositionEnd(topLevelType, nativeEvent) {
154 return nativeEvent.keyCode !== START_KEYCODE;
155 case TOP_KEY_PRESS:
156 case TOP_MOUSE_DOWN:
157 - case TOP_BLUR:
157 + case TOP_FOCUS_OUT:
158 // Events are not possible without cancelling IME.
159 return true;
160 default:
packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js
+7 -7
@@ -17,10 +17,10 @@ import isTextInputElement from '../isTextInputElement';
17 import {canUseDOM} from 'shared/ExecutionEnvironment';
18
19 import {
20 - TOP_BLUR,
20 + TOP_FOCUS_OUT,
21 TOP_CHANGE,
22 TOP_CLICK,
23 - TOP_FOCUS,
23 + TOP_FOCUS_IN,
24 TOP_INPUT,
25 TOP_KEY_DOWN,
26 TOP_KEY_UP,
@@ -42,10 +42,10 @@ import {
42
43 function registerEvents() {
44 registerTwoPhaseEvent('onChange', [
45 - TOP_BLUR,
45 TOP_CHANGE,
46 TOP_CLICK,
48 - TOP_FOCUS,
47 + TOP_FOCUS_IN,
48 + TOP_FOCUS_OUT,
49 TOP_INPUT,
50 TOP_KEY_DOWN,
51 TOP_KEY_UP,
@@ -172,7 +172,7 @@ function handlePropertyChange(nativeEvent) {
172 }
173
174 function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
175 - if (topLevelType === TOP_FOCUS) {
175 + if (topLevelType === TOP_FOCUS_IN) {
176 // In IE9, propertychange fires for most input events but is buggy and
177 // doesn't fire when text is deleted, but conveniently, selectionchange
178 // appears to fire in all of the remaining cases so we catch those and
@@ -185,7 +185,7 @@ function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
185 // missed a blur event somehow.
186 stopWatchingForValueChange();
187 startWatchingForValueChange(target, targetInst);
188 - } else if (topLevelType === TOP_BLUR) {
188 + } else if (topLevelType === TOP_FOCUS_OUT) {
189 stopWatchingForValueChange();
190 }
191 }
@@ -304,7 +304,7 @@ function extractEvents(
304 }
305
306 // When blurring, set the value attribute for number inputs
307 - if (topLevelType === TOP_BLUR) {
307 + if (topLevelType === TOP_FOCUS_OUT) {
308 handleControlledInputBlur(((targetNode: any): HTMLInputElement));
309 }
310 }
packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js
+6 -6
@@ -12,10 +12,10 @@ import shallowEqual from 'shared/shallowEqual';
12
13 import {registerTwoPhaseEvent} from '../EventRegistry';
14 import {
15 - TOP_BLUR,
15 + TOP_FOCUS_OUT,
16 TOP_CONTEXT_MENU,
17 TOP_DRAG_END,
18 - TOP_FOCUS,
18 + TOP_FOCUS_IN,
19 TOP_KEY_DOWN,
20 TOP_KEY_UP,
21 TOP_MOUSE_DOWN,
@@ -35,10 +35,10 @@ const skipSelectionChangeEvent =
35 canUseDOM && 'documentMode' in document && document.documentMode <= 11;
36
37 const rootTargetDependencies = [
38 - TOP_BLUR,
38 + TOP_FOCUS_OUT,
39 TOP_CONTEXT_MENU,
40 TOP_DRAG_END,
41 - TOP_FOCUS,
41 + TOP_FOCUS_IN,
42 TOP_KEY_DOWN,
43 TOP_KEY_UP,
44 TOP_MOUSE_DOWN,
@@ -186,7 +186,7 @@ function extractEvents(
186
187 switch (topLevelType) {
188 // Track the input node that has focus.
189 - case TOP_FOCUS:
189 + case TOP_FOCUS_IN:
190 if (
191 isTextInputElement(targetNode) ||
192 targetNode.contentEditable === 'true'
@@ -196,7 +196,7 @@ function extractEvents(
196 lastSelection = null;
197 }
198 break;
199 - case TOP_BLUR:
199 + case TOP_FOCUS_OUT:
200 activeElement = null;
201 activeElementInst = null;
202 lastSelection = null;
packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js
+2 -2
@@ -68,8 +68,8 @@ function extractEvents(
68 case DOMTopLevelEventTypes.TOP_KEY_UP:
69 EventConstructor = SyntheticKeyboardEvent;
70 break;
71 - case DOMTopLevelEventTypes.TOP_BLUR:
72 - case DOMTopLevelEventTypes.TOP_FOCUS:
71 + case DOMTopLevelEventTypes.TOP_FOCUS_IN:
72 + case DOMTopLevelEventTypes.TOP_FOCUS_OUT:
73 case DOMTopLevelEventTypes.TOP_BEFORE_BLUR:
74 case DOMTopLevelEventTypes.TOP_AFTER_BLUR:
75 EventConstructor = SyntheticFocusEvent;
packages/react-interactions/events/src/dom/create-event-handle/Focus.js
+5 -6
@@ -126,7 +126,6 @@ function handleGlobalFocusVisibleEvent(
126 }
127
128 const passiveObject = {passive: true};
129 -const passiveObjectWithPriority = {passive: true, priority: 0};
129
130 function handleFocusVisibleTargetEvent(
131 type: string,
@@ -243,8 +242,8 @@ export function useFocus(
242 ): void {
243 // Setup controlled state for this useFocus hook
244 const stateRef = useRef({isFocused: false, isFocusVisible: false});
246 - const focusHandle = useEvent('focusin', passiveObjectWithPriority);
247 - const blurHandle = useEvent('focusout', passiveObjectWithPriority);
245 + const focusHandle = useEvent('focusin', passiveObject);
246 + const blurHandle = useEvent('focusout', passiveObject);
247 const focusVisibleHandles = useFocusVisibleInputHandles();
248
249 useEffect(() => {
@@ -334,8 +333,8 @@ export function useFocusWithin(
333 const stateRef = useRef<null | {isFocused: boolean, isFocusVisible: boolean}>(
334 {isFocused: false, isFocusVisible: false},
335 );
337 - const focusHandle = useEvent('focusin', passiveObjectWithPriority);
338 - const blurHandle = useEvent('focusout', passiveObjectWithPriority);
336 + const focusHandle = useEvent('focusin', passiveObject);
337 + const blurHandle = useEvent('focusout', passiveObject);
338 const afterBlurHandle = useEvent('afterblur', passiveObject);
339 const beforeBlurHandle = useEvent('beforeblur', passiveObject);
340 const focusVisibleHandles = useFocusVisibleInputHandles();
@@ -397,7 +396,7 @@ export function useFocusWithin(
396 if (disabled) {
397 return;
398 }
400 - const {relatedTarget} = (event.nativeEvent: any);
399 + const {relatedTarget} = (event: any);
400
401 if (
402 state.isFocused &&