@samitouri / QOS-React / commits / b61174fb7b

Remove the deprecated React Flare event system (#19520)

Dominic Gannaway committed Aug 5, 2020 at 15:13 UTC b61174fb7b09580c1ec2a8f55e73204b706d2935
92 files changed +125 -12325
packages/react-art/src/ReactARTHostConfig.js
-20
@@ -10,10 +10,6 @@ import Mode from 'art/modes/current';
10 import invariant from 'shared/invariant';
11
12 import {TYPES, EVENT_TYPES, childrenAsString} from './ReactARTInternals';
13 -import type {
14 - ReactEventResponder,
15 - ReactEventResponderInstance,
16 -} from 'shared/ReactTypes';
13
14 const pooledTransform = new Transform();
15
@@ -429,22 +425,6 @@ export function clearContainer(container) {
425 // TODO Implement this
426 }
427
432 -export function DEPRECATED_mountResponderInstance(
433 - responder: ReactEventResponder<any, any>,
434 - responderInstance: ReactEventResponderInstance<any, any>,
435 - props: Object,
436 - state: Object,
437 - instance: Object,
438 -) {
439 - throw new Error('Not yet implemented.');
440 -}
441 -
442 -export function DEPRECATED_unmountResponderInstance(
443 - responderInstance: ReactEventResponderInstance<any, any>,
444 -): void {
445 - throw new Error('Not yet implemented.');
446 -}
447 -
428 export function getFundamentalComponentInstance(fundamentalInstance) {
429 throw new Error('Not yet implemented.');
430 }
packages/react-debug-tools/src/ReactDebugHooks.js
-19
@@ -13,8 +13,6 @@ import type {
13 MutableSourceSubscribeFn,
14 ReactContext,
15 ReactProviderType,
16 - ReactEventResponder,
17 - ReactEventResponderListener,
16 } from 'shared/ReactTypes';
17 import type {
18 Fiber,
@@ -260,22 +258,6 @@ function useMutableSource<Source, Snapshot>(
258 return value;
259 }
260
263 -function useResponder(
264 - responder: ReactEventResponder<any, any>,
265 - listenerProps: Object,
266 -): ReactEventResponderListener<any, any> {
267 - // Don't put the actual event responder object in, just its displayName
268 - const value = {
269 - responder: responder.displayName || 'EventResponder',
270 - props: listenerProps,
271 - };
272 - hookLog.push({primitive: 'Responder', stackError: new Error(), value});
273 - return {
274 - responder,
275 - props: listenerProps,
276 - };
277 -}
278 -
261 function useTransition(
262 config: SuspenseConfig | null | void,
263 ): [(() => void) => void, boolean] {
@@ -335,7 +317,6 @@ const Dispatcher: DispatcherType = {
317 useReducer,
318 useRef,
319 useState,
338 - useResponder,
320 useTransition,
321 useMutableSource,
322 useDeferredValue,
packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.internal.js deleted
-46
@@ -1,46 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - * @jest-environment node
9 - */
10 -
11 -'use strict';
12 -
13 -let React;
14 -let ReactDebugTools;
15 -
16 -describe('ReactHooksInspection', () => {
17 - beforeEach(() => {
18 - jest.resetModules();
19 - const ReactFeatureFlags = require('shared/ReactFeatureFlags');
20 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
21 - React = require('react');
22 - ReactDebugTools = require('react-debug-tools');
23 - });
24 -
25 - // @gate experimental
26 - it('should inspect a simple useResponder hook', () => {
27 - const TestResponder = React.DEPRECATED_createResponder('TestResponder', {});
28 -
29 - function Foo(props) {
30 - const listener = React.DEPRECATED_useResponder(TestResponder, {
31 - preventDefault: false,
32 - });
33 - return <div DEPRECATED_flareListeners={listener}>Hello world</div>;
34 - }
35 - const tree = ReactDebugTools.inspectHooks(Foo, {});
36 - expect(tree).toEqual([
37 - {
38 - isStateEditable: false,
39 - id: 0,
40 - name: 'Responder',
41 - value: {props: {preventDefault: false}, responder: 'TestResponder'},
42 - subHooks: [],
43 - },
44 - ]);
45 - });
46 -});
packages/react-devtools-shared/src/backend/ReactSymbols.js
-3
@@ -58,9 +58,6 @@ export const PROFILER_SYMBOL_STRING = 'Symbol(react.profiler)';
58 export const PROVIDER_NUMBER = 0xeacd;
59 export const PROVIDER_SYMBOL_STRING = 'Symbol(react.provider)';
60
61 -export const RESPONDER_NUMBER = 0xead6;
62 -export const RESPONDER_SYMBOL_STRING = 'Symbol(react.responder)';
63 -
61 export const SCOPE_NUMBER = 0xead7;
62 export const SCOPE_SYMBOL_STRING = 'Symbol(react.scope)';
63
packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js
+25 -140
@@ -17,7 +17,6 @@ let ReactFeatureFlags;
17 let Suspense;
18 let SuspenseList;
19 let act;
20 -let useHover;
20
21 function dispatchMouseEvent(to, from) {
22 if (!to) {
@@ -76,7 +75,7 @@ describe('ReactDOMServerPartialHydration', () => {
75
76 ReactFeatureFlags = require('shared/ReactFeatureFlags');
77 ReactFeatureFlags.enableSuspenseCallback = true;
79 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
78 + ReactFeatureFlags.enableCreateEventHandleAPI = true;
79
80 React = require('react');
81 ReactDOM = require('react-dom');
@@ -2202,8 +2201,10 @@ describe('ReactDOMServerPartialHydration', () => {
2201 });
2202
2203 // @gate experimental
2205 - it('does not invoke an event on a hydrated EventResponder until it commits', async () => {
2204 + it('does not invoke an event on a hydrated event handle until it commits', async () => {
2205 + const setClick = ReactDOM.unstable_createEventHandle('click');
2206 let suspend = false;
2207 + let isServerRendering = true;
2208 let resolve;
2209 const promise = new Promise(resolvePromise => (resolve = resolvePromise));
2210
@@ -2216,17 +2217,15 @@ describe('ReactDOMServerPartialHydration', () => {
2217 }
2218
2219 const onEvent = jest.fn();
2219 - const TestResponder = React.DEPRECATED_createResponder(
2220 - 'TestEventResponder',
2221 - {
2222 - targetEventTypes: ['click'],
2223 - onEvent,
2224 - },
2225 - );
2220
2221 function Button() {
2228 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
2229 - return <a DEPRECATED_flareListeners={listener}>Click me</a>;
2222 + const ref = React.useRef(null);
2223 + if (!isServerRendering) {
2224 + React.useLayoutEffect(() => {
2225 + return setClick(ref.current, onEvent);
2226 + });
2227 + }
2228 + return <a ref={ref}>Click me</a>;
2229 }
2230
2231 function App() {
@@ -2253,6 +2252,7 @@ describe('ReactDOMServerPartialHydration', () => {
2252 // On the client we don't have all data yet but we want to start
2253 // hydrating anyway.
2254 suspend = true;
2255 + isServerRendering = false;
2256 const root = ReactDOM.createRoot(container, {hydrate: true});
2257 root.render(<App />);
2258
@@ -2364,23 +2364,25 @@ describe('ReactDOMServerPartialHydration', () => {
2364 });
2365
2366 // @gate experimental
2367 - it('invokes discrete events on nested suspense boundaries in a root (responder system)', async () => {
2367 + it('invokes discrete events on nested suspense boundaries in a root (createEventHandle)', async () => {
2368 let suspend = false;
2369 + let isServerRendering = true;
2370 let resolve;
2371 const promise = new Promise(resolvePromise => (resolve = resolvePromise));
2372
2373 const onEvent = jest.fn();
2373 - const TestResponder = React.DEPRECATED_createResponder(
2374 - 'TestEventResponder',
2375 - {
2376 - targetEventTypes: ['click'],
2377 - onEvent,
2378 - },
2379 - );
2374 + const setClick = ReactDOM.unstable_createEventHandle('click');
2375
2376 function Button() {
2382 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
2383 - return <a DEPRECATED_flareListeners={listener}>Click me</a>;
2377 + const ref = React.useRef(null);
2378 +
2379 + if (!isServerRendering) {
2380 + React.useLayoutEffect(() => {
2381 + return setClick(ref.current, onEvent);
2382 + });
2383 + }
2384 +
2385 + return <a ref={ref}>Click me</a>;
2386 }
2387
2388 function Child() {
@@ -2416,6 +2418,7 @@ describe('ReactDOMServerPartialHydration', () => {
2418 // On the client we don't have all data yet but we want to start
2419 // hydrating anyway.
2420 suspend = true;
2421 + isServerRendering = false;
2422 const root = ReactDOM.createRoot(container, {hydrate: true});
2423 root.render(<App />);
2424
@@ -2704,124 +2707,6 @@ describe('ReactDOMServerPartialHydration', () => {
2707 document.body.removeChild(container);
2708 });
2709
2707 - // @gate experimental
2708 - it('blocks only on the last continuous event (Responder system)', async () => {
2709 - useHover = require('react-interactions/events/hover').useHover;
2710 -
2711 - let suspend1 = false;
2712 - let resolve1;
2713 - const promise1 = new Promise(resolvePromise => (resolve1 = resolvePromise));
2714 - let suspend2 = false;
2715 - let resolve2;
2716 - const promise2 = new Promise(resolvePromise => (resolve2 = resolvePromise));
2717 -
2718 - function First({text}) {
2719 - if (suspend1) {
2720 - throw promise1;
2721 - } else {
2722 - return 'Hello';
2723 - }
2724 - }
2725 -
2726 - function Second({text}) {
2727 - if (suspend2) {
2728 - throw promise2;
2729 - } else {
2730 - return 'World';
2731 - }
2732 - }
2733 -
2734 - const ops = [];
2735 -
2736 - function App() {
2737 - const listener1 = useHover({
2738 - onHoverStart() {
2739 - ops.push('Hover Start First');
2740 - },
2741 - onHoverEnd() {
2742 - ops.push('Hover End First');
2743 - },
2744 - });
2745 - const listener2 = useHover({
2746 - onHoverStart() {
2747 - ops.push('Hover Start Second');
2748 - },
2749 - onHoverEnd() {
2750 - ops.push('Hover End Second');
2751 - },
2752 - });
2753 - return (
2754 - <div>
2755 - <Suspense fallback="Loading First...">
2756 - <span DEPRECATED_flareListeners={listener1} />
2757 - {/* We suspend after to test what happens when we eager
2758 - attach the listener. */}
2759 - <First />
2760 - </Suspense>
2761 - <Suspense fallback="Loading Second...">
2762 - <span DEPRECATED_flareListeners={listener2}>
2763 - <Second />
2764 - </span>
2765 - </Suspense>
2766 - </div>
2767 - );
2768 - }
2769 -
2770 - const finalHTML = ReactDOMServer.renderToString(<App />);
2771 - const container = document.createElement('div');
2772 - container.innerHTML = finalHTML;
2773 -
2774 - // We need this to be in the document since we'll dispatch events on it.
2775 - document.body.appendChild(container);
2776 -
2777 - const appDiv = container.getElementsByTagName('div')[0];
2778 - const firstSpan = appDiv.getElementsByTagName('span')[0];
2779 - const secondSpan = appDiv.getElementsByTagName('span')[1];
2780 - expect(firstSpan.textContent).toBe('');
2781 - expect(secondSpan.textContent).toBe('World');
2782 -
2783 - // On the client we don't have all data yet but we want to start
2784 - // hydrating anyway.
2785 - suspend1 = true;
2786 - suspend2 = true;
2787 - const root = ReactDOM.createRoot(container, {hydrate: true});
2788 - root.render(<App />);
2789 -
2790 - Scheduler.unstable_flushAll();
2791 - jest.runAllTimers();
2792 -
2793 - dispatchMouseEvent(appDiv, null);
2794 - dispatchMouseEvent(firstSpan, appDiv);
2795 - dispatchMouseEvent(secondSpan, firstSpan);
2796 -
2797 - // Neither target is yet hydrated.
2798 - expect(ops).toEqual([]);
2799 -
2800 - // Resolving the second promise so that rendering can complete.
2801 - suspend2 = false;
2802 - resolve2();
2803 - await promise2;
2804 -
2805 - Scheduler.unstable_flushAll();
2806 - jest.runAllTimers();
2807 -
2808 - // We've unblocked the current hover target so we should be
2809 - // able to replay it now.
2810 - expect(ops).toEqual(['Hover Start Second']);
2811 -
2812 - // Resolving the first promise has no effect now.
2813 - suspend1 = false;
2814 - resolve1();
2815 - await promise1;
2816 -
2817 - Scheduler.unstable_flushAll();
2818 - jest.runAllTimers();
2819 -
2820 - expect(ops).toEqual(['Hover Start Second']);
2821 -
2822 - document.body.removeChild(container);
2823 - });
2824 -
2710 // @gate experimental
2711 it('finishes normal pri work before continuing to hydrate a retry', async () => {
2712 let suspend = false;
packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js
+44 -31
@@ -96,8 +96,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
96 jest.resetModuleRegistry();
97
98 const ReactFeatureFlags = require('shared/ReactFeatureFlags');
99 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
100 -
99 + ReactFeatureFlags.enableCreateEventHandleAPI = true;
100 React = require('react');
101 ReactDOM = require('react-dom');
102 ReactDOMServer = require('react-dom/server');
@@ -348,18 +347,22 @@ describe('ReactDOMServerSelectiveHydration', () => {
347 });
348
349 // @gate experimental
351 - it('hydrates the target boundary synchronously during a click (flare)', async () => {
352 - const usePress = require('react-interactions/events/press-legacy').usePress;
350 + it('hydrates the target boundary synchronously during a click (createEventHandle)', async () => {
351 + const setClick = ReactDOM.unstable_createEventHandle('click');
352 + let isServerRendering = true;
353
354 function Child({text}) {
355 + const ref = React.useRef(null);
356 Scheduler.unstable_yieldValue(text);
356 - const listener = usePress({
357 - onPress() {
358 - Scheduler.unstable_yieldValue('Clicked ' + text);
359 - },
360 - });
357 + if (!isServerRendering) {
358 + React.useLayoutEffect(() => {
359 + return setClick(ref.current, () => {
360 + Scheduler.unstable_yieldValue('Clicked ' + text);
361 + });
362 + });
363 + }
364
362 - return <span DEPRECATED_flareListeners={listener}>{text}</span>;
365 + return <span ref={ref}>{text}</span>;
366 }
367
368 function App() {
@@ -386,7 +389,10 @@ describe('ReactDOMServerSelectiveHydration', () => {
389
390 container.innerHTML = finalHTML;
391
392 + isServerRendering = false;
393 +
394 const root = ReactDOM.createRoot(container, {hydrate: true});
395 +
396 root.render(<App />);
397
398 // Nothing has been hydrated so far.
@@ -398,11 +404,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
404
405 // This should synchronously hydrate the root App and the second suspense
406 // boundary.
401 - const preventDefault = jest.fn();
402 - target.virtualclick({preventDefault});
403 -
404 - // The event should have been canceled because we called preventDefault.
405 - expect(preventDefault).toHaveBeenCalled();
407 + target.virtualclick();
408
409 // We rendered App, B and then invoked the event without rendering A.
410 expect(Scheduler).toHaveYielded(['App', 'B', 'Clicked B']);
@@ -414,24 +416,29 @@ describe('ReactDOMServerSelectiveHydration', () => {
416 });
417
418 // @gate experimental
417 - it('hydrates at higher pri if sync did not work first time (flare)', async () => {
418 - const usePress = require('react-interactions/events/press-legacy').usePress;
419 + it('hydrates at higher pri if sync did not work first time (createEventHandle)', async () => {
420 let suspend = false;
421 + let isServerRendering = true;
422 let resolve;
423 const promise = new Promise(resolvePromise => (resolve = resolvePromise));
424 + const setClick = ReactDOM.unstable_createEventHandle('click');
425
426 function Child({text}) {
427 + const ref = React.useRef(null);
428 if ((text === 'A' || text === 'D') && suspend) {
429 throw promise;
430 }
431 Scheduler.unstable_yieldValue(text);
432
429 - const listener = usePress({
430 - onPress() {
431 - Scheduler.unstable_yieldValue('Clicked ' + text);
432 - },
433 - });
434 - return <span DEPRECATED_flareListeners={listener}>{text}</span>;
433 + if (!isServerRendering) {
434 + React.useLayoutEffect(() => {
435 + return setClick(ref.current, () => {
436 + Scheduler.unstable_yieldValue('Clicked ' + text);
437 + });
438 + });
439 + }
440 +
441 + return <span ref={ref}>{text}</span>;
442 }
443
444 function App() {
@@ -467,6 +474,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
474 const spanD = container.getElementsByTagName('span')[3];
475
476 suspend = true;
477 + isServerRendering = false;
478
479 // A and D will be suspended. We'll click on D which should take
480 // priority, after we unsuspend.
@@ -496,24 +504,28 @@ describe('ReactDOMServerSelectiveHydration', () => {
504 });
505
506 // @gate experimental
499 - it('hydrates at higher pri for secondary discrete events (flare)', async () => {
500 - const usePress = require('react-interactions/events/press-legacy').usePress;
507 + it('hydrates at higher pri for secondary discrete events (createEventHandle)', async () => {
508 + const setClick = ReactDOM.unstable_createEventHandle('click');
509 let suspend = false;
510 + let isServerRendering = true;
511 let resolve;
512 const promise = new Promise(resolvePromise => (resolve = resolvePromise));
513
514 function Child({text}) {
515 + const ref = React.useRef(null);
516 if ((text === 'A' || text === 'D') && suspend) {
517 throw promise;
518 }
519 Scheduler.unstable_yieldValue(text);
520
511 - const listener = usePress({
512 - onPress() {
513 - Scheduler.unstable_yieldValue('Clicked ' + text);
514 - },
515 - });
516 - return <span DEPRECATED_flareListeners={listener}>{text}</span>;
521 + if (!isServerRendering) {
522 + React.useLayoutEffect(() => {
523 + return setClick(ref.current, () => {
524 + Scheduler.unstable_yieldValue('Clicked ' + text);
525 + });
526 + });
527 + }
528 + return <span ref={ref}>{text}</span>;
529 }
530
531 function App() {
@@ -551,6 +563,7 @@ describe('ReactDOMServerSelectiveHydration', () => {
563 const spanD = container.getElementsByTagName('span')[3];
564
565 suspend = true;
566 + isServerRendering = false;
567
568 // A and D will be suspended. We'll click on D which should take
569 // priority, after we unsuspend.
packages/react-dom/src/client/ReactDOMComponent.js
+1 -85
@@ -7,8 +7,6 @@
7 * @flow
8 */
9
10 -import type {ElementListenerMapEntry} from '../client/ReactDOMComponentTree';
11 -
10 import {
11 registrationNameDependencies,
12 possibleRegistrationNames,
@@ -16,11 +14,6 @@ import {
14
15 import {canUseDOM} from 'shared/ExecutionEnvironment';
16 import invariant from 'shared/invariant';
19 -import {
20 - setListenToResponderEventTypes,
21 - addResponderEventSystemEvent,
22 - removeTrappedEventListener,
23 -} from '../events/DeprecatedDOMEventResponderSystem';
17
18 import {
19 getValueForAttribute,
@@ -81,16 +74,12 @@ import {validateProperties as validateInputProperties} from '../shared/ReactDOMN
74 import {validateProperties as validateUnknownProperties} from '../shared/ReactDOMUnknownPropertyHook';
75 import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
76
84 -import {
85 - enableDeprecatedFlareAPI,
86 - enableTrustedTypesIntegration,
87 -} from 'shared/ReactFeatureFlags';
77 +import {enableTrustedTypesIntegration} from 'shared/ReactFeatureFlags';
78 import {
79 listenToReactEvent,
80 mediaEventTypes,
81 listenToNonDelegatedEvent,
82 } from '../events/DOMPluginEventSystem';
93 -import {getEventListenerMap} from './ReactDOMComponentTree';
83
84 let didWarnInvalidHydration = false;
85 let didWarnScriptTags = false;
@@ -102,7 +91,6 @@ const AUTOFOCUS = 'autoFocus';
91 const CHILDREN = 'children';
92 const STYLE = 'style';
93 const HTML = '__html';
105 -const DEPRECATED_flareListeners = 'DEPRECATED_flareListeners';
94
95 const {html: HTML_NAMESPACE} = Namespaces;
96
@@ -358,7 +346,6 @@ function setInitialDOMProperties(
346 setTextContent(domElement, '' + nextProp);
347 }
348 } else if (
361 - (enableDeprecatedFlareAPI && propKey === DEPRECATED_flareListeners) ||
349 propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
350 propKey === SUPPRESS_HYDRATION_WARNING
351 ) {
@@ -728,7 +715,6 @@ export function diffProperties(
715 } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) {
716 // Noop. This is handled by the clear text mechanism.
717 } else if (
731 - (enableDeprecatedFlareAPI && propKey === DEPRECATED_flareListeners) ||
718 propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
719 propKey === SUPPRESS_HYDRATION_WARNING
720 ) {
@@ -817,7 +803,6 @@ export function diffProperties(
803 (updatePayload = updatePayload || []).push(propKey, '' + nextProp);
804 }
805 } else if (
820 - (enableDeprecatedFlareAPI && propKey === DEPRECATED_flareListeners) ||
806 propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
807 propKey === SUPPRESS_HYDRATION_WARNING
808 ) {
@@ -1083,7 +1068,6 @@ export function diffHydratedProperties(
1068 if (suppressHydrationWarning) {
1069 // Don't bother comparing. We're ignoring all these warnings.
1070 } else if (
1086 - (enableDeprecatedFlareAPI && propKey === DEPRECATED_flareListeners) ||
1071 propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
1072 propKey === SUPPRESS_HYDRATION_WARNING ||
1073 // Controlled attributes are not validated
@@ -1317,71 +1301,3 @@ export function restoreControlledState(
1301 return;
1302 }
1303 }
1320 -
1321 -function endsWith(subject: string, search: string): boolean {
1322 - const length = subject.length;
1323 - return subject.substring(length - search.length, length) === search;
1324 -}
1325 -
1326 -export function listenToEventResponderEventTypes(
1327 - eventTypes: Array<string>,
1328 - document: Document,
1329 -): void {
1330 - if (enableDeprecatedFlareAPI) {
1331 - // Get the listening Map for this element. We use this to track
1332 - // what events we're listening to.
1333 - const listenerMap = getEventListenerMap(document);
1334 -
1335 - // Go through each target event type of the event responder
1336 - for (let i = 0, length = eventTypes.length; i < length; ++i) {
1337 - const eventType = eventTypes[i];
1338 - const isPassive = !endsWith(eventType, '_active');
1339 - const eventKey = isPassive ? eventType + '_passive' : eventType;
1340 - const targetEventType = isPassive
1341 - ? eventType
1342 - : eventType.substring(0, eventType.length - 7);
1343 - if (!listenerMap.has(eventKey)) {
1344 - if (isPassive) {
1345 - const activeKey = targetEventType + '_active';
1346 - // If we have an active event listener, do not register
1347 - // a passive event listener. We use the same active event
1348 - // listener.
1349 - if (listenerMap.has(activeKey)) {
1350 - continue;
1351 - }
1352 - } else {
1353 - // If we have a passive event listener, remove the
1354 - // existing passive event listener before we add the
1355 - // active event listener.
1356 - const passiveKey = targetEventType + '_passive';
1357 - const passiveItem = ((listenerMap.get(
1358 - passiveKey,
1359 - ): any): ElementListenerMapEntry | void);
1360 - if (passiveItem !== undefined) {
1361 - removeTrappedEventListener(
1362 - document,
1363 - (targetEventType: any),
1364 - true,
1365 - passiveItem.listener,
1366 - );
1367 - listenerMap.delete(passiveKey);
1368 - }
1369 - }
1370 - const eventListener = addResponderEventSystemEvent(
1371 - document,
1372 - targetEventType,
1373 - isPassive,
1374 - );
1375 - listenerMap.set(eventKey, {
1376 - passive: isPassive,
1377 - listener: eventListener,
1378 - });
1379 - }
1380 - }
1381 - }
1382 -}
1383 -
1384 -// We can remove this once the event API is stable and out of a flag
1385 -if (enableDeprecatedFlareAPI) {
1386 - setListenToResponderEventTypes(listenToEventResponderEventTypes);
1387 -}
packages/react-dom/src/client/ReactDOMEventHandle.js
+2 -5
@@ -28,10 +28,7 @@ import {
28 } from '../events/DOMPluginEventSystem';
29
30 import {HostRoot, HostPortal} from 'react-reconciler/src/ReactWorkTags';
31 -import {
32 - PLUGIN_EVENT_SYSTEM,
33 - IS_EVENT_HANDLE_NON_MANAGED_NODE,
34 -} from '../events/EventSystemFlags';
31 +import {IS_EVENT_HANDLE_NON_MANAGED_NODE} from '../events/EventSystemFlags';
32
33 import {
34 enableScopeAPI,
@@ -164,7 +161,7 @@ function registerReactDOMEvent(
161 null,
162 isPassiveListener,
163 listenerPriority,
167 - PLUGIN_EVENT_SYSTEM | IS_EVENT_HANDLE_NON_MANAGED_NODE,
164 + IS_EVENT_HANDLE_NON_MANAGED_NODE,
165 );
166 } else {
167 invariant(
packages/react-dom/src/client/ReactDOMHostConfig.js
+6 -47
@@ -16,11 +16,7 @@ import type {
16 } from 'react-reconciler/src/ReactTestSelectors';
17 import type {RootType} from './ReactDOMRoot';
18 import type {ReactScopeInstance} from 'shared/ReactTypes';
19 -import type {
20 - ReactDOMEventResponder,
21 - ReactDOMEventResponderInstance,
22 - ReactDOMFundamentalComponentInstance,
23 -} from '../shared/ReactDOMTypes';
19 +import type {ReactDOMFundamentalComponentInstance} from '../shared/ReactDOMTypes';
20
21 import {
22 precacheFiberNode,
@@ -45,7 +41,6 @@ import {
41 warnForDeletedHydratableText,
42 warnForInsertedHydratedElement,
43 warnForInsertedHydratedText,
48 - listenToEventResponderEventTypes,
44 } from './ReactDOMComponent';
45 import {getSelectionInformation, restoreSelection} from './ReactInputSelection';
46 import setTextContent from './setTextContent';
@@ -65,15 +60,10 @@ import {
60 import dangerousStyleValue from '../shared/dangerousStyleValue';
61
62 import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
68 -import {
69 - mountEventResponder,
70 - unmountEventResponder,
71 -} from '../events/DeprecatedDOMEventResponderSystem';
63 import {retryIfBlockedOn} from '../events/ReactDOMEventReplaying';
64
65 import {
66 enableSuspenseServerRenderer,
76 - enableDeprecatedFlareAPI,
67 enableFundamentalAPI,
68 enableCreateEventHandleAPI,
69 enableScopeAPI,
@@ -232,7 +222,7 @@ export function prepareForCommit(containerInfo: Container): Object | null {
222 eventsEnabled = ReactBrowserEventEmitterIsEnabled();
223 selectionInformation = getSelectionInformation();
224 let activeInstance = null;
235 - if (enableDeprecatedFlareAPI || enableCreateEventHandleAPI) {
225 + if (enableCreateEventHandleAPI) {
226 const focusedElem = selectionInformation.focusedElem;
227 if (focusedElem !== null) {
228 activeInstance = getClosestInstanceFromNode(focusedElem);
@@ -243,7 +233,7 @@ export function prepareForCommit(containerInfo: Container): Object | null {
233 }
234
235 export function beforeActiveInstanceBlur(): void {
246 - if (enableDeprecatedFlareAPI || enableCreateEventHandleAPI) {
236 + if (enableCreateEventHandleAPI) {
237 ReactBrowserEventEmitterSetEnabled(true);
238 dispatchBeforeDetachedBlur((selectionInformation: any).focusedElem);
239 ReactBrowserEventEmitterSetEnabled(false);
@@ -251,7 +241,7 @@ export function beforeActiveInstanceBlur(): void {
241 }
242
243 export function afterActiveInstanceBlur(): void {
254 - if (enableDeprecatedFlareAPI || enableCreateEventHandleAPI) {
244 + if (enableCreateEventHandleAPI) {
245 ReactBrowserEventEmitterSetEnabled(true);
246 dispatchAfterDetachedBlur((selectionInformation: any).focusedElem);
247 ReactBrowserEventEmitterSetEnabled(false);
@@ -510,7 +500,7 @@ function createEvent(type: DOMEventName, bubbles: boolean): Event {
500 }
501
502 function dispatchBeforeDetachedBlur(target: HTMLElement): void {
513 - if (enableDeprecatedFlareAPI || enableCreateEventHandleAPI) {
503 + if (enableCreateEventHandleAPI) {
504 const event = createEvent('beforeblur', true);
505 // Dispatch "beforeblur" directly on the target,
506 // so it gets picked up by the event system and
@@ -520,7 +510,7 @@ function dispatchBeforeDetachedBlur(target: HTMLElement): void {
510 }
511
512 function dispatchAfterDetachedBlur(target: HTMLElement): void {
523 - if (enableDeprecatedFlareAPI || enableCreateEventHandleAPI) {
513 + if (enableCreateEventHandleAPI) {
514 const event = createEvent('afterblur', false);
515 // So we know what was detached, make the relatedTarget the
516 // detached target on the "afterblur" event.
@@ -975,37 +965,6 @@ export function didNotFindHydratableSuspenseInstance(
965 }
966 }
967
978 -export function DEPRECATED_mountResponderInstance(
979 - responder: ReactDOMEventResponder,
980 - responderInstance: ReactDOMEventResponderInstance,
981 - responderProps: Object,
982 - responderState: Object,
983 - instance: Instance,
984 -): ReactDOMEventResponderInstance {
985 - // Listen to events
986 - const doc = instance.ownerDocument;
987 - const {targetEventTypes} = ((responder: any): ReactDOMEventResponder);
988 - if (targetEventTypes !== null) {
989 - listenToEventResponderEventTypes(targetEventTypes, doc);
990 - }
991 - mountEventResponder(
992 - responder,
993 - responderInstance,
994 - responderProps,
995 - responderState,
996 - );
997 - return responderInstance;
998 -}
999 -
1000 -export function DEPRECATED_unmountResponderInstance(
1001 - responderInstance: ReactDOMEventResponderInstance,
1002 -): void {
1003 - if (enableDeprecatedFlareAPI) {
1004 - // TODO stop listening to targetEventTypes
1005 - unmountEventResponder(responderInstance);
1006 - }
1007 -}
1008 -
968 export function getFundamentalComponentInstance(
969 fundamentalInstance: ReactDOMFundamentalComponentInstance,
970 ): Instance {
packages/react-dom/src/events/DOMPluginEventSystem.js
+5 -7
@@ -22,7 +22,6 @@ import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
22
23 import {registrationNameDependencies} from './EventRegistry';
24 import {
25 - PLUGIN_EVENT_SYSTEM,
25 IS_CAPTURE_PHASE,
26 IS_EVENT_HANDLE_NON_MANAGED_NODE,
27 IS_NON_DELEGATED,
@@ -64,7 +63,6 @@ import {
63 addEventBubbleListenerWithPassiveFlag,
64 addEventCaptureListenerWithPassiveFlag,
65 } from './EventListener';
67 -import {removeTrappedEventListener} from './DeprecatedDOMEventResponderSystem';
66 import {topLevelEventsToReactNames} from './DOMEventProperties';
67 import * as BeforeInputEventPlugin from './plugins/BeforeInputEventPlugin';
68 import * as ChangeEventPlugin from './plugins/ChangeEventPlugin';
@@ -318,7 +316,7 @@ export function listenToNonDelegatedEvent(
316 const listener = addTrappedEventListener(
317 targetElement,
318 domEventName,
321 - PLUGIN_EVENT_SYSTEM | IS_NON_DELEGATED,
319 + IS_NON_DELEGATED,
320 isCapturePhaseListener,
321 );
322 listenerMap.set(listenerMapKey, {passive: false, listener});
@@ -332,7 +330,7 @@ export function listenToNativeEvent(
330 targetElement: Element | null,
331 isPassiveListener?: boolean,
332 listenerPriority?: EventPriority,
335 - eventSystemFlags?: EventSystemFlags = PLUGIN_EVENT_SYSTEM,
333 + eventSystemFlags?: EventSystemFlags = 0,
334 ): void {
335 let target = rootContainerElement;
336 // selectionchange needs to be attached to the document
@@ -381,11 +379,11 @@ export function listenToNativeEvent(
379 // If we should upgrade, then we need to remove the existing trapped
380 // event listener for the target container.
381 if (shouldUpgrade) {
384 - removeTrappedEventListener(
382 + removeEventListener(
383 target,
384 domEventName,
387 - isCapturePhaseListener,
385 ((listenerEntry: any): ElementListenerMapEntry).listener,
386 + isCapturePhaseListener,
387 );
388 }
389 if (isCapturePhaseListener) {
@@ -549,7 +547,7 @@ function deferClickToDocumentForLegacyFBSupport(
547 addTrappedEventListener(
548 targetContainer,
549 domEventName,
552 - PLUGIN_EVENT_SYSTEM | IS_LEGACY_FB_SUPPORT_MODE,
550 + IS_LEGACY_FB_SUPPORT_MODE,
551 false,
552 isDeferredListenerForLegacyFBSupport,
553 );
packages/react-dom/src/events/DeprecatedDOMEventResponderSystem.js deleted
-642
@@ -1,642 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - * @flow
7 - */
8 -
9 -import {
10 - type EventSystemFlags,
11 - IS_PASSIVE,
12 - PASSIVE_NOT_SUPPORTED,
13 - RESPONDER_EVENT_SYSTEM,
14 -} from './EventSystemFlags';
15 -import type {AnyNativeEvent} from '../events/PluginModuleType';
16 -import {
17 - HostComponent,
18 - ScopeComponent,
19 - HostPortal,
20 -} from 'react-reconciler/src/ReactWorkTags';
21 -import type {EventPriority} from 'shared/ReactTypes';
22 -import type {
23 - ReactDOMEventResponder,
24 - ReactDOMEventResponderInstance,
25 - ReactDOMResponderContext,
26 - ReactDOMResponderEvent,
27 -} from '../shared/ReactDOMTypes';
28 -import type {DOMEventName} from '../events/DOMEventNames';
29 -import {
30 - batchedEventUpdates,
31 - discreteUpdates,
32 - flushDiscreteUpdatesIfNeeded,
33 - executeUserEventHandler,
34 -} from './ReactDOMUpdateBatching';
35 -import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
36 -import {enableDeprecatedFlareAPI} from 'shared/ReactFeatureFlags';
37 -import invariant from 'shared/invariant';
38 -
39 -import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
40 -import {enqueueStateRestore} from './ReactDOMControlledComponent';
41 -import {createEventListenerWrapper} from './ReactDOMEventListener';
42 -import {passiveBrowserEventsSupported} from './checkPassiveEvents';
43 -import {
44 - addEventCaptureListener,
45 - addEventCaptureListenerWithPassiveFlag,
46 - removeEventListener,
47 -} from './EventListener';
48 -
49 -import {
50 - ContinuousEvent,
51 - UserBlockingEvent,
52 - DiscreteEvent,
53 -} from 'shared/ReactTypes';
54 -
55 -// Intentionally not named imports because Rollup would use dynamic dispatch for
56 -// CommonJS interop named imports.
57 -import * as Scheduler from 'scheduler';
58 -
59 -import {
60 - InputContinuousLanePriority,
61 - getCurrentUpdateLanePriority,
62 - setCurrentUpdateLanePriority,
63 -} from 'react-reconciler/src/ReactFiberLane';
64 -
65 -const {
66 - unstable_UserBlockingPriority: UserBlockingPriority,
67 - unstable_runWithPriority: runWithPriority,
68 -} = Scheduler;
69 -
70 -export let listenToResponderEventTypesImpl;
71 -
72 -export function setListenToResponderEventTypes(
73 - _listenToResponderEventTypesImpl: Function,
74 -) {
75 - listenToResponderEventTypesImpl = _listenToResponderEventTypesImpl;
76 -}
77 -
78 -const rootEventTypesToEventResponderInstances: Map<
79 - DOMEventName | string,
80 - Set<ReactDOMEventResponderInstance>,
81 -> = new Map();
82 -
83 -type PropagationBehavior = 0 | 1;
84 -
85 -const DoNotPropagateToNextResponder = 0;
86 -const PropagateToNextResponder = 1;
87 -
88 -let currentTimeStamp = 0;
89 -let currentInstance: null | ReactDOMEventResponderInstance = null;
90 -let currentDocument: null | Document = null;
91 -let currentPropagationBehavior: PropagationBehavior = DoNotPropagateToNextResponder;
92 -
93 -const eventResponderContext: ReactDOMResponderContext = {
94 - dispatchEvent(
95 - eventValue: any,
96 - eventListener: any => void,
97 - eventPriority: EventPriority,
98 - ): void {
99 - validateResponderContext();
100 - validateEventValue(eventValue);
101 - switch (eventPriority) {
102 - case DiscreteEvent: {
103 - flushDiscreteUpdatesIfNeeded(currentTimeStamp);
104 - discreteUpdates(() =>
105 - executeUserEventHandler(eventListener, eventValue),
106 - );
107 - break;
108 - }
109 - case UserBlockingEvent: {
110 - const previousPriority = getCurrentUpdateLanePriority();
111 - try {
112 - setCurrentUpdateLanePriority(InputContinuousLanePriority);
113 - runWithPriority(UserBlockingPriority, () =>
114 - executeUserEventHandler(eventListener, eventValue),
115 - );
116 - } finally {
117 - setCurrentUpdateLanePriority(previousPriority);
118 - }
119 - break;
120 - }
121 - case ContinuousEvent: {
122 - executeUserEventHandler(eventListener, eventValue);
123 - break;
124 - }
125 - }
126 - },
127 - isTargetWithinResponder(target: null | Element | Document): boolean {
128 - validateResponderContext();
129 - if (target != null) {
130 - let fiber = getClosestInstanceFromNode(target);
131 - const responderFiber = ((currentInstance: any): ReactDOMEventResponderInstance)
132 - .fiber;
133 -
134 - while (fiber !== null) {
135 - if (fiber === responderFiber || fiber.alternate === responderFiber) {
136 - return true;
137 - }
138 - fiber = fiber.return;
139 - }
140 - }
141 - return false;
142 - },
143 - isTargetWithinResponderScope(target: null | Element | Document): boolean {
144 - validateResponderContext();
145 - const componentInstance = ((currentInstance: any): ReactDOMEventResponderInstance);
146 - const responder = componentInstance.responder;
147 -
148 - if (target != null) {
149 - let fiber = getClosestInstanceFromNode(target);
150 - const responderFiber = ((currentInstance: any): ReactDOMEventResponderInstance)
151 - .fiber;
152 -
153 - while (fiber !== null) {
154 - if (fiber === responderFiber || fiber.alternate === responderFiber) {
155 - return true;
156 - }
157 - if (doesFiberHaveResponder(fiber, responder)) {
158 - return false;
159 - }
160 - fiber = fiber.return;
161 - }
162 - }
163 - return false;
164 - },
165 - isTargetWithinNode(
166 - childTarget: Element | Document,
167 - parentTarget: Element | Document,
168 - ): boolean {
169 - validateResponderContext();
170 - const childFiber = getClosestInstanceFromNode(childTarget);
171 - const parentFiber = getClosestInstanceFromNode(parentTarget);
172 -
173 - if (childFiber != null && parentFiber != null) {
174 - const parentAlternateFiber = parentFiber.alternate;
175 - let node = childFiber;
176 - while (node !== null) {
177 - if (node === parentFiber || node === parentAlternateFiber) {
178 - return true;
179 - }
180 - node = node.return;
181 - }
182 - return false;
183 - }
184 - // Fallback to DOM APIs
185 - return parentTarget.contains(childTarget);
186 - },
187 - addRootEventTypes(rootEventTypes: Array<string>): void {
188 - validateResponderContext();
189 - listenToResponderEventTypesImpl(rootEventTypes, currentDocument);
190 - for (let i = 0; i < rootEventTypes.length; i++) {
191 - const rootEventType = rootEventTypes[i];
192 - const eventResponderInstance = ((currentInstance: any): ReactDOMEventResponderInstance);
193 - DEPRECATED_registerRootEventType(rootEventType, eventResponderInstance);
194 - }
195 - },
196 - removeRootEventTypes(rootEventTypes: Array<string>): void {
197 - validateResponderContext();
198 - for (let i = 0; i < rootEventTypes.length; i++) {
199 - const rootEventType = rootEventTypes[i];
200 - const rootEventResponders = rootEventTypesToEventResponderInstances.get(
201 - rootEventType,
202 - );
203 - const rootEventTypesSet = ((currentInstance: any): ReactDOMEventResponderInstance)
204 - .rootEventTypes;
205 - if (rootEventTypesSet !== null) {
206 - rootEventTypesSet.delete(rootEventType);
207 - }
208 - if (rootEventResponders !== undefined) {
209 - rootEventResponders.delete(
210 - ((currentInstance: any): ReactDOMEventResponderInstance),
211 - );
212 - }
213 - }
214 - },
215 - getActiveDocument,
216 - objectAssign: Object.assign,
217 - getTimeStamp(): number {
218 - validateResponderContext();
219 - return currentTimeStamp;
220 - },
221 - isTargetWithinHostComponent(
222 - target: Element | Document,
223 - elementType: string,
224 - ): boolean {
225 - validateResponderContext();
226 - let fiber = getClosestInstanceFromNode(target);
227 -
228 - while (fiber !== null) {
229 - if (fiber.tag === HostComponent && fiber.type === elementType) {
230 - return true;
231 - }
232 - fiber = fiber.return;
233 - }
234 - return false;
235 - },
236 - continuePropagation() {
237 - currentPropagationBehavior = PropagateToNextResponder;
238 - },
239 - enqueueStateRestore,
240 - getResponderNode(): Element | null {
241 - validateResponderContext();
242 - const responderFiber = ((currentInstance: any): ReactDOMEventResponderInstance)
243 - .fiber;
244 - if (responderFiber.tag === ScopeComponent) {
245 - return null;
246 - }
247 - return responderFiber.stateNode;
248 - },
249 -};
250 -
251 -function validateEventValue(eventValue: any): void {
252 - if (typeof eventValue === 'object' && eventValue !== null) {
253 - const {target, type, timeStamp} = eventValue;
254 -
255 - if (target == null || type == null || timeStamp == null) {
256 - throw new Error(
257 - 'context.dispatchEvent: "target", "timeStamp", and "type" fields on event object are required.',
258 - );
259 - }
260 - const showWarning = name => {
261 - if (__DEV__) {
262 - console.error(
263 - '%s is not available on event objects created from event responder modules (React Flare). ' +
264 - 'Try wrapping in a conditional, i.e. `if (event.type !== "press") { event.%s }`',
265 - name,
266 - name,
267 - );
268 - }
269 - };
270 - eventValue.isDefaultPrevented = () => {
271 - if (__DEV__) {
272 - showWarning('isDefaultPrevented()');
273 - }
274 - };
275 - eventValue.isPropagationStopped = () => {
276 - if (__DEV__) {
277 - showWarning('isPropagationStopped()');
278 - }
279 - };
280 - // $FlowFixMe: we don't need value, Flow thinks we do
281 - Object.defineProperty(eventValue, 'nativeEvent', {
282 - get() {
283 - if (__DEV__) {
284 - showWarning('nativeEvent');
285 - }
286 - },
287 - });
288 - }
289 -}
290 -
291 -function doesFiberHaveResponder(
292 - fiber: Fiber,
293 - responder: ReactDOMEventResponder,
294 -): boolean {
295 - const tag = fiber.tag;
296 - if (tag === HostComponent || tag === ScopeComponent) {
297 - const dependencies = fiber.dependencies;
298 - if (dependencies !== null) {
299 - const respondersMap = dependencies.responders;
300 - if (respondersMap !== null && respondersMap.has(responder)) {
301 - return true;
302 - }
303 - }
304 - }
305 - return false;
306 -}
307 -
308 -function getActiveDocument(): Document {
309 - return ((currentDocument: any): Document);
310 -}
311 -
312 -function createDOMResponderEvent(
313 - domEventName: string,
314 - nativeEvent: AnyNativeEvent,
315 - nativeEventTarget: Element | Document,
316 - passive: boolean,
317 -): ReactDOMResponderEvent {
318 - const {buttons, pointerType} = (nativeEvent: any);
319 - let eventPointerType = '';
320 -
321 - if (pointerType !== undefined) {
322 - eventPointerType = pointerType;
323 - } else if (nativeEvent.key !== undefined) {
324 - eventPointerType = 'keyboard';
325 - } else if (buttons !== undefined) {
326 - eventPointerType = 'mouse';
327 - } else if ((nativeEvent: any).changedTouches !== undefined) {
328 - eventPointerType = 'touch';
329 - }
330 -
331 - return {
332 - nativeEvent: nativeEvent,
333 - passive,
334 - pointerType: eventPointerType,
335 - target: nativeEventTarget,
336 - type: domEventName,
337 - };
338 -}
339 -
340 -function responderEventTypesContainType(
341 - eventTypes: Array<string>,
342 - type: string,
343 - isPassive: boolean,
344 -): boolean {
345 - for (let i = 0, len = eventTypes.length; i < len; i++) {
346 - const eventType = eventTypes[i];
347 - if (eventType === type || (!isPassive && eventType === type + '_active')) {
348 - return true;
349 - }
350 - }
351 - return false;
352 -}
353 -
354 -function validateResponderTargetEventTypes(
355 - eventType: string,
356 - responder: ReactDOMEventResponder,
357 - isPassive: boolean,
358 -): boolean {
359 - const {targetEventTypes} = responder;
360 - // Validate the target event type exists on the responder
361 - if (targetEventTypes !== null) {
362 - return responderEventTypesContainType(
363 - targetEventTypes,
364 - eventType,
365 - isPassive,
366 - );
367 - }
368 - return false;
369 -}
370 -
371 -function traverseAndHandleEventResponderInstances(
372 - domEventName: string,
373 - targetFiber: null | Fiber,
374 - nativeEvent: AnyNativeEvent,
375 - nativeEventTarget: Document | Element,
376 - eventSystemFlags: EventSystemFlags,
377 -): void {
378 - const isPassiveEvent = (eventSystemFlags & IS_PASSIVE) !== 0;
379 - const isPassiveSupported = (eventSystemFlags & PASSIVE_NOT_SUPPORTED) === 0;
380 - const isPassive = isPassiveEvent || !isPassiveSupported;
381 -
382 - // Trigger event responders in this order:
383 - // - Bubble target responder phase
384 - // - Root responder phase
385 -
386 - const visitedResponders = new Set();
387 - const responderEvent = createDOMResponderEvent(
388 - domEventName,
389 - nativeEvent,
390 - nativeEventTarget,
391 - isPassiveEvent,
392 - );
393 - let node = targetFiber;
394 - let insidePortal = false;
395 - while (node !== null) {
396 - const tag = node.tag;
397 - const dependencies = node.dependencies;
398 - if (tag === HostPortal) {
399 - insidePortal = true;
400 - } else if (
401 - (tag === HostComponent || tag === ScopeComponent) &&
402 - dependencies !== null
403 - ) {
404 - const respondersMap = dependencies.responders;
405 - if (respondersMap !== null) {
406 - const responderInstances = Array.from(respondersMap.values());
407 - for (let i = 0, length = responderInstances.length; i < length; i++) {
408 - const responderInstance = responderInstances[i];
409 - const {props, responder, state} = responderInstance;
410 - if (
411 - !visitedResponders.has(responder) &&
412 - validateResponderTargetEventTypes(
413 - domEventName,
414 - responder,
415 - isPassive,
416 - ) &&
417 - (!insidePortal || responder.targetPortalPropagation)
418 - ) {
419 - visitedResponders.add(responder);
420 - const onEvent = responder.onEvent;
421 - if (onEvent !== null) {
422 - currentInstance = responderInstance;
423 - onEvent(responderEvent, eventResponderContext, props, state);
424 - if (currentPropagationBehavior === PropagateToNextResponder) {
425 - visitedResponders.delete(responder);
426 - currentPropagationBehavior = DoNotPropagateToNextResponder;
427 - }
428 - }
429 - }
430 - }
431 - }
432 - }
433 - node = node.return;
434 - }
435 - // Root phase
436 - const passive = rootEventTypesToEventResponderInstances.get(domEventName);
437 - const rootEventResponderInstances = [];
438 - if (passive !== undefined) {
439 - rootEventResponderInstances.push(...Array.from(passive));
440 - }
441 - if (!isPassive) {
442 - const active = rootEventTypesToEventResponderInstances.get(
443 - domEventName + '_active',
444 - );
445 - if (active !== undefined) {
446 - rootEventResponderInstances.push(...Array.from(active));
447 - }
448 - }
449 - if (rootEventResponderInstances.length > 0) {
450 - const responderInstances = Array.from(rootEventResponderInstances);
451 -
452 - for (let i = 0; i < responderInstances.length; i++) {
453 - const responderInstance = responderInstances[i];
454 - const {props, responder, state} = responderInstance;
455 - const onRootEvent = responder.onRootEvent;
456 - if (onRootEvent !== null) {
457 - currentInstance = responderInstance;
458 - onRootEvent(responderEvent, eventResponderContext, props, state);
459 - }
460 - }
461 - }
462 -}
463 -
464 -export function mountEventResponder(
465 - responder: ReactDOMEventResponder,
466 - responderInstance: ReactDOMEventResponderInstance,
467 - props: Object,
468 - state: Object,
469 -) {
470 - const onMount = responder.onMount;
471 - if (onMount !== null) {
472 - const previousInstance = currentInstance;
473 - currentInstance = responderInstance;
474 - try {
475 - onMount(eventResponderContext, props, state);
476 - } finally {
477 - currentInstance = previousInstance;
478 - }
479 - }
480 -}
481 -
482 -export function unmountEventResponder(
483 - responderInstance: ReactDOMEventResponderInstance,
484 -): void {
485 - const responder = ((responderInstance.responder: any): ReactDOMEventResponder);
486 - const onUnmount = responder.onUnmount;
487 - if (onUnmount !== null) {
488 - const {props, state} = responderInstance;
489 - const previousInstance = currentInstance;
490 - currentInstance = responderInstance;
491 - try {
492 - onUnmount(eventResponderContext, props, state);
493 - } finally {
494 - currentInstance = previousInstance;
495 - }
496 - }
497 - const rootEventTypesSet = responderInstance.rootEventTypes;
498 - if (rootEventTypesSet !== null) {
499 - const rootEventTypes = Array.from(rootEventTypesSet);
500 -
501 - for (let i = 0; i < rootEventTypes.length; i++) {
502 - const topLevelEventType = rootEventTypes[i];
503 - const rootEventResponderInstances = rootEventTypesToEventResponderInstances.get(
504 - topLevelEventType,
505 - );
506 - if (rootEventResponderInstances !== undefined) {
507 - rootEventResponderInstances.delete(responderInstance);
508 - }
509 - }
510 - }
511 -}
512 -
513 -function validateResponderContext(): void {
514 - invariant(
515 - currentInstance !== null,
516 - 'An event responder context was used outside of an event cycle.',
517 - );
518 -}
519 -
520 -export function DEPRECATED_dispatchEventForResponderEventSystem(
521 - domEventName: string,
522 - targetFiber: null | Fiber,
523 - nativeEvent: AnyNativeEvent,
524 - nativeEventTarget: Document | Element,
525 - eventSystemFlags: EventSystemFlags,
526 -): void {
527 - if (enableDeprecatedFlareAPI) {
528 - const previousInstance = currentInstance;
529 - const previousTimeStamp = currentTimeStamp;
530 - const previousDocument = currentDocument;
531 - const previousPropagationBehavior = currentPropagationBehavior;
532 - currentPropagationBehavior = DoNotPropagateToNextResponder;
533 - // nodeType 9 is DOCUMENT_NODE
534 - currentDocument =
535 - (nativeEventTarget: any).nodeType === 9
536 - ? ((nativeEventTarget: any): Document)
537 - : (nativeEventTarget: any).ownerDocument;
538 - // We might want to control timeStamp another way here
539 - currentTimeStamp = (nativeEvent: any).timeStamp;
540 - try {
541 - batchedEventUpdates(() => {
542 - traverseAndHandleEventResponderInstances(
543 - domEventName,
544 - targetFiber,
545 - nativeEvent,
546 - nativeEventTarget,
547 - eventSystemFlags,
548 - );
549 - });
550 - } finally {
551 - currentInstance = previousInstance;
552 - currentTimeStamp = previousTimeStamp;
553 - currentDocument = previousDocument;
554 - currentPropagationBehavior = previousPropagationBehavior;
555 - }
556 - }
557 -}
558 -
559 -export function addRootEventTypesForResponderInstance(
560 - responderInstance: ReactDOMEventResponderInstance,
561 - rootEventTypes: Array<string>,
562 -): void {
563 - for (let i = 0; i < rootEventTypes.length; i++) {
564 - const rootEventType = rootEventTypes[i];
565 - DEPRECATED_registerRootEventType(rootEventType, responderInstance);
566 - }
567 -}
568 -
569 -function DEPRECATED_registerRootEventType(
570 - rootEventType: string,
571 - eventResponderInstance: ReactDOMEventResponderInstance,
572 -): void {
573 - let rootEventResponderInstances = rootEventTypesToEventResponderInstances.get(
574 - rootEventType,
575 - );
576 - if (rootEventResponderInstances === undefined) {
577 - rootEventResponderInstances = new Set();
578 - rootEventTypesToEventResponderInstances.set(
579 - rootEventType,
580 - rootEventResponderInstances,
581 - );
582 - }
583 - let rootEventTypesSet = eventResponderInstance.rootEventTypes;
584 - if (rootEventTypesSet === null) {
585 - rootEventTypesSet = eventResponderInstance.rootEventTypes = new Set();
586 - }
587 - invariant(
588 - !rootEventTypesSet.has(rootEventType),
589 - 'addRootEventTypes() found a duplicate root event ' +
590 - 'type of "%s". This might be because the event type exists in the event responder "rootEventTypes" ' +
591 - 'array or because of a previous addRootEventTypes() using this root event type.',
592 - rootEventType,
593 - );
594 - rootEventTypesSet.add(rootEventType);
595 - rootEventResponderInstances.add(eventResponderInstance);
596 -}
597 -
598 -export function addResponderEventSystemEvent(
599 - document: Document,
600 - domEventName: string,
601 - passive: boolean,
602 -): any => void {
603 - let eventFlags = RESPONDER_EVENT_SYSTEM;
604 -
605 - // If passive option is not supported, then the event will be
606 - // active and not passive, but we flag it as using not being
607 - // supported too. This way the responder event plugins know,
608 - // and can provide polyfills if needed.
609 - if (passive) {
610 - if (passiveBrowserEventsSupported) {
611 - eventFlags |= IS_PASSIVE;
612 - } else {
613 - eventFlags |= PASSIVE_NOT_SUPPORTED;
614 - passive = false;
615 - }
616 - }
617 - // Check if interactive and wrap in discreteUpdates
618 - const listener = createEventListenerWrapper(
619 - document,
620 - ((domEventName: any): DOMEventName),
621 - eventFlags,
622 - );
623 - if (passiveBrowserEventsSupported) {
624 - return addEventCaptureListenerWithPassiveFlag(
625 - document,
626 - domEventName,
627 - listener,
628 - passive,
629 - );
630 - } else {
631 - return addEventCaptureListener(document, domEventName, listener);
632 - }
633 -}
634 -
635 -export function removeTrappedEventListener(
636 - targetContainer: EventTarget,
637 - domEventName: DOMEventName,
638 - capture: boolean,
639 - listener: any => void,
640 -): void {
641 - removeEventListener(targetContainer, domEventName, listener, capture);
642 -}
packages/react-dom/src/events/EventSystemFlags.js
+6 -10
@@ -9,16 +9,12 @@
9
10 export type EventSystemFlags = number;
11
12 -export const PLUGIN_EVENT_SYSTEM = 1;
13 -export const RESPONDER_EVENT_SYSTEM = 1 << 1;
14 -export const IS_EVENT_HANDLE_NON_MANAGED_NODE = 1 << 2;
15 -export const IS_NON_DELEGATED = 1 << 3;
16 -export const IS_CAPTURE_PHASE = 1 << 4;
17 -export const IS_PASSIVE = 1 << 5;
18 -export const IS_REPLAYED = 1 << 6;
19 -export const IS_LEGACY_FB_SUPPORT_MODE = 1 << 7;
20 -// This is used by React Flare
21 -export const PASSIVE_NOT_SUPPORTED = 1 << 8;
12 +export const IS_EVENT_HANDLE_NON_MANAGED_NODE = 1;
13 +export const IS_NON_DELEGATED = 1 << 1;
14 +export const IS_CAPTURE_PHASE = 1 << 2;
15 +export const IS_PASSIVE = 1 << 3;
16 +export const IS_REPLAYED = 1 << 4;
17 +export const IS_LEGACY_FB_SUPPORT_MODE = 1 << 5;
18
19 export const SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE =
20 IS_LEGACY_FB_SUPPORT_MODE | IS_REPLAYED | IS_CAPTURE_PHASE;
packages/react-dom/src/events/ReactDOMEventListener.js
+16 -67
@@ -17,7 +17,6 @@ import type {DOMEventName} from '../events/DOMEventNames';
17 // CommonJS interop named imports.
18 import * as Scheduler from 'scheduler';
19
20 -import {DEPRECATED_dispatchEventForResponderEventSystem} from './DeprecatedDOMEventResponderSystem';
20 import {
21 isReplayableDiscreteEvent,
22 queueDiscreteEvent,
@@ -34,17 +33,12 @@ import {HostRoot, SuspenseComponent} from 'react-reconciler/src/ReactWorkTags';
33 import {
34 type EventSystemFlags,
35 IS_LEGACY_FB_SUPPORT_MODE,
37 - PLUGIN_EVENT_SYSTEM,
38 - RESPONDER_EVENT_SYSTEM,
36 } from './EventSystemFlags';
37
38 import getEventTarget from './getEventTarget';
39 import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
40
44 -import {
45 - enableDeprecatedFlareAPI,
46 - enableLegacyFBSupport,
47 -} from 'shared/ReactFeatureFlags';
41 +import {enableLegacyFBSupport} from 'shared/ReactFeatureFlags';
42 import {
43 UserBlockingEvent,
44 ContinuousEvent,
@@ -136,7 +130,7 @@ function dispatchDiscreteEvent(
130 // flushed for this event and we don't need to do it again.
131 (eventSystemFlags & IS_LEGACY_FB_SUPPORT_MODE) === 0
132 ) {
139 - flushDiscreteUpdatesIfNeeded(nativeEvent.timeStamp);
133 + flushDiscreteUpdatesIfNeeded();
134 }
135 discreteUpdates(
136 dispatchEvent,
@@ -238,35 +232,13 @@ export function dispatchEvent(
232
233 // This is not replayable so we'll invoke it but without a target,
234 // in case the event system needs to trace it.
241 - if (enableDeprecatedFlareAPI) {
242 - if (eventSystemFlags & PLUGIN_EVENT_SYSTEM) {
243 - dispatchEventForPluginEventSystem(
244 - domEventName,
245 - eventSystemFlags,
246 - nativeEvent,
247 - null,
248 - targetContainer,
249 - );
250 - }
251 - if (eventSystemFlags & RESPONDER_EVENT_SYSTEM) {
252 - // React Flare event system
253 - DEPRECATED_dispatchEventForResponderEventSystem(
254 - (domEventName: any),
255 - null,
256 - nativeEvent,
257 - getEventTarget(nativeEvent),
258 - eventSystemFlags,
259 - );
260 - }
261 - } else {
262 - dispatchEventForPluginEventSystem(
263 - domEventName,
264 - eventSystemFlags,
265 - nativeEvent,
266 - null,
267 - targetContainer,
268 - );
269 - }
235 + dispatchEventForPluginEventSystem(
236 + domEventName,
237 + eventSystemFlags,
238 + nativeEvent,
239 + null,
240 + targetContainer,
241 + );
242 }
243
244 // Attempt dispatching an event. Returns a SuspenseInstance or Container if it's blocked.
@@ -318,36 +290,13 @@ export function attemptToDispatchEvent(
290 }
291 }
292 }
321 -
322 - if (enableDeprecatedFlareAPI) {
323 - if (eventSystemFlags & PLUGIN_EVENT_SYSTEM) {
324 - dispatchEventForPluginEventSystem(
325 - domEventName,
326 - eventSystemFlags,
327 - nativeEvent,
328 - targetInst,
329 - targetContainer,
330 - );
331 - }
332 - if (eventSystemFlags & RESPONDER_EVENT_SYSTEM) {
333 - // React Flare event system
334 - DEPRECATED_dispatchEventForResponderEventSystem(
335 - (domEventName: any),
336 - targetInst,
337 - nativeEvent,
338 - nativeEventTarget,
339 - eventSystemFlags,
340 - );
341 - }
342 - } else {
343 - dispatchEventForPluginEventSystem(
344 - domEventName,
345 - eventSystemFlags,
346 - nativeEvent,
347 - targetInst,
348 - targetContainer,
349 - );
350 - }
293 + dispatchEventForPluginEventSystem(
294 + domEventName,
295 + eventSystemFlags,
296 + nativeEvent,
297 + targetInst,
298 + targetContainer,
299 + );
300 // We're not blocked on anything.
301 return null;
302 }
packages/react-dom/src/events/ReactDOMEventReplaying.js
+1 -33
@@ -10,15 +10,11 @@
10 import type {AnyNativeEvent} from '../events/PluginModuleType';
11 import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
12 import type {DOMEventName} from '../events/DOMEventNames';
13 -import type {ElementListenerMap} from '../client/ReactDOMComponentTree';
13 import type {EventSystemFlags} from './EventSystemFlags';
14 import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
15 import type {LanePriority} from 'react-reconciler/src/ReactFiberLane';
16
18 -import {
19 - enableDeprecatedFlareAPI,
20 - enableSelectiveHydration,
21 -} from 'shared/ReactFeatureFlags';
17 +import {enableSelectiveHydration} from 'shared/ReactFeatureFlags';
18 import {
19 unstable_runWithPriority as runWithPriority,
20 unstable_scheduleCallback as scheduleCallback,
@@ -34,7 +30,6 @@ import {attemptToDispatchEvent} from './ReactDOMEventListener';
30 import {
31 getInstanceFromNode,
32 getClosestInstanceFromNode,
37 - getEventListenerMap,
33 } from '../client/ReactDOMComponentTree';
34 import {HostRoot, SuspenseComponent} from 'react-reconciler/src/ReactWorkTags';
35
@@ -88,7 +83,6 @@ type PointerEvent = Event & {
83
84 import {IS_REPLAYED} from './EventSystemFlags';
85 import {listenToNativeEvent} from './DOMPluginEventSystem';
91 -import {addResponderEventSystemEvent} from './DeprecatedDOMEventResponderSystem';
86
87 type QueuedReplayableEvent = {|
88 blockedOn: null | Container | SuspenseInstance,
@@ -186,43 +180,17 @@ function trapReplayableEventForContainer(
180 listenToNativeEvent(domEventName, false, ((container: any): Element), null);
181 }
182
189 -function trapReplayableEventForDocument(
190 - domEventName: DOMEventName,
191 - document: Document,
192 - listenerMap: ElementListenerMap,
193 -) {
194 - if (enableDeprecatedFlareAPI) {
195 - // Trap events for the responder system.
196 - // TODO: Ideally we shouldn't need these to be active but
197 - // if we only have a passive listener, we at least need it
198 - // to still pretend to be active so that Flare gets those
199 - // events.
200 - const activeEventKey = domEventName + '_active';
201 - if (!listenerMap.has(activeEventKey)) {
202 - const listener = addResponderEventSystemEvent(
203 - document,
204 - domEventName,
205 - false,
206 - );
207 - listenerMap.set(activeEventKey, {passive: false, listener});
208 - }
209 - }
210 -}
211 -
183 export function eagerlyTrapReplayableEvents(
184 container: Container,
185 document: Document,
186 ) {
216 - const listenerMapForDoc = getEventListenerMap(document);
187 // Discrete
188 discreteReplayableEvents.forEach(domEventName => {
189 trapReplayableEventForContainer(domEventName, container);
220 - trapReplayableEventForDocument(domEventName, document, listenerMapForDoc);
190 });
191 // Continuous
192 continuousReplayableEvents.forEach(domEventName => {
193 trapReplayableEventForContainer(domEventName, container);
225 - trapReplayableEventForDocument(domEventName, document, listenerMapForDoc);
194 });
195 }
196
packages/react-dom/src/events/ReactDOMUpdateBatching.js
+2 -36
@@ -10,9 +10,6 @@ import {
10 restoreStateIfNeeded,
11 } from './ReactDOMControlledComponent';
12
13 -import {enableDeprecatedFlareAPI} from 'shared/ReactFeatureFlags';
14 -import {invokeGuardedCallbackAndCatchFirstError} from 'shared/ReactErrorUtils';
15 -
13 // Used as a way to call batchedUpdates when we don't have a reference to
14 // the renderer. Such as when we're dispatching events or if third party
15 // libraries need to call batchedUpdates. Eventually, this API will go away when
@@ -77,18 +74,6 @@ export function batchedEventUpdates(fn, a, b) {
74 }
75 }
76
80 -// This is for the React Flare event system
81 -export function executeUserEventHandler(fn: any => void, value: any): void {
82 - const previouslyInEventHandler = isInsideEventHandler;
83 - try {
84 - isInsideEventHandler = true;
85 - const type = typeof value === 'object' && value !== null ? value.type : '';
86 - invokeGuardedCallbackAndCatchFirstError(type, fn, undefined, value);
87 - } finally {
88 - isInsideEventHandler = previouslyInEventHandler;
89 - }
90 -}
91 -
77 export function discreteUpdates(fn, a, b, c, d) {
78 const prevIsInsideEventHandler = isInsideEventHandler;
79 isInsideEventHandler = true;
@@ -102,27 +87,8 @@ export function discreteUpdates(fn, a, b, c, d) {
87 }
88 }
89
105 -let lastFlushedEventTimeStamp = 0;
106 -export function flushDiscreteUpdatesIfNeeded(timeStamp: number) {
107 - // event.timeStamp isn't overly reliable due to inconsistencies in
108 - // how different browsers have historically provided the time stamp.
109 - // Some browsers provide high-resolution time stamps for all events,
110 - // some provide low-resolution time stamps for all events. FF < 52
111 - // even mixes both time stamps together. Some browsers even report
112 - // negative time stamps or time stamps that are 0 (iOS9) in some cases.
113 - // Given we are only comparing two time stamps with equality (!==),
114 - // we are safe from the resolution differences. If the time stamp is 0
115 - // we bail-out of preventing the flush, which can affect semantics,
116 - // such as if an earlier flush removes or adds event listeners that
117 - // are fired in the subsequent flush. However, this is the same
118 - // behaviour as we had before this change, so the risks are low.
119 - if (
120 - !isInsideEventHandler &&
121 - (!enableDeprecatedFlareAPI ||
122 - timeStamp === 0 ||
123 - lastFlushedEventTimeStamp !== timeStamp)
124 - ) {
125 - lastFlushedEventTimeStamp = timeStamp;
90 +export function flushDiscreteUpdatesIfNeeded() {
91 + if (!isInsideEventHandler) {
92 flushDiscreteUpdatesImpl();
93 }
94 }
packages/react-dom/src/events/__tests__/DeprecatedDOMEventResponderSystem-test.internal.js deleted
-1002
@@ -1,1002 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -let React;
13 -let ReactFeatureFlags;
14 -let ReactDOM;
15 -let ReactDOMServer;
16 -let ReactTestRenderer;
17 -let Scheduler;
18 -
19 -// FIXME: What should the public API be for setting an event's priority? Right
20 -// now it's an enum but is that what we want? Hard coding this for now.
21 -const DiscreteEvent = 0;
22 -
23 -function createEventResponder({
24 - onEvent,
25 - onRootEvent,
26 - targetEventTypes,
27 - onMount,
28 - onUnmount,
29 - getInitialState,
30 - targetPortalPropagation,
31 -}) {
32 - return React.DEPRECATED_createResponder('TestEventResponder', {
33 - targetEventTypes,
34 - onEvent,
35 - onRootEvent,
36 - onMount,
37 - onUnmount,
38 - getInitialState,
39 - targetPortalPropagation,
40 - });
41 -}
42 -
43 -const createEvent = (type, data) => {
44 - const event = document.createEvent('CustomEvent');
45 - event.initCustomEvent(type, true, true);
46 - if (data != null) {
47 - Object.entries(data).forEach(([key, value]) => {
48 - event[key] = value;
49 - });
50 - }
51 - return event;
52 -};
53 -
54 -function dispatchEvent(element, type) {
55 - const event = document.createEvent('Event');
56 - event.initEvent(type, true, true);
57 - element.dispatchEvent(event);
58 -}
59 -
60 -function dispatchClickEvent(element) {
61 - dispatchEvent(element, 'click');
62 -}
63 -
64 -// This is a new feature in Fiber so I put it in its own test file. It could
65 -// probably move to one of the other test files once it is official.
66 -describe('DOMEventResponderSystem', () => {
67 - let container;
68 -
69 - beforeEach(() => {
70 - jest.resetModules();
71 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
72 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
73 - ReactFeatureFlags.enableScopeAPI = true;
74 - React = require('react');
75 - ReactDOM = require('react-dom');
76 - ReactDOMServer = require('react-dom/server');
77 - Scheduler = require('scheduler');
78 - container = document.createElement('div');
79 - document.body.appendChild(container);
80 - });
81 -
82 - afterEach(() => {
83 - document.body.removeChild(container);
84 - container = null;
85 - });
86 -
87 - // @gate experimental
88 - it('can mount and render correctly with the ReactTestRenderer', () => {
89 - jest.resetModules();
90 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
91 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
92 - React = require('react');
93 - ReactTestRenderer = require('react-test-renderer');
94 - const TestResponder = createEventResponder({});
95 -
96 - function Test() {
97 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
98 -
99 - return <div DEPRECATED_flareListeners={listener}>Hello world</div>;
100 - }
101 - const renderer = ReactTestRenderer.create(<Test />);
102 - expect(renderer).toMatchRenderedOutput(<div>Hello world</div>);
103 - });
104 -
105 - // @gate experimental
106 - it('can render correctly with the ReactDOMServer', () => {
107 - const TestResponder = createEventResponder({});
108 -
109 - function Test() {
110 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
111 -
112 - return <div DEPRECATED_flareListeners={listener}>Hello world</div>;
113 - }
114 - const output = ReactDOMServer.renderToString(<Test />);
115 - expect(output).toBe(`<div data-reactroot="">Hello world</div>`);
116 - });
117 -
118 - // @gate experimental
119 - it('can render correctly with the ReactDOMServer hydration', () => {
120 - const onEvent = jest.fn();
121 - const TestResponder = createEventResponder({
122 - targetEventTypes: ['click'],
123 - onEvent,
124 - });
125 - const ref = React.createRef();
126 -
127 - function Test() {
128 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
129 -
130 - return (
131 - <div>
132 - <span DEPRECATED_flareListeners={listener} ref={ref}>
133 - Hello world
134 - </span>
135 - </div>
136 - );
137 - }
138 - const output = ReactDOMServer.renderToString(<Test />);
139 - expect(output).toBe(
140 - `<div data-reactroot=""><span>Hello world</span></div>`,
141 - );
142 - container.innerHTML = output;
143 - ReactDOM.hydrate(<Test />, container);
144 - dispatchClickEvent(ref.current);
145 - expect(onEvent).toHaveBeenCalledTimes(1);
146 - });
147 -
148 - // @gate experimental
149 - it('the event responders should fire on click event', () => {
150 - let eventResponderFiredCount = 0;
151 - const eventLog = [];
152 - const buttonRef = React.createRef();
153 -
154 - const TestResponder = createEventResponder({
155 - targetEventTypes: ['click'],
156 - onEvent: (event, context, props) => {
157 - eventResponderFiredCount++;
158 - eventLog.push({
159 - name: event.type,
160 - passive: event.passive,
161 - phase: 'bubble',
162 - });
163 - },
164 - });
165 -
166 - function Test() {
167 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
168 -
169 - return (
170 - <button ref={buttonRef} DEPRECATED_flareListeners={listener}>
171 - Click me!
172 - </button>
173 - );
174 - }
175 -
176 - ReactDOM.render(<Test />, container);
177 - expect(container.innerHTML).toBe('<button>Click me!</button>');
178 -
179 - // Clicking the button should trigger the event responder onEvent() twice
180 - let buttonElement = buttonRef.current;
181 - dispatchClickEvent(buttonElement);
182 - expect(eventResponderFiredCount).toBe(1);
183 - expect(eventLog.length).toBe(1);
184 - expect(eventLog).toEqual([
185 - {
186 - name: 'click',
187 - passive: true,
188 - phase: 'bubble',
189 - },
190 - ]);
191 -
192 - // Unmounting the container and clicking should not increment anything
193 - ReactDOM.render(null, container);
194 - dispatchClickEvent(buttonElement);
195 - expect(eventResponderFiredCount).toBe(1);
196 -
197 - // Re-rendering the container and clicking should increase the counters again
198 - ReactDOM.render(<Test />, container);
199 - buttonElement = buttonRef.current;
200 - dispatchClickEvent(buttonElement);
201 - expect(eventResponderFiredCount).toBe(2);
202 - });
203 -
204 - // @gate experimental
205 - it('the event responders should fire on click event (passive events forced)', () => {
206 - // JSDOM does not support passive events, so this manually overrides the value to be true
207 - const checkPassiveEvents = require('react-dom/src/events/checkPassiveEvents');
208 - checkPassiveEvents.passiveBrowserEventsSupported = true;
209 -
210 - const eventLog = [];
211 - const buttonRef = React.createRef();
212 -
213 - const TestResponder = createEventResponder({
214 - targetEventTypes: ['click'],
215 - onEvent: (event, context, props) => {
216 - eventLog.push({
217 - name: event.type,
218 - passive: event.passive,
219 - phase: 'bubble',
220 - });
221 - },
222 - });
223 -
224 - function Test() {
225 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
226 -
227 - return (
228 - <button ref={buttonRef} DEPRECATED_flareListeners={listener}>
229 - Click me!
230 - </button>
231 - );
232 - }
233 -
234 - ReactDOM.render(<Test />, container);
235 -
236 - // Clicking the button should trigger the event responder onEvent()
237 - const buttonElement = buttonRef.current;
238 - dispatchClickEvent(buttonElement);
239 - expect(eventLog.length).toBe(1);
240 - expect(eventLog).toEqual([
241 - {
242 - name: 'click',
243 - passive: true,
244 - phase: 'bubble',
245 - },
246 - ]);
247 - });
248 -
249 - // @gate experimental
250 - it('nested event responders should not fire multiple times', () => {
251 - let eventResponderFiredCount = 0;
252 - let eventLog = [];
253 - const buttonRef = React.createRef();
254 -
255 - const TestResponder = createEventResponder({
256 - targetEventTypes: ['click'],
257 - onEvent: (event, context, props) => {
258 - eventResponderFiredCount++;
259 - eventLog.push({
260 - name: event.type,
261 - passive: event.passive,
262 - phase: 'bubble',
263 - });
264 - },
265 - });
266 -
267 - function Test() {
268 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
269 - const listener2 = React.DEPRECATED_useResponder(TestResponder, {});
270 -
271 - return (
272 - <button
273 - ref={buttonRef}
274 - DEPRECATED_flareListeners={[listener, listener2]}>
275 - Click me!
276 - </button>
277 - );
278 - }
279 -
280 - expect(() => {
281 - ReactDOM.render(<Test />, container);
282 - }).toErrorDev(
283 - 'Duplicate event responder "TestEventResponder" found in event listeners. ' +
284 - 'Event listeners passed to elements cannot use the same event responder more than once.',
285 - );
286 -
287 - // Clicking the button should trigger the event responder onEvent()
288 - let buttonElement = buttonRef.current;
289 - dispatchClickEvent(buttonElement);
290 - expect(eventResponderFiredCount).toBe(1);
291 - expect(eventLog.length).toBe(1);
292 - expect(eventLog).toEqual([
293 - {
294 - name: 'click',
295 - passive: true,
296 - phase: 'bubble',
297 - },
298 - ]);
299 -
300 - eventLog = [];
301 -
302 - function Test2() {
303 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
304 -
305 - return (
306 - <div DEPRECATED_flareListeners={listener}>
307 - <button ref={buttonRef} DEPRECATED_flareListeners={listener}>
308 - Click me!
309 - </button>
310 - </div>
311 - );
312 - }
313 -
314 - ReactDOM.render(<Test2 />, container);
315 -
316 - // Clicking the button should trigger the event responder onEvent()
317 - buttonElement = buttonRef.current;
318 - dispatchClickEvent(buttonElement);
319 - expect(eventResponderFiredCount).toBe(2);
320 - expect(eventLog.length).toBe(1);
321 -
322 - expect(eventLog).toEqual([
323 - {
324 - name: 'click',
325 - passive: true,
326 - phase: 'bubble',
327 - },
328 - ]);
329 - });
330 -
331 - // @gate experimental
332 - it('nested event responders should fire in the correct order', () => {
333 - let eventLog = [];
334 - const buttonRef = React.createRef();
335 -
336 - const TestResponderA = createEventResponder({
337 - targetEventTypes: ['click'],
338 - onEvent: (event, context, props) => {
339 - eventLog.push(`A [bubble]`);
340 - },
341 - });
342 -
343 - const TestResponderB = createEventResponder({
344 - targetEventTypes: ['click'],
345 - onEvent: (event, context, props) => {
346 - eventLog.push(`B [bubble]`);
347 - },
348 - });
349 -
350 - function Test() {
351 - const listener = React.DEPRECATED_useResponder(TestResponderA, {});
352 - const listener2 = React.DEPRECATED_useResponder(TestResponderB, {});
353 -
354 - return (
355 - <button
356 - ref={buttonRef}
357 - DEPRECATED_flareListeners={[listener, listener2]}>
358 - Click me!
359 - </button>
360 - );
361 - }
362 -
363 - ReactDOM.render(<Test />, container);
364 -
365 - // Clicking the button should trigger the event responder onEvent()
366 - let buttonElement = buttonRef.current;
367 - dispatchClickEvent(buttonElement);
368 -
369 - expect(eventLog).toEqual(['A [bubble]', 'B [bubble]']);
370 -
371 - eventLog = [];
372 -
373 - function Test2() {
374 - const listener = React.DEPRECATED_useResponder(TestResponderA, {});
375 - const listener2 = React.DEPRECATED_useResponder(TestResponderB, {});
376 -
377 - return (
378 - <div DEPRECATED_flareListeners={listener}>
379 - <button ref={buttonRef} DEPRECATED_flareListeners={listener2}>
380 - Click me!
381 - </button>
382 - </div>
383 - );
384 - }
385 -
386 - ReactDOM.render(<Test2 />, container);
387 -
388 - // Clicking the button should trigger the event responder onEvent()
389 - buttonElement = buttonRef.current;
390 - dispatchClickEvent(buttonElement);
391 -
392 - expect(eventLog).toEqual(['B [bubble]', 'A [bubble]']);
393 - });
394 -
395 - // @gate experimental
396 - it('nested event responders should fire in the correct order #2', () => {
397 - const eventLog = [];
398 - const buttonRef = React.createRef();
399 -
400 - const TestResponder = createEventResponder({
401 - targetEventTypes: ['click'],
402 - onEvent: (event, context, props) => {
403 - eventLog.push(`${props.name} [bubble]`);
404 - },
405 - });
406 -
407 - const Test = () => {
408 - const listener = React.DEPRECATED_useResponder(TestResponder, {
409 - name: 'A',
410 - });
411 - const listener2 = React.DEPRECATED_useResponder(TestResponder, {
412 - name: 'B',
413 - });
414 - return (
415 - <div DEPRECATED_flareListeners={listener}>
416 - <button ref={buttonRef} DEPRECATED_flareListeners={listener2}>
417 - Click me!
418 - </button>
419 - </div>
420 - );
421 - };
422 -
423 - ReactDOM.render(<Test />, container);
424 -
425 - // Clicking the button should trigger the event responder onEvent()
426 - const buttonElement = buttonRef.current;
427 - dispatchClickEvent(buttonElement);
428 -
429 - expect(eventLog).toEqual(['B [bubble]']);
430 - });
431 -
432 - // @gate experimental
433 - it('custom event dispatching for click -> magicClick works', () => {
434 - const eventLog = [];
435 - const buttonRef = React.createRef();
436 -
437 - const TestResponder = createEventResponder({
438 - targetEventTypes: ['click'],
439 - onEvent: (event, context, props) => {
440 - const syntheticEvent = {
441 - target: event.target,
442 - type: 'magicclick',
443 - phase: 'bubble',
444 - timeStamp: context.getTimeStamp(),
445 - };
446 - context.dispatchEvent(
447 - syntheticEvent,
448 - props.onMagicClick,
449 - DiscreteEvent,
450 - );
451 - },
452 - });
453 -
454 - function handleMagicEvent(e) {
455 - eventLog.push('magic event fired', e.type, e.phase);
456 - }
457 -
458 - const Test = () => {
459 - const listener = React.DEPRECATED_useResponder(TestResponder, {
460 - onMagicClick: handleMagicEvent,
461 - });
462 -
463 - return (
464 - <button ref={buttonRef} DEPRECATED_flareListeners={listener}>
465 - Click me!
466 - </button>
467 - );
468 - };
469 -
470 - ReactDOM.render(<Test />, container);
471 -
472 - // Clicking the button should trigger the event responder onEvent()
473 - const buttonElement = buttonRef.current;
474 - dispatchClickEvent(buttonElement);
475 -
476 - expect(eventLog).toEqual(['magic event fired', 'magicclick', 'bubble']);
477 - });
478 -
479 - // @gate experimental
480 - it('the event responder onMount() function should fire', () => {
481 - let onMountFired = 0;
482 -
483 - const TestResponder = createEventResponder({
484 - targetEventTypes: [],
485 - onMount: () => {
486 - onMountFired++;
487 - },
488 - });
489 -
490 - const TestResponder2 = createEventResponder({
491 - targetEventTypes: [],
492 - onMount: () => {
493 - onMountFired++;
494 - },
495 - });
496 -
497 - function Test({toggle}) {
498 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
499 - const listener2 = React.DEPRECATED_useResponder(TestResponder2, {});
500 - if (toggle) {
501 - return <button DEPRECATED_flareListeners={[listener2, listener]} />;
502 - }
503 - return <button DEPRECATED_flareListeners={[listener, listener2]} />;
504 - }
505 -
506 - ReactDOM.render(<Test />, container);
507 - expect(onMountFired).toEqual(2);
508 -
509 - ReactDOM.render(<Test toggle={true} />, container);
510 - expect(onMountFired).toEqual(2);
511 - });
512 -
513 - // @gate experimental
514 - it('the event responder onUnmount() function should fire', () => {
515 - let onUnmountFired = 0;
516 -
517 - const TestResponder = createEventResponder({
518 - targetEventTypes: [],
519 - onUnmount: () => {
520 - onUnmountFired++;
521 - },
522 - });
523 -
524 - function Test({test}) {
525 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
526 - if (test === 0) {
527 - return <button DEPRECATED_flareListeners={[listener]} />;
528 - } else if (test === 1) {
529 - return <button DEPRECATED_flareListeners={null} />;
530 - } else if (test === 2) {
531 - return <button DEPRECATED_flareListeners={[]} />;
532 - } else if (test === 3) {
533 - return <button />;
534 - } else if (test === 4) {
535 - return <button DEPRECATED_flareListeners={listener} />;
536 - }
537 - }
538 -
539 - ReactDOM.render(<Test test={0} />, container);
540 - ReactDOM.render(null, container);
541 - expect(onUnmountFired).toEqual(1);
542 -
543 - ReactDOM.render(<Test test={0} />, container);
544 - ReactDOM.render(<Test test={1} />, container);
545 - expect(onUnmountFired).toEqual(2);
546 -
547 - ReactDOM.render(<Test test={0} />, container);
548 - ReactDOM.render(<Test test={2} />, container);
549 - expect(onUnmountFired).toEqual(3);
550 -
551 - ReactDOM.render(<Test test={0} />, container);
552 - ReactDOM.render(<Test test={3} />, container);
553 - expect(onUnmountFired).toEqual(4);
554 -
555 - ReactDOM.render(<Test test={0} />, container);
556 - ReactDOM.render(<Test test={4} />, container);
557 - expect(onUnmountFired).toEqual(4);
558 - });
559 -
560 - // @gate experimental
561 - it('the event responder onUnmount() function should fire using scopes', () => {
562 - let onUnmountFired = 0;
563 -
564 - const TestScope = React.unstable_Scope;
565 - const TestResponder = createEventResponder({
566 - targetEventTypes: [],
567 - onUnmount: () => {
568 - onUnmountFired++;
569 - },
570 - });
571 -
572 - function Test({test}) {
573 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
574 - if (test === 0) {
575 - return <TestScope DEPRECATED_flareListeners={[listener]} />;
576 - } else if (test === 1) {
577 - return <TestScope DEPRECATED_flareListeners={null} />;
578 - } else if (test === 2) {
579 - return <TestScope DEPRECATED_flareListeners={[]} />;
580 - } else if (test === 3) {
581 - return <TestScope />;
582 - } else if (test === 4) {
583 - return <TestScope DEPRECATED_flareListeners={listener} />;
584 - }
585 - }
586 -
587 - ReactDOM.render(<Test test={0} />, container);
588 - ReactDOM.render(null, container);
589 - expect(onUnmountFired).toEqual(1);
590 -
591 - ReactDOM.render(<Test test={0} />, container);
592 - ReactDOM.render(<Test test={1} />, container);
593 - expect(onUnmountFired).toEqual(2);
594 -
595 - ReactDOM.render(<Test test={0} />, container);
596 - ReactDOM.render(<Test test={2} />, container);
597 - expect(onUnmountFired).toEqual(3);
598 -
599 - ReactDOM.render(<Test test={0} />, container);
600 - ReactDOM.render(<Test test={3} />, container);
601 - expect(onUnmountFired).toEqual(4);
602 -
603 - ReactDOM.render(<Test test={0} />, container);
604 - ReactDOM.render(<Test test={4} />, container);
605 - expect(onUnmountFired).toEqual(4);
606 - });
607 -
608 - // @gate experimental
609 - it('the event responder onUnmount() function should fire with state', () => {
610 - let counter = 0;
611 -
612 - const TestResponder = createEventResponder({
613 - targetEventTypes: [],
614 - getInitialState: () => ({
615 - incrementAmount: 5,
616 - }),
617 - onUnmount: (context, props, state) => {
618 - counter += state.incrementAmount;
619 - },
620 - });
621 -
622 - const Test = () => {
623 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
624 - return <button DEPRECATED_flareListeners={listener} />;
625 - };
626 -
627 - ReactDOM.render(<Test />, container);
628 - ReactDOM.render(null, container);
629 - expect(counter).toEqual(5);
630 - });
631 -
632 - // @gate experimental
633 - it('the event responder target listeners should correctly fire for only their events', () => {
634 - let clickEventComponent1Fired = 0;
635 - let clickEventComponent2Fired = 0;
636 - const eventLog = [];
637 - const buttonRef = React.createRef();
638 -
639 - const TestResponderA = createEventResponder({
640 - targetEventTypes: ['click_active'],
641 - onEvent: event => {
642 - clickEventComponent1Fired++;
643 - eventLog.push({
644 - name: event.type,
645 - passive: event.passive,
646 - });
647 - },
648 - });
649 -
650 - const TestResponderB = createEventResponder({
651 - targetEventTypes: ['click'],
652 - onEvent: event => {
653 - clickEventComponent2Fired++;
654 - eventLog.push({
655 - name: event.type,
656 - passive: event.passive,
657 - });
658 - },
659 - });
660 -
661 - const Test = () => {
662 - const listener = React.DEPRECATED_useResponder(TestResponderA, {});
663 - const listener2 = React.DEPRECATED_useResponder(TestResponderB, {});
664 -
665 - return (
666 - <div DEPRECATED_flareListeners={listener}>
667 - <button ref={buttonRef} DEPRECATED_flareListeners={listener2}>
668 - Click me!
669 - </button>
670 - </div>
671 - );
672 - };
673 -
674 - ReactDOM.render(<Test />, container);
675 -
676 - const buttonElement = buttonRef.current;
677 - dispatchClickEvent(buttonElement);
678 -
679 - expect(clickEventComponent1Fired).toBe(1);
680 - expect(clickEventComponent2Fired).toBe(1);
681 - expect(eventLog.length).toBe(2);
682 - expect(eventLog).toEqual([
683 - {
684 - name: 'click',
685 - passive: false,
686 - },
687 - {
688 - name: 'click',
689 - passive: false,
690 - },
691 - ]);
692 - });
693 -
694 - // @gate experimental
695 - it('the event responder system should warn on accessing invalid properties', () => {
696 - const TestResponder = createEventResponder({
697 - targetEventTypes: ['click'],
698 - onEvent: (event, context, props) => {
699 - const syntheticEvent = {
700 - target: event.target,
701 - type: 'click',
702 - timeStamp: context.getTimeStamp(),
703 - };
704 - context.dispatchEvent(syntheticEvent, props.onClick, DiscreteEvent);
705 - },
706 - });
707 -
708 - let handler;
709 - const buttonRef = React.createRef();
710 - const Test = () => {
711 - const listener = React.DEPRECATED_useResponder(TestResponder, {
712 - onClick: handler,
713 - });
714 -
715 - return (
716 - <button DEPRECATED_flareListeners={listener} ref={buttonRef}>
717 - Click me!
718 - </button>
719 - );
720 - };
721 - expect(() => {
722 - handler = event => {
723 - event.isDefaultPrevented();
724 - };
725 - ReactDOM.render(<Test />, container);
726 - dispatchClickEvent(buttonRef.current);
727 - }).toErrorDev(
728 - 'Warning: isDefaultPrevented() is not available on event objects created from event responder modules ' +
729 - '(React Flare).' +
730 - ' Try wrapping in a conditional, i.e. `if (event.type !== "press") { event.isDefaultPrevented() }`',
731 - {withoutStack: true},
732 - );
733 - expect(() => {
734 - handler = event => {
735 - event.isPropagationStopped();
736 - };
737 - ReactDOM.render(<Test />, container);
738 - dispatchClickEvent(buttonRef.current);
739 - }).toErrorDev(
740 - 'Warning: isPropagationStopped() is not available on event objects created from event responder modules ' +
741 - '(React Flare).' +
742 - ' Try wrapping in a conditional, i.e. `if (event.type !== "press") { event.isPropagationStopped() }`',
743 - {withoutStack: true},
744 - );
745 - expect(() => {
746 - handler = event => {
747 - return event.nativeEvent;
748 - };
749 - ReactDOM.render(<Test />, container);
750 - dispatchClickEvent(buttonRef.current);
751 - }).toErrorDev(
752 - 'Warning: nativeEvent is not available on event objects created from event responder modules ' +
753 - '(React Flare).' +
754 - ' Try wrapping in a conditional, i.e. `if (event.type !== "press") { event.nativeEvent }`',
755 - {withoutStack: true},
756 - );
757 - expect(container.innerHTML).toBe('<button>Click me!</button>');
758 - });
759 -
760 - // @gate experimental
761 - it('should work with event responder hooks', () => {
762 - const buttonRef = React.createRef();
763 - const eventLogs = [];
764 - const TestResponder = createEventResponder({
765 - targetEventTypes: ['foo'],
766 - onEvent: (event, context, props) => {
767 - const fooEvent = {
768 - target: event.target,
769 - type: 'foo',
770 - timeStamp: context.getTimeStamp(),
771 - };
772 - context.dispatchEvent(fooEvent, props.onFoo, DiscreteEvent);
773 - },
774 - });
775 -
776 - const Test = () => {
777 - const listener = React.DEPRECATED_useResponder(TestResponder, {
778 - onFoo: e => eventLogs.push('hook'),
779 - });
780 -
781 - return <button ref={buttonRef} DEPRECATED_flareListeners={listener} />;
782 - };
783 -
784 - ReactDOM.render(<Test />, container);
785 - buttonRef.current.dispatchEvent(createEvent('foo'));
786 - expect(eventLogs).toEqual(['hook']);
787 -
788 - // Clear events
789 - eventLogs.length = 0;
790 -
791 - const Test2 = () => {
792 - const listener = React.DEPRECATED_useResponder(TestResponder, {
793 - onFoo: e => eventLogs.push('hook'),
794 - });
795 -
796 - return <button ref={buttonRef} DEPRECATED_flareListeners={listener} />;
797 - };
798 -
799 - ReactDOM.render(<Test2 />, container);
800 - buttonRef.current.dispatchEvent(createEvent('foobar'));
801 - });
802 -
803 - // @gate experimental
804 - it('should work with concurrent mode updates', async () => {
805 - const log = [];
806 - const TestResponder = createEventResponder({
807 - targetEventTypes: ['click'],
808 - onEvent(event, context, props) {
809 - log.push(props);
810 - },
811 - });
812 - const ref = React.createRef();
813 -
814 - function Test({counter}) {
815 - const listener = React.DEPRECATED_useResponder(TestResponder, {counter});
816 - Scheduler.unstable_yieldValue('Test');
817 - return (
818 - <button DEPRECATED_flareListeners={listener} ref={ref}>
819 - Press me
820 - </button>
821 - );
822 - }
823 -
824 - const root = ReactDOM.createRoot(container);
825 - root.render(<Test counter={0} />);
826 - expect(Scheduler).toFlushAndYield(['Test']);
827 -
828 - // Click the button
829 - dispatchClickEvent(ref.current);
830 - expect(log).toEqual([{counter: 0}]);
831 -
832 - // Clear log
833 - log.length = 0;
834 -
835 - // Increase counter
836 - root.render(<Test counter={1} />);
837 - // Yield before committing
838 - expect(Scheduler).toFlushAndYieldThrough(['Test']);
839 -
840 - // Click the button again
841 - dispatchClickEvent(ref.current);
842 - expect(log).toEqual([{counter: 0}]);
843 -
844 - // Clear log
845 - log.length = 0;
846 -
847 - // Commit
848 - expect(Scheduler).toFlushAndYield([]);
849 - dispatchClickEvent(ref.current);
850 - expect(log).toEqual([{counter: 1}]);
851 - });
852 -
853 - // @gate experimental
854 - it('should correctly pass through event properties', () => {
855 - const timeStamps = [];
856 - const ref = React.createRef();
857 - const eventLog = [];
858 - const logEvent = event => {
859 - const propertiesWeCareAbout = {
860 - counter: event.counter,
861 - target: event.target,
862 - timeStamp: event.timeStamp,
863 - type: event.type,
864 - };
865 - timeStamps.push(event.timeStamp);
866 - eventLog.push(propertiesWeCareAbout);
867 - };
868 - let counter = 0;
869 -
870 - const TestResponder = createEventResponder({
871 - targetEventTypes: ['click'],
872 - onEvent(event, context, props) {
873 - const obj = {
874 - counter,
875 - timeStamp: context.getTimeStamp(),
876 - target: context.getResponderNode(),
877 - type: 'click-test',
878 - };
879 - context.dispatchEvent(obj, props.onClick, DiscreteEvent);
880 - },
881 - });
882 -
883 - const Component = () => {
884 - const listener = React.DEPRECATED_useResponder(TestResponder, {
885 - onClick: logEvent,
886 - });
887 - return <button ref={ref} DEPRECATED_flareListeners={listener} />;
888 - };
889 - ReactDOM.render(<Component />, container);
890 - dispatchClickEvent(ref.current);
891 - counter++;
892 - dispatchClickEvent(ref.current);
893 - counter++;
894 - dispatchClickEvent(ref.current);
895 - expect(typeof timeStamps[0] === 'number').toBe(true);
896 - expect(eventLog).toEqual([
897 - {
898 - counter: 0,
899 - target: ref.current,
900 - timeStamp: timeStamps[0],
901 - type: 'click-test',
902 - },
903 - {
904 - counter: 1,
905 - target: ref.current,
906 - timeStamp: timeStamps[1],
907 - type: 'click-test',
908 - },
909 - {
910 - counter: 2,
911 - target: ref.current,
912 - timeStamp: timeStamps[2],
913 - type: 'click-test',
914 - },
915 - ]);
916 - });
917 -
918 - // @gate experimental
919 - it('should not propagate target events through portals by default', () => {
920 - const buttonRef = React.createRef();
921 - const onEvent = jest.fn();
922 - const TestResponder = createEventResponder({
923 - targetEventTypes: ['click'],
924 - onEvent,
925 - });
926 - const domNode = document.createElement('div');
927 - document.body.appendChild(domNode);
928 - const Component = () => {
929 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
930 - return (
931 - <div DEPRECATED_flareListeners={listener}>
932 - {ReactDOM.createPortal(<button ref={buttonRef} />, domNode)}
933 - </div>
934 - );
935 - };
936 - ReactDOM.render(<Component />, container);
937 - dispatchClickEvent(buttonRef.current);
938 - document.body.removeChild(domNode);
939 - expect(onEvent).not.toBeCalled();
940 - });
941 -
942 - // @gate experimental
943 - it('should propagate target events through portals when enabled', () => {
944 - const buttonRef = React.createRef();
945 - const onEvent = jest.fn();
946 - const TestResponder = createEventResponder({
947 - targetPortalPropagation: true,
948 - targetEventTypes: ['click'],
949 - onEvent,
950 - });
951 - const domNode = document.createElement('div');
952 - document.body.appendChild(domNode);
953 - const Component = () => {
954 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
955 - return (
956 - <div DEPRECATED_flareListeners={listener}>
957 - {ReactDOM.createPortal(<button ref={buttonRef} />, domNode)}
958 - </div>
959 - );
960 - };
961 - ReactDOM.render(<Component />, container);
962 - dispatchClickEvent(buttonRef.current);
963 - document.body.removeChild(domNode);
964 - expect(onEvent).toBeCalled();
965 - });
966 -
967 - // @gate experimental
968 - it('event upgrading should work correctly', () => {
969 - let eventResponderFiredCount = 0;
970 - const buttonRef = React.createRef();
971 -
972 - const TestResponder = createEventResponder({
973 - targetEventTypes: ['click'],
974 - onEvent: (event, context, props, state) => {
975 - eventResponderFiredCount++;
976 - if (!state.addedRootEventTypes) {
977 - context.addRootEventTypes(['click_active']);
978 - }
979 - state.addedRootEventTypes = true;
980 - },
981 - });
982 -
983 - function Test() {
984 - const listener = React.DEPRECATED_useResponder(TestResponder, {});
985 -
986 - return (
987 - <button ref={buttonRef} DEPRECATED_flareListeners={listener}>
988 - Click me!
989 - </button>
990 - );
991 - }
992 -
993 - ReactDOM.render(<Test />, container);
994 - expect(container.innerHTML).toBe('<button>Click me!</button>');
995 -
996 - const buttonElement = buttonRef.current;
997 - dispatchClickEvent(buttonElement);
998 - expect(eventResponderFiredCount).toBe(1);
999 - dispatchClickEvent(buttonElement);
1000 - expect(eventResponderFiredCount).toBe(2);
1001 - });
1002 -});
packages/react-dom/src/events/checkPassiveEvents.js
+2 -2
@@ -8,13 +8,13 @@
8 */
9
10 import {canUseDOM} from 'shared/ExecutionEnvironment';
11 -import {enableDeprecatedFlareAPI} from 'shared/ReactFeatureFlags';
11 +import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags';
12
13 export let passiveBrowserEventsSupported = false;
14
15 // Check if browser support events with passive listeners
16 // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
17 -if (enableDeprecatedFlareAPI && canUseDOM) {
17 +if (enableCreateEventHandleAPI && canUseDOM) {
18 try {
19 const options = {};
20 // $FlowFixMe: Ignore Flow complaining about needing a value
packages/react-dom/src/server/ReactPartialRenderer.js
-4
@@ -23,7 +23,6 @@ import {
23 disableModulePatternComponents,
24 enableSuspenseServerRenderer,
25 enableFundamentalAPI,
26 - enableDeprecatedFlareAPI,
26 enableScopeAPI,
27 } from 'shared/ReactFeatureFlags';
28
@@ -368,9 +367,6 @@ function createOpenTagMarkup(
367 if (!hasOwnProperty.call(props, propKey)) {
368 continue;
369 }
371 - if (enableDeprecatedFlareAPI && propKey === 'DEPRECATED_flareListeners') {
372 - continue;
373 - }
370 let propValue = props[propKey];
371 if (propValue == null) {
372 continue;
packages/react-dom/src/server/ReactPartialRendererHooks.js
-9
@@ -14,7 +14,6 @@ import type {
14 MutableSourceGetSnapshotFn,
15 MutableSourceSubscribeFn,
16 ReactContext,
17 - ReactEventResponderListener,
17 } from 'shared/ReactTypes';
18 import type {SuspenseConfig} from 'react-reconciler/src/ReactFiberSuspenseConfig';
19 import type PartialRenderer from './ReactPartialRenderer';
@@ -457,13 +456,6 @@ export function useCallback<T>(
456 return useMemo(() => callback, deps);
457 }
458
460 -function useResponder(responder, props): ReactEventResponderListener<any, any> {
461 - return {
462 - props,
463 - responder,
464 - };
465 -}
466 -
459 // TODO Decide on how to implement this hook for server rendering.
460 // If a mutation occurs during render, consider triggering a Suspense boundary
461 // and falling back to client rendering.
@@ -521,7 +513,6 @@ export const Dispatcher: DispatcherType = {
513 useEffect: noop,
514 // Debugging effect
515 useDebugValue: noop,
524 - useResponder,
516 useDeferredValue,
517 useTransition,
518 useOpaqueIdentifier,
packages/react-dom/src/shared/DOMProperty.js
+1 -7
@@ -7,10 +7,7 @@
7 * @flow
8 */
9
10 -import {
11 - enableDeprecatedFlareAPI,
12 - enableFilterEmptyStringAttributesDOM,
13 -} from 'shared/ReactFeatureFlags';
10 +import {enableFilterEmptyStringAttributesDOM} from 'shared/ReactFeatureFlags';
11
12 type PropertyType = 0 | 1 | 2 | 3 | 4 | 5 | 6;
13
@@ -252,9 +249,6 @@ const reservedProps = [
249 'suppressHydrationWarning',
250 'style',
251 ];
255 -if (enableDeprecatedFlareAPI) {
256 - reservedProps.push('DEPRECATED_flareListeners');
257 -}
252
253 reservedProps.forEach(name => {
254 properties[name] = new PropertyInfoRecord(
packages/react-dom/src/shared/ReactControlledValuePropTypes.js
+2 -6
@@ -5,8 +5,6 @@
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 -import {enableDeprecatedFlareAPI} from 'shared/ReactFeatureFlags';
9 -
8 const hasReadOnlyValue = {
9 button: true,
10 checkbox: true,
@@ -29,8 +27,7 @@ export function checkControlledValueProps(
27 props.onInput ||
28 props.readOnly ||
29 props.disabled ||
32 - props.value == null ||
33 - (enableDeprecatedFlareAPI && props.DEPRECATED_flareListeners)
30 + props.value == null
31 )
32 ) {
33 console.error(
@@ -46,8 +43,7 @@ export function checkControlledValueProps(
43 props.onChange ||
44 props.readOnly ||
45 props.disabled ||
49 - props.checked == null ||
50 - (enableDeprecatedFlareAPI && props.DEPRECATED_flareListeners)
46 + props.checked == null
47 )
48 ) {
49 console.error(
packages/react-dom/src/shared/ReactDOMTypes.js
-60
@@ -9,75 +9,15 @@
9
10 import type {
11 ReactFundamentalComponentInstance,
12 - ReactEventResponder,
13 - ReactEventResponderInstance,
14 - EventPriority,
12 ReactScopeInstance,
13 } from 'shared/ReactTypes';
14 import type {DOMEventName} from '../events/DOMEventNames';
15
19 -type AnyNativeEvent = Event | KeyboardEvent | MouseEvent | Touch;
20 -
21 -export type PointerType =
22 - | ''
23 - | 'mouse'
24 - | 'keyboard'
25 - | 'pen'
26 - | 'touch'
27 - | 'trackpad';
28 -
29 -export type ReactDOMResponderEvent = {
30 - nativeEvent: AnyNativeEvent,
31 - passive: boolean,
32 - pointerType: PointerType,
33 - target: Element | Document,
34 - type: string,
35 - ...
36 -};
37 -
38 -export type ReactDOMEventResponder = ReactEventResponder<
39 - ReactDOMResponderEvent,
40 - ReactDOMResponderContext,
41 ->;
42 -
43 -export type ReactDOMEventResponderInstance = ReactEventResponderInstance<
44 - ReactDOMResponderEvent,
45 - ReactDOMResponderContext,
46 ->;
47 -
16 export type ReactDOMFundamentalComponentInstance = ReactFundamentalComponentInstance<
17 any,
18 any,
19 >;
20
53 -export type ReactDOMResponderContext = {
54 - dispatchEvent: (
55 - eventValue: any,
56 - listener: (any) => void,
57 - eventPriority: EventPriority,
58 - ) => void,
59 - isTargetWithinNode: (
60 - childTarget: Element | Document,
61 - parentTarget: Element | Document,
62 - ) => boolean,
63 - isTargetWithinResponder: (null | Element | Document) => boolean,
64 - isTargetWithinResponderScope: (null | Element | Document) => boolean,
65 - addRootEventTypes: (rootEventTypes: Array<string>) => void,
66 - removeRootEventTypes: (rootEventTypes: Array<string>) => void,
67 - getActiveDocument(): Document,
68 - objectAssign: Function,
69 - getTimeStamp: () => number,
70 - isTargetWithinHostComponent: (
71 - target: Element | Document,
72 - elementType: string,
73 - ) => boolean,
74 - continuePropagation(): void,
75 - // Used for controller components
76 - enqueueStateRestore(Element | Document): void,
77 - getResponderNode(): Element | null,
78 - ...
79 -};
80 -
21 export type ReactDOMEventHandle = (
22 target: EventTarget | ReactScopeInstance,
23 callback: (SyntheticEvent<EventTarget>) => void,
packages/react-interactions/events/README.md deleted
-105
@@ -1,105 +0,0 @@
1 -# `react-interactions/events`
2 -
3 -*This package is experimental. It is intended for use with the experimental React
4 -events API that is not available in open source builds.*
5 -
6 -Event Responders attach to a host node. They listen to native browser events
7 -dispatched on the host node of their child and transform those events into
8 -high-level events for applications.
9 -
10 -The core API is documented below. Documentation for individual Event Responders
11 -can be found [here](./docs).
12 -
13 -## Event Responder Interface
14 -
15 -Note: React Responders require the internal React flag `enableDeprecatedFlareAPI`.
16 -
17 -An Event Responder Interface is defined using an object. Each responder can define DOM
18 -events to listen to, handle the synthetic responder events, dispatch custom
19 -events, and implement a state machine.
20 -
21 -```js
22 -// types
23 -type ResponderEventType = string;
24 -
25 -type ResponderEvent = {|
26 - nativeEvent: any,
27 - target: Element | Document,
28 - pointerType: string,
29 - type: string,
30 - passive: boolean,
31 -|};
32 -
33 -type CustomEvent = {
34 - type: string,
35 - target: Element,
36 - ...
37 -}
38 -```
39 -
40 -### getInitialState?: (props: null | Object) => Object
41 -
42 -The initial state of that the Event Responder is created with.
43 -
44 -### onEvent?: (event: ResponderEvent, context: ResponderContext, props, state)
45 -
46 -Called during the bubble phase of the `targetEventTypes` dispatched on DOM
47 -elements within the Event Responder.
48 -
49 -### onMount?: (context: ResponderContext, props, state)
50 -
51 -Called after an Event Responder in mounted.
52 -
53 -### onRootEvent?: (event: ResponderEvent, context: ResponderContext, props, state)
54 -
55 -Called when any of the `rootEventTypes` are dispatched on the root of the app.
56 -
57 -### onUnmount?: (context: ResponderContext, props, state)
58 -
59 -Called before an Event Responder in unmounted.
60 -
61 -### rootEventTypes?: Array<ResponderEventType>
62 -
63 -Defines the DOM events to listen to on the root of the app.
64 -
65 -### targetEventTypes?: Array<ResponderEventType>
66 -
67 -Defines the DOM events to listen to within the Event Responder subtree.
68 -
69 -## ResponderContext
70 -
71 -The Event Responder Context is exposed via the `context` argument for certain methods
72 -on the `EventResponder` object.
73 -
74 -### addRootEventTypes(eventTypes: Array<ResponderEventType>)
75 -
76 -This can be used to dynamically listen to events on the root of the app only
77 -when it is necessary to do so.
78 -
79 -### dispatchEvent(propName: string, event: CustomEvent, { discrete: boolean })
80 -
81 -Dispatches a custom synthetic event. The `type` and `target` are required
82 -fields if the event is an object, but any other fields can be defined on the `event` that will be passed
83 -to the `listener`. You can also pass a value that is not an object, but a `boolean`. For example:
84 -
85 -```js
86 -const event = { type: 'press', target, pointerType, x, y };
87 -context.dispatchEvent('onPress', event, DiscreteEvent);
88 -```
89 -
90 -### isTargetWithinNode(target: Element, element: Element): boolean
91 -
92 -Returns `true` if `target` is a child of `element`.
93 -
94 -### isTargetWithinResponder(target: Element): boolean
95 -
96 -Returns `true` is the target element is within the subtree of the Event Responder.
97 -
98 -### isTargetWithinResponderScope(target: Element): boolean
99 -
100 -Returns `true` is the target element is within the current Event Responder's scope. If the target element
101 -is within the scope of the same responder, but owned by another Event Responder instance, this will return `false`.
102 -
103 -### removeRootEventTypes(eventTypes: Array<ResponderEventType>)
104 -
105 -Remove the root event types added with `addRootEventTypes`.
packages/react-interactions/events/context-menu.js deleted
-10
@@ -1,10 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -export * from './src/dom/ContextMenu';
packages/react-interactions/events/deprecated-focus.js deleted
-10
@@ -1,10 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -export * from './src/dom/DeprecatedFocus';
packages/react-interactions/events/docs/ContextMenu.md deleted
-54
@@ -1,54 +0,0 @@
1 -# ContextMenu
2 -
3 -The `useContextMenu` hooks responds to context-menu events.
4 -
5 -```js
6 -// Example
7 -const Button = (props) => {
8 - const contextmenu = useContextMenu({
9 - disabled,
10 - onContextMenu,
11 - preventDefault
12 - });
13 -
14 - return (
15 - <div DEPRECATED_flareListeners={contextmenu}>
16 - {props.children}
17 - </div>
18 - );
19 -};
20 -```
21 -
22 -## Types
23 -
24 -```js
25 -type ContextMenuEvent = {
26 - altKey: boolean,
27 - buttons: 0 | 1 | 2,
28 - ctrlKey: boolean,
29 - metaKey: boolean,
30 - pageX: number,
31 - pageY: number,
32 - pointerType: PointerType,
33 - shiftKey: boolean,
34 - target: Element,
35 - timeStamp: number,
36 - type: 'contextmenu',
37 - x: number,
38 - y: number,
39 -}
40 -```
41 -
42 -## Props
43 -
44 -### disabled: boolean = false
45 -
46 -Disables the responder.
47 -
48 -### onContextMenu: (e: ContextMenuEvent) => void
49 -
50 -Called when the user performs a gesture to display a context menu.
51 -
52 -### preventDefault: boolean = true
53 -
54 -Prevents the native behavior (i.e., context menu).
packages/react-interactions/events/docs/Focus.md deleted
-64
@@ -1,64 +0,0 @@
1 -# Focus
2 -
3 -The `useFocus` hook responds to focus and blur events on its child. Focus events
4 -are dispatched for all input types, with the exception of `onFocusVisibleChange`
5 -which is only dispatched when focusing with a keyboard.
6 -
7 -Focus events do not propagate between `useFocus` event responders.
8 -
9 -```js
10 -// Example
11 -const Button = (props) => {
12 - const [ isFocusVisible, setFocusVisible ] = useState(false);
13 - const focus = useFocus({
14 - onBlur={props.onBlur}
15 - onFocus={props.onFocus}
16 - onFocusVisibleChange={setFocusVisible}
17 - });
18 -
19 - return (
20 - <button
21 - children={props.children}
22 - DEPRECATED_flareListeners={focus}
23 - style={{
24 - ...(isFocusVisible && focusVisibleStyles)
25 - }}
26 - >
27 - );
28 -};
29 -```
30 -
31 -## Types
32 -
33 -```js
34 -type FocusEvent = {
35 - target: Element,
36 - pointerType: 'mouse' | 'touch' | 'pen' | 'keyboard',
37 - timeStamp: number,
38 - type: 'blur' | 'focus' | 'focuschange' | 'focusvisiblechange'
39 -}
40 -```
41 -
42 -## Props
43 -
44 -### disabled: boolean = false
45 -
46 -Disables the responder.
47 -
48 -### onBlur: (e: FocusEvent) => void
49 -
50 -Called when the element loses focus.
51 -
52 -### onFocus: (e: FocusEvent) => void
53 -
54 -Called when the element gains focus.
55 -
56 -### onFocusChange: boolean => void
57 -
58 -Called when the element changes focus state (i.e., after `onBlur` and
59 -`onFocus`).
60 -
61 -### onFocusVisibleChange: boolean => void
62 -
63 -Called when the element receives or loses focus following keyboard navigation.
64 -This can be used to display focus styles only for keyboard interactions.
packages/react-interactions/events/docs/FocusWithin.md deleted
-48
@@ -1,48 +0,0 @@
1 -# FocusWithin
2 -
3 -The `useFocusWithin` hooks responds to focus and blur events on its child. Focus events
4 -are dispatched for all input types, with the exception of `onFocusVisibleChange`
5 -which is only dispatched when focusing with a keyboard.
6 -
7 -Focus events do not propagate between `useFocusWithin` event responders.
8 -
9 -```js
10 -// Example
11 -const Button = (props) => {
12 - const [ isFocusWithin, updateFocusWithin ] = useState(false);
13 - const [ isFocusWithinVisible, updateFocusWithinVisible ] = useState(false);
14 - const focusWithin = useFocusWithin({
15 - onFocusWithinChange={updateFocusWithin}
16 - onFocusWithinVisibleChange={updateFocusWithinVisible}
17 - });
18 -
19 - return (
20 - <button
21 - children={props.children}
22 - DEPRECATED_flareListeners={focusWithin}
23 - style={{
24 - ...(isFocusWithin && focusWithinStyles),
25 - ...(isFocusWithinVisible && focusWithinVisibleStyles)
26 - }}
27 - >
28 - );
29 -};
30 -```
31 -
32 -## Props
33 -
34 -### disabled: boolean = false
35 -
36 -Disables the responder.
37 -
38 -### onFocusWithinChange: boolean => void
39 -
40 -Called once the element or a descendant receives focus, and once focus moves
41 -outside of the element.
42 -
43 -### onFocusWithinVisibleChange: boolean => void
44 -
45 -Called once the element or a descendant is focused following keyboard
46 -navigation, and once focus moves outside of the element. This can be used to
47 -display focus styles only when the keyboard is being used to focus within the
48 -element's subtree.
packages/react-interactions/events/docs/Hover.md deleted
-75
@@ -1,75 +0,0 @@
1 -# Hover
2 -
3 -The `useHover` hook responds to hover events on the element it wraps. Hover
4 -events are only dispatched for `mouse` and `pen` pointer types. Hover begins
5 -when the pointer enters the element's bounds and ends when the pointer leaves.
6 -
7 -Hover events do not propagate between `useHover` event responders.
8 -
9 -```js
10 -// Example
11 -const Link = (props) => (
12 - const [ isHovered, setHovered ] = useState(false);
13 - const hover = useHover({
14 - onHoverChange: setHovered
15 - });
16 -
17 - return (
18 - <a
19 - {...props}
20 - href={props.href}
21 - DEPRECATED_flareListeners={hover}
22 - style={{
23 - ...props.style,
24 - textDecoration: isHovered ? 'underline': 'none'
25 - }}
26 - />
27 - );
28 -);
29 -```
30 -
31 -## Types
32 -
33 -```js
34 -type HoverEventType = 'hoverstart' | 'hoverend' | 'hoverchange' | 'hovermove';
35 -
36 -type HoverEvent = {|
37 - clientX: number,
38 - clientY: number,
39 - pageX: number,
40 - pageY: number,
41 - pointerType: PointerType,
42 - target: Element,
43 - timeStamp: number,
44 - type: HoverEventType,
45 - x: number,
46 - y: number,
47 -|};
48 -```
49 -
50 -## Props
51 -
52 -### disabled: boolean
53 -
54 -Disables the responder.
55 -
56 -### onHoverChange: boolean => void
57 -
58 -Called when the element changes hover state (i.e., after `onHoverStart` and
59 -`onHoverEnd`).
60 -
61 -### onHoverEnd: (e: HoverEvent) => void
62 -
63 -Called once the element is no longer hovered.
64 -
65 -### onHoverMove: (e: HoverEvent) => void
66 -
67 -Called when the pointer moves within the hit bounds of the element.
68 -
69 -### onHoverStart: (e: HoverEvent) => void
70 -
71 -Called once the element is hovered.
72 -
73 -### preventDefault: boolean = true
74 -
75 -Whether to `preventDefault()` native events.
packages/react-interactions/events/docs/Press.md deleted
-121
@@ -1,121 +0,0 @@
1 -# Press
2 -
3 -The `usePress` hook responds to press events on the element it wraps. Press
4 -events are dispatched for `mouse`, `pen`, `touch`, `trackpad`, and `keyboard`
5 -pointer types. Press events are only dispatched for keyboards when pressing the
6 -Enter or Spacebar keys. If `onPress` is not called, this signifies that the
7 -press ended outside of the element hit bounds (i.e., the user aborted the
8 -press).
9 -
10 -Press events do not propagate between `usePress` event responders.
11 -
12 -```js
13 -// Example
14 -const Button = (props) => (
15 - const [ isPressed, setPressed ] = useState(false);
16 - const press = usePress({
17 - onPress={props.onPress}
18 - onPressChange={setPressed}
19 - });
20 -
21 - return (
22 - <div
23 - {...props}
24 - DEPRECATED_flareListeners={press}
25 - role="button"
26 - tabIndex={0}
27 - style={
28 - ...buttonStyles,
29 - ...(isPressed && pressedStyles)
30 - }}
31 - />
32 - );
33 -);
34 -```
35 -
36 -## Types
37 -
38 -```js
39 -type PressEvent = {
40 - altKey: boolean,
41 - buttons: 0 | 1 | 4,
42 - ctrlKey: boolean,
43 - defaultPrevented: boolean,
44 - metaKey: boolean,
45 - pageX: number,
46 - pageY: number,
47 - pointerType:
48 - | 'mouse'
49 - | 'touch'
50 - | 'pen'
51 - | 'trackpad'
52 - | 'keyboard',
53 - screenX: number,
54 - screenY: number,
55 - shiftKey: boolean,
56 - target: Element,
57 - timeStamp: number,
58 - type:
59 - | 'press'
60 - | 'pressstart'
61 - | 'pressend'
62 - | 'presschange'
63 - | 'pressmove'
64 - | 'contextmenu',
65 - x: number,
66 - y: number
67 -}
68 -
69 -type PressOffset = {
70 - top?: number,
71 - right?: number,
72 - bottom?: number,
73 - right?: number
74 -};
75 -```
76 -
77 -## Props
78 -
79 -### disabled: boolean = false
80 -
81 -Disables the responder.
82 -
83 -### onPress: (e: PressEvent) => void
84 -
85 -Called immediately after a press is released, unless the press is released
86 -outside the hit bounds of the element (accounting for `pressRetentionOffset`.
87 -
88 -### onPressChange: boolean => void
89 -
90 -Called when the element changes press state (i.e., after `onPressStart` and
91 -`onPressEnd`).
92 -
93 -### onPressEnd: (e: PressEvent) => void
94 -
95 -Called once the element is no longer pressed (because the press was released,
96 -cancelled, or moved beyond the hit bounds).
97 -
98 -### onPressMove: (e: PressEvent) => void
99 -
100 -Called when a press moves within the hit bounds of the element. Never called for
101 -keyboard-initiated press events.
102 -
103 -### onPressStart: (e: PressEvent) => void
104 -
105 -Called once the element is pressed down.
106 -
107 -### pressRetentionOffset: PressOffset
108 -
109 -Defines how far the pointer (while held down) may move outside the bounds of the
110 -element before it is deactivated. Once deactivated, the pointer (still held
111 -down) can be moved back within the bounds of the element to reactivate it.
112 -Ensure you pass in a constant to reduce memory allocations. Default is `20` for
113 -each offset.
114 -
115 -### preventDefault: boolean = true
116 -
117 -Whether to `preventDefault()` native events. Native behavior is prevented by
118 -default. If an anchor is the child of `Press`, internal and external navigation
119 -should be performed in `onPress`. To rely on native behavior instead, set
120 -`preventDefault` to `false`, but be aware that native behavior will take place
121 -immediately after interaction.
packages/react-interactions/events/hover.js deleted
-10
@@ -1,10 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -export * from './src/dom/Hover';
packages/react-interactions/events/input.js deleted
-10
@@ -1,10 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -export * from './src/dom/Input';
packages/react-interactions/events/press-legacy.js deleted
-10
@@ -1,10 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -export * from './src/dom/PressLegacy';
packages/react-interactions/events/src/dom/ContextMenu.js deleted
-126
@@ -1,126 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import type {
11 - ReactDOMResponderEvent,
12 - ReactDOMResponderContext,
13 - PointerType,
14 -} from 'react-dom/src/shared/ReactDOMTypes';
15 -import type {ReactEventResponderListener} from 'shared/ReactTypes';
16 -
17 -import * as React from 'react';
18 -import {DiscreteEvent} from 'shared/ReactTypes';
19 -
20 -type ContextMenuProps = {|
21 - disabled: boolean,
22 - onContextMenu: (e: ContextMenuEvent) => void,
23 - preventDefault: boolean,
24 -|};
25 -
26 -type ContextMenuState = {pointerType: PointerType, ...};
27 -
28 -type ContextMenuEvent = {|
29 - altKey: boolean,
30 - buttons: 0 | 1 | 2,
31 - ctrlKey: boolean,
32 - metaKey: boolean,
33 - pageX: null | number,
34 - pageY: null | number,
35 - pointerType: PointerType,
36 - shiftKey: boolean,
37 - target: Element | Document,
38 - timeStamp: number,
39 - type: 'contextmenu',
40 - x: null | number,
41 - y: null | number,
42 -|};
43 -
44 -const hasPointerEvents =
45 - typeof window !== 'undefined' && window.PointerEvent != null;
46 -
47 -function dispatchContextMenuEvent(
48 - event: ReactDOMResponderEvent,
49 - context: ReactDOMResponderContext,
50 - props: ContextMenuProps,
51 - state: ContextMenuState,
52 -): void {
53 - const nativeEvent: any = event.nativeEvent;
54 - const target = event.target;
55 - const timeStamp = context.getTimeStamp();
56 - const pointerType = state.pointerType;
57 -
58 - const gestureState = {
59 - altKey: nativeEvent.altKey,
60 - buttons: nativeEvent.buttons != null ? nativeEvent.buttons : 0,
61 - ctrlKey: nativeEvent.ctrlKey,
62 - metaKey: nativeEvent.metaKey,
63 - pageX: nativeEvent.pageX,
64 - pageY: nativeEvent.pageY,
65 - pointerType,
66 - shiftKey: nativeEvent.shiftKey,
67 - target,
68 - timeStamp,
69 - type: 'contextmenu',
70 - x: nativeEvent.clientX,
71 - y: nativeEvent.clientY,
72 - };
73 -
74 - context.dispatchEvent(gestureState, props.onContextMenu, DiscreteEvent);
75 -}
76 -
77 -const contextMenuImpl = {
78 - targetEventTypes: hasPointerEvents
79 - ? ['contextmenu_active', 'pointerdown']
80 - : ['contextmenu_active', 'touchstart', 'mousedown'],
81 - getInitialState(): ContextMenuState {
82 - return {
83 - pointerType: '',
84 - };
85 - },
86 - onEvent(
87 - event: ReactDOMResponderEvent,
88 - context: ReactDOMResponderContext,
89 - props: ContextMenuProps,
90 - state: ContextMenuState,
91 - ): void {
92 - const nativeEvent: any = event.nativeEvent;
93 - const pointerType = event.pointerType;
94 - const type = event.type;
95 -
96 - if (props.disabled) {
97 - return;
98 - }
99 -
100 - if (type === 'contextmenu') {
101 - const onContextMenu = props.onContextMenu;
102 - const preventDefault = props.preventDefault;
103 - if (preventDefault !== false && !nativeEvent.defaultPrevented) {
104 - nativeEvent.preventDefault();
105 - }
106 - if (typeof onContextMenu === 'function') {
107 - dispatchContextMenuEvent(event, context, props, state);
108 - }
109 - state.pointerType = '';
110 - } else {
111 - state.pointerType = pointerType;
112 - }
113 - },
114 -};
115 -
116 -// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
117 -export const ContextMenuResponder = React.DEPRECATED_createResponder(
118 - 'ContextMenu',
119 - contextMenuImpl,
120 -);
121 -
122 -export function useContextMenu(
123 - props: ContextMenuProps,
124 -): ?ReactEventResponderListener<any, any> {
125 - return React.DEPRECATED_useResponder(ContextMenuResponder, props);
126 -}
packages/react-interactions/events/src/dom/DeprecatedFocus.js deleted
-718
@@ -1,718 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import type {
11 - ReactDOMResponderEvent,
12 - ReactDOMResponderContext,
13 - PointerType,
14 -} from 'react-dom/src/shared/ReactDOMTypes';
15 -import type {ReactEventResponderListener} from 'shared/ReactTypes';
16 -
17 -import * as React from 'react';
18 -import {DiscreteEvent} from 'shared/ReactTypes';
19 -
20 -/**
21 - * Types
22 - */
23 -
24 -type FocusEvent = {|
25 - relatedTarget: null | Element | Document,
26 - target: Element | Document,
27 - type: FocusEventType | FocusWithinEventType,
28 - pointerType: PointerType,
29 - timeStamp: number,
30 - continuePropagation: () => void,
31 -|};
32 -
33 -type FocusState = {
34 - detachedTarget: null | Element | Document,
35 - focusTarget: null | Element | Document,
36 - isFocused: boolean,
37 - isFocusVisible: boolean,
38 - pointerType: PointerType,
39 - addedRootEvents?: boolean,
40 -};
41 -
42 -type FocusProps = {
43 - disabled: boolean,
44 - onBlur: (e: FocusEvent) => void,
45 - onFocus: (e: FocusEvent) => void,
46 - onFocusChange: boolean => void,
47 - onFocusVisibleChange: boolean => void,
48 - ...
49 -};
50 -
51 -type FocusEventType = 'focus' | 'blur' | 'focuschange' | 'focusvisiblechange';
52 -
53 -type FocusWithinProps = {
54 - disabled?: boolean,
55 - onFocusWithin?: (e: FocusEvent) => void,
56 - onAfterBlurWithin?: (e: FocusEvent) => void,
57 - onBeforeBlurWithin?: (e: FocusEvent) => void,
58 - onBlurWithin?: (e: FocusEvent) => void,
59 - onFocusWithinChange?: boolean => void,
60 - onFocusWithinVisibleChange?: boolean => void,
61 - ...
62 -};
63 -
64 -type FocusWithinEventType =
65 - | 'focuswithinvisiblechange'
66 - | 'focuswithinchange'
67 - | 'blurwithin'
68 - | 'focuswithin'
69 - | 'beforeblurwithin'
70 - | 'afterblurwithin';
71 -
72 -/**
73 - * Shared between Focus and FocusWithin
74 - */
75 -
76 -let isGlobalFocusVisible = true;
77 -let hasTrackedGlobalFocusVisible = false;
78 -let globalFocusVisiblePointerType = '';
79 -let isEmulatingMouseEvents = false;
80 -
81 -const isMac =
82 - typeof window !== 'undefined' && window.navigator != null
83 - ? /^Mac/.test(window.navigator.platform)
84 - : false;
85 -
86 -let passiveBrowserEventsSupported = false;
87 -
88 -const canUseDOM: boolean = !!(
89 - typeof window !== 'undefined' &&
90 - typeof window.document !== 'undefined' &&
91 - typeof window.document.createElement !== 'undefined'
92 -);
93 -
94 -// Check if browser support events with passive listeners
95 -// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
96 -if (canUseDOM) {
97 - try {
98 - const options = {};
99 - // $FlowFixMe: Ignore Flow complaining about needing a value
100 - Object.defineProperty(options, 'passive', {
101 - get: function() {
102 - passiveBrowserEventsSupported = true;
103 - },
104 - });
105 - window.addEventListener('test', options, options);
106 - window.removeEventListener('test', options, options);
107 - } catch (e) {
108 - passiveBrowserEventsSupported = false;
109 - }
110 -}
111 -
112 -const hasPointerEvents =
113 - typeof window !== 'undefined' && window.PointerEvent != null;
114 -
115 -const focusVisibleEvents = hasPointerEvents
116 - ? ['keydown', 'keyup', 'pointermove', 'pointerdown', 'pointerup']
117 - : ['keydown', 'keyup', 'mousedown', 'touchmove', 'touchstart', 'touchend'];
118 -
119 -const targetEventTypes = ['focus', 'blur', 'beforeblur', ...focusVisibleEvents];
120 -
121 -const rootEventTypes = ['afterblur'];
122 -
123 -function addWindowEventListener(types, callback, options) {
124 - types.forEach(type => {
125 - window.addEventListener(type, callback, options);
126 - });
127 -}
128 -
129 -function trackGlobalFocusVisible() {
130 - if (!hasTrackedGlobalFocusVisible) {
131 - hasTrackedGlobalFocusVisible = true;
132 - addWindowEventListener(
133 - focusVisibleEvents,
134 - handleGlobalFocusVisibleEvent,
135 - passiveBrowserEventsSupported ? {capture: true, passive: true} : true,
136 - );
137 - }
138 -}
139 -
140 -function handleGlobalFocusVisibleEvent(
141 - nativeEvent: MouseEvent | TouchEvent | KeyboardEvent,
142 -): void {
143 - const {type} = nativeEvent;
144 -
145 - switch (type) {
146 - case 'pointermove':
147 - case 'pointerdown':
148 - case 'pointerup': {
149 - isGlobalFocusVisible = false;
150 - globalFocusVisiblePointerType = (nativeEvent: any).pointerType;
151 - break;
152 - }
153 -
154 - case 'keydown':
155 - case 'keyup': {
156 - const {metaKey, altKey, ctrlKey} = nativeEvent;
157 - const validKey = !(metaKey || (!isMac && altKey) || ctrlKey);
158 -
159 - if (validKey) {
160 - globalFocusVisiblePointerType = 'keyboard';
161 - isGlobalFocusVisible = true;
162 - }
163 - break;
164 - }
165 -
166 - // fallbacks for no PointerEvent support
167 - case 'touchmove':
168 - case 'touchstart':
169 - case 'touchend': {
170 - isEmulatingMouseEvents = true;
171 - isGlobalFocusVisible = false;
172 - globalFocusVisiblePointerType = 'touch';
173 - break;
174 - }
175 - case 'mousedown': {
176 - if (!isEmulatingMouseEvents) {
177 - isGlobalFocusVisible = false;
178 - globalFocusVisiblePointerType = 'mouse';
179 - } else {
180 - isEmulatingMouseEvents = false;
181 - }
182 - break;
183 - }
184 - }
185 -}
186 -
187 -function isFunction(obj): boolean {
188 - return typeof obj === 'function';
189 -}
190 -
191 -function createFocusEvent(
192 - context: ReactDOMResponderContext,
193 - type: FocusEventType | FocusWithinEventType,
194 - target: Element | Document,
195 - pointerType: PointerType,
196 - relatedTarget: null | Element | Document,
197 -): FocusEvent {
198 - return {
199 - relatedTarget,
200 - target,
201 - type,
202 - pointerType,
203 - timeStamp: context.getTimeStamp(),
204 - // We don't use stopPropagation, as the default behavior
205 - // is to not propagate. Plus, there might be confusion
206 - // using stopPropagation as we don't actually stop
207 - // native propagation from working, but instead only
208 - // allow propagation to the others keyboard responders.
209 - continuePropagation() {
210 - context.continuePropagation();
211 - },
212 - };
213 -}
214 -
215 -function handleFocusVisibleTargetEvent(
216 - event: ReactDOMResponderEvent,
217 - context: ReactDOMResponderContext,
218 - state: FocusState,
219 - callback: boolean => void,
220 -): void {
221 - const {type} = event;
222 - isGlobalFocusVisible = false;
223 -
224 - // Focus should stop being visible if a pointer is used on the element
225 - // after it was focused using a keyboard.
226 - const focusTarget = state.focusTarget;
227 - if (
228 - focusTarget !== null &&
229 - (type === 'mousedown' || type === 'touchstart' || type === 'pointerdown')
230 - ) {
231 - callback(false);
232 - }
233 -}
234 -
235 -function handleFocusVisibleTargetEvents(
236 - event: ReactDOMResponderEvent,
237 - context: ReactDOMResponderContext,
238 - state: FocusState,
239 - callback: boolean => void,
240 -): void {
241 - const {type} = event;
242 - state.pointerType = globalFocusVisiblePointerType;
243 -
244 - switch (type) {
245 - case 'pointermove':
246 - case 'pointerdown':
247 - case 'pointerup': {
248 - handleFocusVisibleTargetEvent(event, context, state, callback);
249 - break;
250 - }
251 -
252 - case 'keydown':
253 - case 'keyup': {
254 - const nativeEvent = event.nativeEvent;
255 - const focusTarget = state.focusTarget;
256 - const {metaKey, altKey, ctrlKey} = (nativeEvent: any);
257 - const validKey = !(metaKey || (!isMac && altKey) || ctrlKey);
258 -
259 - if (validKey) {
260 - if (focusTarget !== null) {
261 - callback(true);
262 - }
263 - }
264 - break;
265 - }
266 -
267 - // fallbacks for no PointerEvent support
268 - case 'touchmove':
269 - case 'touchstart':
270 - case 'touchend': {
271 - handleFocusVisibleTargetEvent(event, context, state, callback);
272 - break;
273 - }
274 - case 'mousedown': {
275 - if (!isEmulatingMouseEvents) {
276 - handleFocusVisibleTargetEvent(event, context, state, callback);
277 - }
278 - break;
279 - }
280 - }
281 -}
282 -
283 -/**
284 - * Focus Responder
285 - */
286 -
287 -function dispatchFocusEvents(
288 - context: ReactDOMResponderContext,
289 - props: FocusProps,
290 - state: FocusState,
291 -) {
292 - const pointerType = state.pointerType;
293 - const target = ((state.focusTarget: any): Element | Document);
294 - const onFocus = props.onFocus;
295 - if (isFunction(onFocus)) {
296 - const syntheticEvent = createFocusEvent(
297 - context,
298 - 'focus',
299 - target,
300 - pointerType,
301 - null,
302 - );
303 - context.dispatchEvent(syntheticEvent, onFocus, DiscreteEvent);
304 - }
305 - dispatchFocusChange(context, props, true);
306 - if (state.isFocusVisible) {
307 - dispatchFocusVisibleChangeEvent(context, props, true);
308 - }
309 -}
310 -
311 -function dispatchBlurEvents(
312 - context: ReactDOMResponderContext,
313 - props: FocusProps,
314 - state: FocusState,
315 -) {
316 - const pointerType = state.pointerType;
317 - const target = ((state.focusTarget: any): Element | Document);
318 - const onBlur = props.onBlur;
319 - if (isFunction(onBlur)) {
320 - const syntheticEvent = createFocusEvent(
321 - context,
322 - 'blur',
323 - target,
324 - pointerType,
325 - null,
326 - );
327 - context.dispatchEvent(syntheticEvent, onBlur, DiscreteEvent);
328 - }
329 - dispatchFocusChange(context, props, false);
330 - if (state.isFocusVisible) {
331 - dispatchFocusVisibleChangeEvent(context, props, false);
332 - }
333 -}
334 -
335 -function dispatchFocusWithinEvents(
336 - context: ReactDOMResponderContext,
337 - event: ReactDOMResponderEvent,
338 - props: FocusWithinProps,
339 - state: FocusState,
340 -) {
341 - const pointerType = state.pointerType;
342 - const target = ((state.focusTarget: any): Element | Document) || event.target;
343 - const onFocusWithin = (props.onFocusWithin: any);
344 - if (isFunction(onFocusWithin)) {
345 - const syntheticEvent = createFocusEvent(
346 - context,
347 - 'focuswithin',
348 - target,
349 - pointerType,
350 - null,
351 - );
352 - context.dispatchEvent(syntheticEvent, onFocusWithin, DiscreteEvent);
353 - }
354 -}
355 -
356 -function dispatchBlurWithinEvents(
357 - context: ReactDOMResponderContext,
358 - event: ReactDOMResponderEvent,
359 - props: FocusWithinProps,
360 - state: FocusState,
361 -) {
362 - const pointerType = state.pointerType;
363 - const target = ((state.focusTarget: any): Element | Document) || event.target;
364 - const onBlurWithin = (props.onBlurWithin: any);
365 - if (isFunction(onBlurWithin)) {
366 - const syntheticEvent = createFocusEvent(
367 - context,
368 - 'blurwithin',
369 - target,
370 - pointerType,
371 - null,
372 - );
373 - context.dispatchEvent(syntheticEvent, onBlurWithin, DiscreteEvent);
374 - }
375 -}
376 -
377 -function dispatchAfterBlurWithinEvents(
378 - context: ReactDOMResponderContext,
379 - event: ReactDOMResponderEvent,
380 - props: FocusWithinProps,
381 - state: FocusState,
382 -) {
383 - const pointerType = state.pointerType;
384 - const onAfterBlurWithin = (props.onAfterBlurWithin: any);
385 - const relatedTarget = state.detachedTarget;
386 - if (isFunction(onAfterBlurWithin) && relatedTarget !== null) {
387 - const syntheticEvent = createFocusEvent(
388 - context,
389 - 'afterblurwithin',
390 - relatedTarget,
391 - pointerType,
392 - relatedTarget,
393 - );
394 - context.dispatchEvent(syntheticEvent, onAfterBlurWithin, DiscreteEvent);
395 - }
396 -}
397 -
398 -function dispatchFocusChange(
399 - context: ReactDOMResponderContext,
400 - props: FocusProps,
401 - value: boolean,
402 -): void {
403 - const onFocusChange = props.onFocusChange;
404 - if (isFunction(onFocusChange)) {
405 - context.dispatchEvent(value, onFocusChange, DiscreteEvent);
406 - }
407 -}
408 -
409 -function dispatchFocusVisibleChangeEvent(
410 - context: ReactDOMResponderContext,
411 - props: FocusProps,
412 - value: boolean,
413 -) {
414 - const onFocusVisibleChange = props.onFocusVisibleChange;
415 - if (isFunction(onFocusVisibleChange)) {
416 - context.dispatchEvent(value, onFocusVisibleChange, DiscreteEvent);
417 - }
418 -}
419 -
420 -function unmountFocusResponder(
421 - context: ReactDOMResponderContext,
422 - props: FocusProps,
423 - state: FocusState,
424 -) {
425 - if (state.isFocused) {
426 - dispatchBlurEvents(context, props, state);
427 - }
428 -}
429 -
430 -const focusResponderImpl = {
431 - targetEventTypes,
432 - targetPortalPropagation: true,
433 - getInitialState(): FocusState {
434 - return {
435 - detachedTarget: null,
436 - focusTarget: null,
437 - isFocused: false,
438 - isFocusVisible: false,
439 - pointerType: '',
440 - addedRootEvents: false,
441 - };
442 - },
443 - onMount() {
444 - trackGlobalFocusVisible();
445 - },
446 - onEvent(
447 - event: ReactDOMResponderEvent,
448 - context: ReactDOMResponderContext,
449 - props: FocusProps,
450 - state: FocusState,
451 - ): void {
452 - const {type, target} = event;
453 -
454 - if (props.disabled) {
455 - if (state.isFocused) {
456 - dispatchBlurEvents(context, props, state);
457 - state.isFocused = false;
458 - state.focusTarget = null;
459 - }
460 - return;
461 - }
462 -
463 - switch (type) {
464 - case 'focus': {
465 - state.focusTarget = context.getResponderNode();
466 - // Limit focus events to the direct child of the event component.
467 - // Browser focus is not expected to bubble.
468 - if (!state.isFocused && state.focusTarget === target) {
469 - state.isFocused = true;
470 - state.isFocusVisible = isGlobalFocusVisible;
471 - dispatchFocusEvents(context, props, state);
472 - }
473 - isEmulatingMouseEvents = false;
474 - break;
475 - }
476 - case 'blur': {
477 - if (state.isFocused) {
478 - dispatchBlurEvents(context, props, state);
479 - state.isFocusVisible = isGlobalFocusVisible;
480 - state.isFocused = false;
481 - }
482 - // This covers situations where focus is lost to another document in
483 - // the same window (e.g., iframes). Any action that restores focus to
484 - // the document (e.g., touch or click) first causes 'focus' to be
485 - // dispatched, which means the 'pointerType' we provide is stale
486 - // (it reflects the *previous* pointer). We cannot determine the
487 - // 'pointerType' in this case, so a blur with no
488 - // relatedTarget is used as a signal to reset the 'pointerType'.
489 - if (event.nativeEvent.relatedTarget == null) {
490 - state.pointerType = '';
491 - }
492 - isEmulatingMouseEvents = false;
493 - break;
494 - }
495 - default:
496 - handleFocusVisibleTargetEvents(
497 - event,
498 - context,
499 - state,
500 - isFocusVisible => {
501 - if (state.isFocused && state.isFocusVisible !== isFocusVisible) {
502 - state.isFocusVisible = isFocusVisible;
503 - dispatchFocusVisibleChangeEvent(context, props, isFocusVisible);
504 - }
505 - },
506 - );
507 - }
508 - },
509 - onUnmount(
510 - context: ReactDOMResponderContext,
511 - props: FocusProps,
512 - state: FocusState,
513 - ) {
514 - unmountFocusResponder(context, props, state);
515 - },
516 -};
517 -
518 -// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
519 -export const FocusResponder = React.DEPRECATED_createResponder(
520 - 'Focus',
521 - focusResponderImpl,
522 -);
523 -
524 -export function useFocus(
525 - props: FocusProps,
526 -): ?ReactEventResponderListener<any, any> {
527 - return React.DEPRECATED_useResponder(FocusResponder, props);
528 -}
529 -
530 -/**
531 - * FocusWithin Responder
532 - */
533 -
534 -function dispatchFocusWithinChangeEvent(
535 - context: ReactDOMResponderContext,
536 - props: FocusWithinProps,
537 - state: FocusState,
538 - value: boolean,
539 -) {
540 - const onFocusWithinChange = (props.onFocusWithinChange: any);
541 - if (isFunction(onFocusWithinChange)) {
542 - context.dispatchEvent(value, onFocusWithinChange, DiscreteEvent);
543 - }
544 - if (state.isFocusVisible) {
545 - dispatchFocusWithinVisibleChangeEvent(context, props, state, value);
546 - }
547 -}
548 -
549 -function dispatchFocusWithinVisibleChangeEvent(
550 - context: ReactDOMResponderContext,
551 - props: FocusWithinProps,
552 - state: FocusState,
553 - value: boolean,
554 -) {
555 - const onFocusWithinVisibleChange = (props.onFocusWithinVisibleChange: any);
556 - if (isFunction(onFocusWithinVisibleChange)) {
557 - context.dispatchEvent(value, onFocusWithinVisibleChange, DiscreteEvent);
558 - }
559 -}
560 -
561 -function unmountFocusWithinResponder(
562 - context: ReactDOMResponderContext,
563 - props: FocusWithinProps,
564 - state: FocusState,
565 -) {
566 - if (state.isFocused) {
567 - dispatchFocusWithinChangeEvent(context, props, state, false);
568 - }
569 -}
570 -
571 -const focusWithinResponderImpl = {
572 - targetEventTypes,
573 - targetPortalPropagation: true,
574 - getInitialState(): FocusState {
575 - return {
576 - detachedTarget: null,
577 - focusTarget: null,
578 - isFocused: false,
579 - isFocusVisible: false,
580 - pointerType: '',
581 - };
582 - },
583 - onMount() {
584 - trackGlobalFocusVisible();
585 - },
586 - onEvent(
587 - event: ReactDOMResponderEvent,
588 - context: ReactDOMResponderContext,
589 - props: FocusWithinProps,
590 - state: FocusState,
591 - ): void {
592 - const {nativeEvent, type} = event;
593 - const relatedTarget = (nativeEvent: any).relatedTarget;
594 -
595 - if (props.disabled) {
596 - if (state.isFocused) {
597 - dispatchFocusWithinChangeEvent(context, props, state, false);
598 - state.isFocused = false;
599 - state.focusTarget = null;
600 - }
601 - return;
602 - }
603 -
604 - switch (type) {
605 - case 'focus': {
606 - state.focusTarget = context.getResponderNode();
607 - // Limit focus events to the direct child of the event component.
608 - // Browser focus is not expected to bubble.
609 - if (!state.isFocused) {
610 - state.isFocused = true;
611 - state.isFocusVisible = isGlobalFocusVisible;
612 - dispatchFocusWithinChangeEvent(context, props, state, true);
613 - }
614 - if (!state.isFocusVisible && isGlobalFocusVisible) {
615 - state.isFocusVisible = isGlobalFocusVisible;
616 - dispatchFocusWithinVisibleChangeEvent(context, props, state, true);
617 - }
618 - dispatchFocusWithinEvents(context, event, props, state);
619 - break;
620 - }
621 - case 'blur': {
622 - if (
623 - state.isFocused &&
624 - !context.isTargetWithinResponder(relatedTarget)
625 - ) {
626 - dispatchFocusWithinChangeEvent(context, props, state, false);
627 - dispatchBlurWithinEvents(context, event, props, state);
628 - state.isFocused = false;
629 - }
630 - break;
631 - }
632 - case 'beforeblur': {
633 - const onBeforeBlurWithin = (props.onBeforeBlurWithin: any);
634 - if (isFunction(onBeforeBlurWithin)) {
635 - const syntheticEvent = createFocusEvent(
636 - context,
637 - 'beforeblurwithin',
638 - event.target,
639 - state.pointerType,
640 - null,
641 - );
642 - state.detachedTarget = event.target;
643 - context.dispatchEvent(
644 - syntheticEvent,
645 - onBeforeBlurWithin,
646 - DiscreteEvent,
647 - );
648 - if (!state.addedRootEvents) {
649 - state.addedRootEvents = true;
650 - context.addRootEventTypes(rootEventTypes);
651 - }
652 - } else {
653 - // We want to propagate to next focusWithin responder
654 - // if this responder doesn't handle beforeblur
655 - context.continuePropagation();
656 - }
657 - break;
658 - }
659 - default:
660 - handleFocusVisibleTargetEvents(
661 - event,
662 - context,
663 - state,
664 - isFocusVisible => {
665 - if (state.isFocused && state.isFocusVisible !== isFocusVisible) {
666 - state.isFocusVisible = isFocusVisible;
667 - dispatchFocusWithinVisibleChangeEvent(
668 - context,
669 - props,
670 - state,
671 - isFocusVisible,
672 - );
673 - }
674 - },
675 - );
676 - }
677 - },
678 - onRootEvent(
679 - event: ReactDOMResponderEvent,
680 - context: ReactDOMResponderContext,
681 - props: FocusWithinProps,
682 - state: FocusState,
683 - ): void {
684 - if (event.type === 'afterblur') {
685 - const detachedTarget = state.detachedTarget;
686 - if (
687 - detachedTarget !== null &&
688 - detachedTarget === event.nativeEvent.relatedTarget
689 - ) {
690 - dispatchAfterBlurWithinEvents(context, event, props, state);
691 - state.detachedTarget = null;
692 - if (state.addedRootEvents) {
693 - state.addedRootEvents = false;
694 - context.removeRootEventTypes(rootEventTypes);
695 - }
696 - }
697 - }
698 - },
699 - onUnmount(
700 - context: ReactDOMResponderContext,
701 - props: FocusWithinProps,
702 - state: FocusState,
703 - ) {
704 - unmountFocusWithinResponder(context, props, state);
705 - },
706 -};
707 -
708 -// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
709 -export const FocusWithinResponder = React.DEPRECATED_createResponder(
710 - 'FocusWithin',
711 - focusWithinResponderImpl,
712 -);
713 -
714 -export function useFocusWithin(
715 - props: FocusWithinProps,
716 -): ?ReactEventResponderListener<any, any> {
717 - return React.DEPRECATED_useResponder(FocusWithinResponder, props);
718 -}
packages/react-interactions/events/src/dom/Hover.js deleted
-391
@@ -1,391 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import type {
11 - ReactDOMResponderEvent,
12 - ReactDOMResponderContext,
13 - PointerType,
14 -} from 'react-dom/src/shared/ReactDOMTypes';
15 -import type {ReactEventResponderListener} from 'shared/ReactTypes';
16 -
17 -import * as React from 'react';
18 -import {UserBlockingEvent} from 'shared/ReactTypes';
19 -
20 -type HoverProps = {
21 - disabled: boolean,
22 - preventDefault: boolean,
23 - onHoverChange: boolean => void,
24 - onHoverEnd: (e: HoverEvent) => void,
25 - onHoverMove: (e: HoverEvent) => void,
26 - onHoverStart: (e: HoverEvent) => void,
27 - ...
28 -};
29 -
30 -type HoverState = {
31 - hoverTarget: null | Element | Document,
32 - isActiveHovered: boolean,
33 - isHovered: boolean,
34 - isTouched?: boolean,
35 - ignoreEmulatedMouseEvents?: boolean,
36 - ...
37 -};
38 -
39 -type HoverEventType = 'hoverstart' | 'hoverend' | 'hoverchange' | 'hovermove';
40 -
41 -type HoverEvent = {|
42 - clientX: null | number,
43 - clientY: null | number,
44 - pageX: null | number,
45 - pageY: null | number,
46 - pointerType: PointerType,
47 - screenX: null | number,
48 - screenY: null | number,
49 - target: Element | Document,
50 - timeStamp: number,
51 - type: HoverEventType,
52 - x: null | number,
53 - y: null | number,
54 -|};
55 -
56 -const hasPointerEvents =
57 - typeof window !== 'undefined' && window.PointerEvent != null;
58 -
59 -function isFunction(obj): boolean {
60 - return typeof obj === 'function';
61 -}
62 -
63 -function createHoverEvent(
64 - event: ?ReactDOMResponderEvent,
65 - context: ReactDOMResponderContext,
66 - type: HoverEventType,
67 - target: Element | Document,
68 -): HoverEvent {
69 - let clientX = null;
70 - let clientY = null;
71 - let pageX = null;
72 - let pageY = null;
73 - let screenX = null;
74 - let screenY = null;
75 - let pointerType = '';
76 -
77 - if (event) {
78 - const nativeEvent = (event.nativeEvent: any);
79 - pointerType = event.pointerType;
80 - ({clientX, clientY, pageX, pageY, screenX, screenY} = nativeEvent);
81 - }
82 -
83 - return {
84 - pointerType,
85 - target,
86 - type,
87 - timeStamp: context.getTimeStamp(),
88 - clientX,
89 - clientY,
90 - pageX,
91 - pageY,
92 - screenX,
93 - screenY,
94 - x: clientX,
95 - y: clientY,
96 - };
97 -}
98 -
99 -function dispatchHoverChangeEvent(
100 - event: null | ReactDOMResponderEvent,
101 - context: ReactDOMResponderContext,
102 - props: HoverProps,
103 - state: HoverState,
104 -): void {
105 - const onHoverChange = props.onHoverChange;
106 - if (isFunction(onHoverChange)) {
107 - const bool = state.isActiveHovered;
108 - context.dispatchEvent(bool, onHoverChange, UserBlockingEvent);
109 - }
110 -}
111 -
112 -function dispatchHoverStartEvents(
113 - event: ReactDOMResponderEvent,
114 - context: ReactDOMResponderContext,
115 - props: HoverProps,
116 - state: HoverState,
117 -): boolean {
118 - const target = state.hoverTarget;
119 - if (event !== null) {
120 - const {nativeEvent} = event;
121 - if (
122 - context.isTargetWithinResponderScope((nativeEvent: any).relatedTarget)
123 - ) {
124 - return false;
125 - }
126 - }
127 -
128 - state.isHovered = true;
129 -
130 - if (!state.isActiveHovered) {
131 - state.isActiveHovered = true;
132 - const onHoverStart = props.onHoverStart;
133 - if (isFunction(onHoverStart)) {
134 - const syntheticEvent = createHoverEvent(
135 - event,
136 - context,
137 - 'hoverstart',
138 - ((target: any): Element | Document),
139 - );
140 - context.dispatchEvent(syntheticEvent, onHoverStart, UserBlockingEvent);
141 - }
142 - dispatchHoverChangeEvent(event, context, props, state);
143 - }
144 - return true;
145 -}
146 -
147 -function dispatchHoverMoveEvent(event, context, props, state) {
148 - const target = state.hoverTarget;
149 - const onHoverMove = props.onHoverMove;
150 - if (isFunction(onHoverMove)) {
151 - const syntheticEvent = createHoverEvent(
152 - event,
153 - context,
154 - 'hovermove',
155 - ((target: any): Element | Document),
156 - );
157 - context.dispatchEvent(syntheticEvent, onHoverMove, UserBlockingEvent);
158 - }
159 -}
160 -
161 -function dispatchHoverEndEvents(
162 - event: null | ReactDOMResponderEvent,
163 - context: ReactDOMResponderContext,
164 - props: HoverProps,
165 - state: HoverState,
166 -): boolean {
167 - const target = state.hoverTarget;
168 - if (event !== null) {
169 - const {nativeEvent} = event;
170 - if (
171 - context.isTargetWithinResponderScope((nativeEvent: any).relatedTarget)
172 - ) {
173 - return false;
174 - }
175 - }
176 -
177 - state.isHovered = false;
178 -
179 - if (state.isActiveHovered) {
180 - state.isActiveHovered = false;
181 - const onHoverEnd = props.onHoverEnd;
182 - if (isFunction(onHoverEnd)) {
183 - const syntheticEvent = createHoverEvent(
184 - event,
185 - context,
186 - 'hoverend',
187 - ((target: any): Element | Document),
188 - );
189 - context.dispatchEvent(syntheticEvent, onHoverEnd, UserBlockingEvent);
190 - }
191 - dispatchHoverChangeEvent(event, context, props, state);
192 - state.hoverTarget = null;
193 - state.isTouched = false;
194 - }
195 - return true;
196 -}
197 -
198 -function unmountResponder(
199 - context: ReactDOMResponderContext,
200 - props: HoverProps,
201 - state: HoverState,
202 -): void {
203 - if (state.isHovered) {
204 - dispatchHoverEndEvents(null, context, props, state);
205 - }
206 -}
207 -
208 -const rootPointerEventTypes = ['pointerout', 'pointermove', 'pointercancel'];
209 -
210 -const hoverResponderImpl = {
211 - targetEventTypes: ['pointerover'],
212 - getInitialState() {
213 - return {
214 - isActiveHovered: false,
215 - isHovered: false,
216 - };
217 - },
218 - allowMultipleHostChildren: false,
219 - allowEventHooks: true,
220 - onRootEvent(
221 - event: ReactDOMResponderEvent,
222 - context: ReactDOMResponderContext,
223 - props: HoverProps,
224 - state: HoverState,
225 - ): void {
226 - const {type} = event;
227 -
228 - switch (type) {
229 - // MOVE
230 - case 'pointermove': {
231 - if (state.isHovered && state.hoverTarget !== null) {
232 - dispatchHoverMoveEvent(event, context, props, state);
233 - }
234 - break;
235 - }
236 -
237 - // END
238 - case 'pointercancel':
239 - case 'pointerout': {
240 - if (state.isHovered) {
241 - if (
242 - dispatchHoverEndEvents(event, context, props, state) ||
243 - type === 'pointercancel'
244 - ) {
245 - context.removeRootEventTypes(rootPointerEventTypes);
246 - }
247 - }
248 - break;
249 - }
250 - }
251 - },
252 - onEvent(
253 - event: ReactDOMResponderEvent,
254 - context: ReactDOMResponderContext,
255 - props: HoverProps,
256 - state: HoverState,
257 - ): void {
258 - const {pointerType, type} = event;
259 -
260 - if (props.disabled) {
261 - if (state.isHovered) {
262 - context.removeRootEventTypes(rootPointerEventTypes);
263 - dispatchHoverEndEvents(event, context, props, state);
264 - }
265 - return;
266 - }
267 -
268 - switch (type) {
269 - // START
270 - case 'pointerover': {
271 - if (!state.isHovered && pointerType !== 'touch') {
272 - state.hoverTarget = context.getResponderNode();
273 - if (dispatchHoverStartEvents(event, context, props, state)) {
274 - context.addRootEventTypes(rootPointerEventTypes);
275 - }
276 - }
277 - break;
278 - }
279 - }
280 - },
281 - onUnmount: unmountResponder,
282 -};
283 -
284 -const rootMouseEventTypes = ['mousemove', 'mouseout'];
285 -
286 -const hoverResponderFallbackImpl = {
287 - targetEventTypes: ['mouseover', 'mousemove', 'touchstart'],
288 - getInitialState() {
289 - return {
290 - isActiveHovered: false,
291 - isHovered: false,
292 - isTouched: false,
293 - ignoreEmulatedMouseEvents: false,
294 - };
295 - },
296 - allowMultipleHostChildren: false,
297 - allowEventHooks: true,
298 - onRootEvent(
299 - event: ReactDOMResponderEvent,
300 - context: ReactDOMResponderContext,
301 - props: HoverProps,
302 - state: HoverState,
303 - ): void {
304 - const {type} = event;
305 -
306 - switch (type) {
307 - // MOVE
308 - case 'mousemove': {
309 - if (
310 - state.isHovered &&
311 - state.hoverTarget !== null &&
312 - !state.ignoreEmulatedMouseEvents
313 - ) {
314 - dispatchHoverMoveEvent(event, context, props, state);
315 - }
316 - break;
317 - }
318 -
319 - // END
320 - case 'mouseout': {
321 - if (state.isHovered) {
322 - if (dispatchHoverEndEvents(event, context, props, state)) {
323 - context.removeRootEventTypes(rootMouseEventTypes);
324 - }
325 - }
326 - break;
327 - }
328 - }
329 - },
330 - onEvent(
331 - event: ReactDOMResponderEvent,
332 - context: ReactDOMResponderContext,
333 - props: HoverProps,
334 - state: HoverState,
335 - ): void {
336 - const {type} = event;
337 -
338 - if (props.disabled) {
339 - if (state.isHovered) {
340 - context.removeRootEventTypes(rootMouseEventTypes);
341 - dispatchHoverEndEvents(event, context, props, state);
342 - state.ignoreEmulatedMouseEvents = false;
343 - }
344 - state.isTouched = false;
345 - return;
346 - }
347 -
348 - switch (type) {
349 - // START
350 - case 'mouseover': {
351 - if (!state.isHovered && !state.ignoreEmulatedMouseEvents) {
352 - state.hoverTarget = context.getResponderNode();
353 - if (dispatchHoverStartEvents(event, context, props, state)) {
354 - context.addRootEventTypes(rootMouseEventTypes);
355 - }
356 - }
357 - break;
358 - }
359 -
360 - // MOVE
361 - case 'mousemove': {
362 - if (!state.isHovered && type === 'mousemove') {
363 - state.ignoreEmulatedMouseEvents = false;
364 - state.isTouched = false;
365 - }
366 - break;
367 - }
368 -
369 - case 'touchstart': {
370 - if (!state.isHovered) {
371 - state.isTouched = true;
372 - state.ignoreEmulatedMouseEvents = true;
373 - }
374 - break;
375 - }
376 - }
377 - },
378 - onUnmount: unmountResponder,
379 -};
380 -
381 -// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
382 -export const HoverResponder = React.DEPRECATED_createResponder(
383 - 'Hover',
384 - hasPointerEvents ? hoverResponderImpl : hoverResponderFallbackImpl,
385 -);
386 -
387 -export function useHover(
388 - props: HoverProps,
389 -): ?ReactEventResponderListener<any, any> {
390 - return React.DEPRECATED_useResponder(HoverResponder, props);
391 -}
packages/react-interactions/events/src/dom/Input.js deleted
-225
@@ -1,225 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import type {
11 - ReactDOMResponderEvent,
12 - ReactDOMResponderContext,
13 -} from 'react-dom/src/shared/ReactDOMTypes';
14 -
15 -import * as React from 'react';
16 -import {DiscreteEvent} from 'shared/ReactTypes';
17 -import type {ReactEventResponderListener} from 'shared/ReactTypes';
18 -
19 -type InputEventType = 'change' | 'beforechange' | 'valuechange';
20 -
21 -type InputResponderProps = {
22 - disabled: boolean,
23 - onBeforeChange: (e: InputEvent) => void,
24 - onChange: (e: InputEvent) => void,
25 - onValueChange: (value: string | boolean) => void,
26 - ...
27 -};
28 -
29 -type InputEvent = {|
30 - data: string,
31 - isComposing: boolean,
32 - inputType: string,
33 - dataTransfer: null | string,
34 - target: Element | Document,
35 - type: InputEventType,
36 - timeStamp: number,
37 -|};
38 -
39 -const targetEventTypes = ['input', 'change', 'beforeinput', 'click'];
40 -
41 -const supportedInputTypes = new Set([
42 - 'color',
43 - 'date',
44 - 'datetime',
45 - 'datetime-local',
46 - 'email',
47 - 'month',
48 - 'number',
49 - 'password',
50 - 'range',
51 - 'search',
52 - 'tel',
53 - 'text',
54 - 'time',
55 - 'url',
56 - 'week',
57 -]);
58 -
59 -function isFunction(obj): boolean {
60 - return typeof obj === 'function';
61 -}
62 -
63 -function createInputEvent(
64 - event: ReactDOMResponderEvent,
65 - context: ReactDOMResponderContext,
66 - type: InputEventType,
67 - target: Document | Element,
68 -): InputEvent {
69 - const {data, dataTransfer, inputType, isComposing} = (event: any).nativeEvent;
70 - return {
71 - data,
72 - dataTransfer,
73 - inputType,
74 - isComposing,
75 - target,
76 - timeStamp: context.getTimeStamp(),
77 - type,
78 - };
79 -}
80 -
81 -function dispatchInputEvent(
82 - event: ReactDOMResponderEvent,
83 - listener: InputEvent => void,
84 - context: ReactDOMResponderContext,
85 - type: InputEventType,
86 - target: Element | Document,
87 -): void {
88 - const syntheticEvent = createInputEvent(event, context, type, target);
89 - context.dispatchEvent(syntheticEvent, listener, DiscreteEvent);
90 -}
91 -
92 -function getNodeName(elem: Element | Document): string {
93 - return elem.nodeName && elem.nodeName.toLowerCase();
94 -}
95 -
96 -function isTextInputElement(elem: Element | Document): boolean {
97 - const nodeName = getNodeName(elem);
98 - const type = (elem: any).type;
99 - return (
100 - nodeName === 'textarea' ||
101 - (nodeName === 'input' && (type == null || supportedInputTypes.has(type)))
102 - );
103 -}
104 -
105 -function isCheckable(elem: Element | Document): boolean {
106 - const nodeName = getNodeName(elem);
107 - const type = (elem: any).type;
108 - return nodeName === 'input' && (type === 'checkbox' || type === 'radio');
109 -}
110 -
111 -function shouldUseChangeEvent(elem: Element | Document): boolean {
112 - const nodeName = getNodeName(elem);
113 - return (
114 - nodeName === 'select' ||
115 - (nodeName === 'input' && (elem: any).type === 'file')
116 - );
117 -}
118 -
119 -function dispatchChangeEvent(
120 - context: ReactDOMResponderContext,
121 - props: InputResponderProps,
122 - target: Element | Document,
123 -): void {
124 - const onValueChange = props.onValueChange;
125 - if (isFunction(onValueChange)) {
126 - const value = getValueFromNode(target);
127 - context.dispatchEvent(value, onValueChange, DiscreteEvent);
128 - }
129 -}
130 -
131 -function dispatchBothChangeEvents(
132 - event: ReactDOMResponderEvent,
133 - context: ReactDOMResponderContext,
134 - props: InputResponderProps,
135 - target: Document | Element,
136 -): void {
137 - context.enqueueStateRestore(target);
138 - const onChange = props.onChange;
139 - if (isFunction(onChange)) {
140 - dispatchInputEvent(event, onChange, context, 'change', target);
141 - }
142 - dispatchChangeEvent(context, props, target);
143 -}
144 -
145 -function updateValueIfChanged(elem: Element | Document): boolean {
146 - // React's internal value tracker
147 - const valueTracker = (elem: any)._valueTracker;
148 - if (valueTracker == null) {
149 - return true;
150 - }
151 - const prevValue = valueTracker.getValue();
152 - const nextValue = getValueFromNode(elem);
153 -
154 - if (prevValue !== nextValue) {
155 - valueTracker.setValue(nextValue);
156 - return true;
157 - }
158 - return false;
159 -}
160 -
161 -function getValueFromNode(node: Element | Document): string {
162 - let value = '';
163 - if (!node) {
164 - return value;
165 - }
166 -
167 - if (isCheckable(node)) {
168 - value = (node: any).checked ? 'true' : 'false';
169 - } else {
170 - value = (node: any).value;
171 - }
172 -
173 - return value;
174 -}
175 -
176 -const inputResponderImpl = {
177 - targetEventTypes,
178 - onEvent(
179 - event: ReactDOMResponderEvent,
180 - context: ReactDOMResponderContext,
181 - props: InputResponderProps,
182 - ): void {
183 - const {type, target} = event;
184 -
185 - if (props.disabled) {
186 - return;
187 - }
188 - const currentTarget = context.getResponderNode();
189 - if (target !== currentTarget || currentTarget === null) {
190 - return;
191 - }
192 - switch (type) {
193 - default: {
194 - if (shouldUseChangeEvent(target) && type === 'change') {
195 - dispatchBothChangeEvents(event, context, props, currentTarget);
196 - } else if (
197 - isTextInputElement(target) &&
198 - (type === 'input' || type === 'change') &&
199 - updateValueIfChanged(target)
200 - ) {
201 - dispatchBothChangeEvents(event, context, props, currentTarget);
202 - } else if (
203 - isCheckable(target) &&
204 - type === 'click' &&
205 - updateValueIfChanged(target)
206 - ) {
207 - dispatchBothChangeEvents(event, context, props, currentTarget);
208 - }
209 - break;
210 - }
211 - }
212 - },
213 -};
214 -
215 -// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
216 -export const InputResponder = React.DEPRECATED_createResponder(
217 - 'Input',
218 - inputResponderImpl,
219 -);
220 -
221 -export function useInput(
222 - props: InputResponderProps,
223 -): ?ReactEventResponderListener<any, any> {
224 - return React.DEPRECATED_useResponder(InputResponder, props);
225 -}
packages/react-interactions/events/src/dom/PressLegacy.js deleted
-924
@@ -1,924 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import type {
11 - ReactDOMResponderEvent,
12 - ReactDOMResponderContext,
13 - PointerType,
14 -} from 'react-dom/src/shared/ReactDOMTypes';
15 -import type {
16 - EventPriority,
17 - ReactEventResponderListener,
18 -} from 'shared/ReactTypes';
19 -
20 -import * as React from 'react';
21 -import {DiscreteEvent, UserBlockingEvent} from 'shared/ReactTypes';
22 -
23 -type PressProps = {|
24 - disabled: boolean,
25 - pressRetentionOffset: {
26 - top: number,
27 - right: number,
28 - bottom: number,
29 - left: number,
30 - ...
31 - },
32 - preventDefault: boolean,
33 - onPress: (e: PressEvent) => void,
34 - onPressChange: boolean => void,
35 - onPressEnd: (e: PressEvent) => void,
36 - onPressMove: (e: PressEvent) => void,
37 - onPressStart: (e: PressEvent) => void,
38 -|};
39 -
40 -type PressState = {
41 - activationPosition: null | $ReadOnly<{|
42 - x: number,
43 - y: number,
44 - |}>,
45 - addedRootEvents: boolean,
46 - buttons: 0 | 1 | 4,
47 - isActivePressed: boolean,
48 - isActivePressStart: boolean,
49 - isPressed: boolean,
50 - isPressWithinResponderRegion: boolean,
51 - pointerType: PointerType,
52 - pressTarget: null | Element | Document,
53 - responderRegionOnActivation: null | $ReadOnly<{|
54 - bottom: number,
55 - left: number,
56 - right: number,
57 - top: number,
58 - |}>,
59 - responderRegionOnDeactivation: null | $ReadOnly<{|
60 - bottom: number,
61 - left: number,
62 - right: number,
63 - top: number,
64 - |}>,
65 - ignoreEmulatedMouseEvents: boolean,
66 - activePointerId: null | number,
67 - shouldPreventClick: boolean,
68 - touchEvent: null | Touch,
69 - ...
70 -};
71 -
72 -type PressEventType =
73 - | 'press'
74 - | 'pressmove'
75 - | 'pressstart'
76 - | 'pressend'
77 - | 'presschange';
78 -
79 -type PressEvent = {|
80 - altKey: boolean,
81 - buttons: 0 | 1 | 4,
82 - clientX: null | number,
83 - clientY: null | number,
84 - ctrlKey: boolean,
85 - defaultPrevented: boolean,
86 - metaKey: boolean,
87 - pageX: null | number,
88 - pageY: null | number,
89 - pointerType: PointerType,
90 - screenX: null | number,
91 - screenY: null | number,
92 - shiftKey: boolean,
93 - target: Element | Document,
94 - timeStamp: number,
95 - type: PressEventType,
96 - x: null | number,
97 - y: null | number,
98 - preventDefault: () => void,
99 - stopPropagation: () => void,
100 -|};
101 -
102 -const hasPointerEvents =
103 - typeof window !== 'undefined' && window.PointerEvent !== undefined;
104 -
105 -const isMac =
106 - typeof window !== 'undefined' && window.navigator != null
107 - ? /^Mac/.test(window.navigator.platform)
108 - : false;
109 -
110 -const DEFAULT_PRESS_RETENTION_OFFSET = {
111 - bottom: 20,
112 - top: 20,
113 - left: 20,
114 - right: 20,
115 -};
116 -
117 -const targetEventTypes = hasPointerEvents
118 - ? ['keydown_active', 'pointerdown_active', 'click_active']
119 - : ['keydown_active', 'touchstart', 'mousedown_active', 'click_active'];
120 -
121 -const rootEventTypes = hasPointerEvents
122 - ? [
123 - 'pointerup_active',
124 - 'pointermove',
125 - 'pointercancel',
126 - 'click',
127 - 'keyup',
128 - 'scroll',
129 - 'blur',
130 - ]
131 - : [
132 - 'click',
133 - 'keyup',
134 - 'scroll',
135 - 'mousemove',
136 - 'touchmove',
137 - 'touchcancel',
138 - // Used as a 'cancel' signal for mouse interactions
139 - 'dragstart',
140 - 'mouseup_active',
141 - 'touchend',
142 - 'blur',
143 - ];
144 -
145 -function isFunction(obj): boolean {
146 - return typeof obj === 'function';
147 -}
148 -
149 -function createPressEvent(
150 - context: ReactDOMResponderContext,
151 - type: PressEventType,
152 - target: Element | Document,
153 - pointerType: PointerType,
154 - event: ?ReactDOMResponderEvent,
155 - touchEvent: null | Touch,
156 - defaultPrevented: boolean,
157 - state: PressState,
158 -): PressEvent {
159 - const timeStamp = context.getTimeStamp();
160 - let clientX = null;
161 - let clientY = null;
162 - let pageX = null;
163 - let pageY = null;
164 - let screenX = null;
165 - let screenY = null;
166 - let altKey = false;
167 - let ctrlKey = false;
168 - let metaKey = false;
169 - let shiftKey = false;
170 - let nativeEvent;
171 -
172 - if (event) {
173 - nativeEvent = (event.nativeEvent: any);
174 - ({altKey, ctrlKey, metaKey, shiftKey} = nativeEvent);
175 - // Only check for one property, checking for all of them is costly. We can assume
176 - // if clientX exists, so do the rest.
177 - const eventObject = (touchEvent: any) || (nativeEvent: any);
178 - if (eventObject) {
179 - ({clientX, clientY, pageX, pageY, screenX, screenY} = eventObject);
180 - }
181 - }
182 - const pressEvent = {
183 - altKey,
184 - buttons: state.buttons,
185 - clientX,
186 - clientY,
187 - ctrlKey,
188 - defaultPrevented,
189 - metaKey,
190 - pageX,
191 - pageY,
192 - pointerType,
193 - screenX,
194 - screenY,
195 - shiftKey,
196 - target,
197 - timeStamp,
198 - type,
199 - x: clientX,
200 - y: clientY,
201 - preventDefault() {
202 - state.shouldPreventClick = true;
203 - if (nativeEvent) {
204 - pressEvent.defaultPrevented = true;
205 - nativeEvent.preventDefault();
206 - }
207 - },
208 - stopPropagation() {
209 - // NO-OP, we should remove this in the future
210 - if (__DEV__) {
211 - console.error(
212 - 'stopPropagation is not available on event objects created from event responder modules (React Flare). ' +
213 - 'Try wrapping in a conditional, i.e. `if (event.type !== "press") { event.stopPropagation() }`',
214 - );
215 - }
216 - },
217 - };
218 - return pressEvent;
219 -}
220 -
221 -function dispatchEvent(
222 - event: ?ReactDOMResponderEvent,
223 - listener: any => void,
224 - context: ReactDOMResponderContext,
225 - state: PressState,
226 - name: PressEventType,
227 - eventPriority: EventPriority,
228 -): void {
229 - const target = ((state.pressTarget: any): Element | Document);
230 - const pointerType = state.pointerType;
231 - const defaultPrevented =
232 - (event != null && event.nativeEvent.defaultPrevented === true) ||
233 - (name === 'press' && state.shouldPreventClick);
234 - const touchEvent = state.touchEvent;
235 - const syntheticEvent = createPressEvent(
236 - context,
237 - name,
238 - target,
239 - pointerType,
240 - event,
241 - touchEvent,
242 - defaultPrevented,
243 - state,
244 - );
245 - context.dispatchEvent(syntheticEvent, listener, eventPriority);
246 -}
247 -
248 -function dispatchPressChangeEvent(
249 - context: ReactDOMResponderContext,
250 - props: PressProps,
251 - state: PressState,
252 -): void {
253 - const onPressChange = props.onPressChange;
254 - if (isFunction(onPressChange)) {
255 - const bool = state.isActivePressed;
256 - context.dispatchEvent(bool, onPressChange, DiscreteEvent);
257 - }
258 -}
259 -
260 -function dispatchPressStartEvents(
261 - event: ReactDOMResponderEvent,
262 - context: ReactDOMResponderContext,
263 - props: PressProps,
264 - state: PressState,
265 -): void {
266 - state.isPressed = true;
267 -
268 - if (!state.isActivePressStart) {
269 - state.isActivePressStart = true;
270 - const nativeEvent: any = event.nativeEvent;
271 - const {clientX: x, clientY: y} = state.touchEvent || nativeEvent;
272 - const wasActivePressed = state.isActivePressed;
273 - state.isActivePressed = true;
274 - if (x !== undefined && y !== undefined) {
275 - state.activationPosition = {x, y};
276 - }
277 - const onPressStart = props.onPressStart;
278 -
279 - if (isFunction(onPressStart)) {
280 - dispatchEvent(
281 - event,
282 - onPressStart,
283 - context,
284 - state,
285 - 'pressstart',
286 - DiscreteEvent,
287 - );
288 - }
289 - if (!wasActivePressed) {
290 - dispatchPressChangeEvent(context, props, state);
291 - }
292 - }
293 -}
294 -
295 -function dispatchPressEndEvents(
296 - event: ?ReactDOMResponderEvent,
297 - context: ReactDOMResponderContext,
298 - props: PressProps,
299 - state: PressState,
300 -): void {
301 - state.isActivePressStart = false;
302 - state.isPressed = false;
303 -
304 - if (state.isActivePressed) {
305 - state.isActivePressed = false;
306 - const onPressEnd = props.onPressEnd;
307 -
308 - if (isFunction(onPressEnd)) {
309 - dispatchEvent(
310 - event,
311 - onPressEnd,
312 - context,
313 - state,
314 - 'pressend',
315 - DiscreteEvent,
316 - );
317 - }
318 - dispatchPressChangeEvent(context, props, state);
319 - }
320 -
321 - state.responderRegionOnDeactivation = null;
322 -}
323 -
324 -function dispatchCancel(
325 - event: ReactDOMResponderEvent,
326 - context: ReactDOMResponderContext,
327 - props: PressProps,
328 - state: PressState,
329 -): void {
330 - state.touchEvent = null;
331 - if (state.isPressed) {
332 - state.ignoreEmulatedMouseEvents = false;
333 - dispatchPressEndEvents(event, context, props, state);
334 - }
335 - removeRootEventTypes(context, state);
336 -}
337 -
338 -function isValidKeyboardEvent(nativeEvent: Object): boolean {
339 - const {key, target} = nativeEvent;
340 - const {tagName, isContentEditable} = target;
341 - // Accessibility for keyboards. Space and Enter only.
342 - // "Spacebar" is for IE 11
343 - return (
344 - (key === 'Enter' || key === ' ' || key === 'Spacebar') &&
345 - tagName !== 'INPUT' &&
346 - tagName !== 'TEXTAREA' &&
347 - isContentEditable !== true
348 - );
349 -}
350 -
351 -// TODO: account for touch hit slop
352 -function calculateResponderRegion(
353 - context: ReactDOMResponderContext,
354 - target: Element,
355 - props: PressProps,
356 -) {
357 - const pressRetentionOffset = context.objectAssign(
358 - {},
359 - DEFAULT_PRESS_RETENTION_OFFSET,
360 - props.pressRetentionOffset,
361 - );
362 -
363 - let {left, right, bottom, top} = target.getBoundingClientRect();
364 -
365 - if (pressRetentionOffset) {
366 - if (pressRetentionOffset.bottom != null) {
367 - bottom += pressRetentionOffset.bottom;
368 - }
369 - if (pressRetentionOffset.left != null) {
370 - left -= pressRetentionOffset.left;
371 - }
372 - if (pressRetentionOffset.right != null) {
373 - right += pressRetentionOffset.right;
374 - }
375 - if (pressRetentionOffset.top != null) {
376 - top -= pressRetentionOffset.top;
377 - }
378 - }
379 -
380 - return {
381 - bottom,
382 - top,
383 - left,
384 - right,
385 - };
386 -}
387 -
388 -function getTouchFromPressEvent(nativeEvent: TouchEvent): null | Touch {
389 - const targetTouches = nativeEvent.targetTouches;
390 - if (targetTouches.length > 0) {
391 - return targetTouches[0];
392 - }
393 - return null;
394 -}
395 -
396 -function unmountResponder(
397 - context: ReactDOMResponderContext,
398 - props: PressProps,
399 - state: PressState,
400 -): void {
401 - if (state.isPressed) {
402 - removeRootEventTypes(context, state);
403 - dispatchPressEndEvents(null, context, props, state);
404 - }
405 -}
406 -
407 -function addRootEventTypes(
408 - context: ReactDOMResponderContext,
409 - state: PressState,
410 -): void {
411 - if (!state.addedRootEvents) {
412 - state.addedRootEvents = true;
413 - context.addRootEventTypes(rootEventTypes);
414 - }
415 -}
416 -
417 -function removeRootEventTypes(
418 - context: ReactDOMResponderContext,
419 - state: PressState,
420 -): void {
421 - if (state.addedRootEvents) {
422 - state.addedRootEvents = false;
423 - context.removeRootEventTypes(rootEventTypes);
424 - }
425 -}
426 -
427 -function getTouchById(
428 - nativeEvent: TouchEvent,
429 - pointerId: null | number,
430 -): null | Touch {
431 - const changedTouches = nativeEvent.changedTouches;
432 - for (let i = 0; i < changedTouches.length; i++) {
433 - const touch = changedTouches[i];
434 - if (touch.identifier === pointerId) {
435 - return touch;
436 - }
437 - }
438 - return null;
439 -}
440 -
441 -function getTouchTarget(context: ReactDOMResponderContext, touchEvent: Touch) {
442 - const doc = context.getActiveDocument();
443 - return doc.elementFromPoint(touchEvent.clientX, touchEvent.clientY);
444 -}
445 -
446 -function updateIsPressWithinResponderRegion(
447 - nativeEventOrTouchEvent: Event | Touch,
448 - context: ReactDOMResponderContext,
449 - props: PressProps,
450 - state: PressState,
451 -): void {
452 - // Calculate the responder region we use for deactivation if not
453 - // already done during move event.
454 - if (state.responderRegionOnDeactivation == null) {
455 - state.responderRegionOnDeactivation = calculateResponderRegion(
456 - context,
457 - ((state.pressTarget: any): Element),
458 - props,
459 - );
460 - }
461 - const {responderRegionOnActivation, responderRegionOnDeactivation} = state;
462 - let left, top, right, bottom;
463 -
464 - if (responderRegionOnActivation != null) {
465 - left = responderRegionOnActivation.left;
466 - top = responderRegionOnActivation.top;
467 - right = responderRegionOnActivation.right;
468 - bottom = responderRegionOnActivation.bottom;
469 -
470 - if (responderRegionOnDeactivation != null) {
471 - left = Math.min(left, responderRegionOnDeactivation.left);
472 - top = Math.min(top, responderRegionOnDeactivation.top);
473 - right = Math.max(right, responderRegionOnDeactivation.right);
474 - bottom = Math.max(bottom, responderRegionOnDeactivation.bottom);
475 - }
476 - }
477 - const {clientX: x, clientY: y} = (nativeEventOrTouchEvent: any);
478 -
479 - state.isPressWithinResponderRegion =
480 - left != null &&
481 - right != null &&
482 - top != null &&
483 - bottom != null &&
484 - x !== null &&
485 - y !== null &&
486 - x >= left &&
487 - x <= right &&
488 - y >= top &&
489 - y <= bottom;
490 -}
491 -
492 -// After some investigation work, screen reader virtual
493 -// clicks (NVDA, Jaws, VoiceOver) do not have co-ords associated with the click
494 -// event and "detail" is always 0 (where normal clicks are > 0)
495 -function isScreenReaderVirtualClick(nativeEvent): boolean {
496 - // JAWS/NVDA with Firefox.
497 - if (nativeEvent.mozInputSource === 0 && nativeEvent.isTrusted) {
498 - return true;
499 - }
500 - // Chrome
501 - return (
502 - nativeEvent.detail === 0 &&
503 - nativeEvent.screenX === 0 &&
504 - nativeEvent.screenY === 0 &&
505 - nativeEvent.clientX === 0 &&
506 - nativeEvent.clientY === 0
507 - );
508 -}
509 -
510 -function targetIsDocument(target: null | Node): boolean {
511 - // When target is null, it is the root
512 - return target === null || target.nodeType === 9;
513 -}
514 -
515 -const pressResponderImpl = {
516 - targetEventTypes,
517 - getInitialState(): PressState {
518 - return {
519 - activationPosition: null,
520 - addedRootEvents: false,
521 - buttons: 0,
522 - isActivePressed: false,
523 - isActivePressStart: false,
524 - isPressed: false,
525 - isPressWithinResponderRegion: true,
526 - pointerType: '',
527 - pressTarget: null,
528 - responderRegionOnActivation: null,
529 - responderRegionOnDeactivation: null,
530 - ignoreEmulatedMouseEvents: false,
531 - activePointerId: null,
532 - shouldPreventClick: false,
533 - touchEvent: null,
534 - };
535 - },
536 - onEvent(
537 - event: ReactDOMResponderEvent,
538 - context: ReactDOMResponderContext,
539 - props: PressProps,
540 - state: PressState,
541 - ): void {
542 - const {pointerType, type} = event;
543 -
544 - if (props.disabled) {
545 - removeRootEventTypes(context, state);
546 - dispatchPressEndEvents(event, context, props, state);
547 - state.ignoreEmulatedMouseEvents = false;
548 - return;
549 - }
550 - const nativeEvent: any = event.nativeEvent;
551 - const isPressed = state.isPressed;
552 -
553 - switch (type) {
554 - // START
555 - case 'pointerdown':
556 - case 'keydown':
557 - case 'mousedown':
558 - case 'touchstart': {
559 - if (!isPressed) {
560 - const isTouchEvent = type === 'touchstart';
561 - const isPointerEvent = type === 'pointerdown';
562 - const isKeyboardEvent = pointerType === 'keyboard';
563 - const isMouseEvent = pointerType === 'mouse';
564 -
565 - // Ignore emulated mouse events
566 - if (type === 'mousedown' && state.ignoreEmulatedMouseEvents) {
567 - return;
568 - }
569 -
570 - state.shouldPreventClick = false;
571 - if (isTouchEvent) {
572 - state.ignoreEmulatedMouseEvents = true;
573 - } else if (isKeyboardEvent) {
574 - // Ignore unrelated key events
575 - if (isValidKeyboardEvent(nativeEvent)) {
576 - const {
577 - altKey,
578 - ctrlKey,
579 - metaKey,
580 - shiftKey,
581 - } = (nativeEvent: MouseEvent);
582 - if (
583 - props.preventDefault !== false &&
584 - !shiftKey &&
585 - !metaKey &&
586 - !ctrlKey &&
587 - !altKey
588 - ) {
589 - // Prevent spacebar press from scrolling the window
590 - const key = nativeEvent.key;
591 - if (key === ' ' || key === 'Spacebar') {
592 - nativeEvent.preventDefault();
593 - }
594 - state.shouldPreventClick = true;
595 - }
596 - } else {
597 - return;
598 - }
599 - }
600 -
601 - // We set these here, before the button check so we have this
602 - // data around for handling of the context menu
603 - state.pointerType = pointerType;
604 - const pressTarget = (state.pressTarget = context.getResponderNode());
605 - if (isPointerEvent) {
606 - state.activePointerId = nativeEvent.pointerId;
607 - } else if (isTouchEvent) {
608 - const touchEvent = getTouchFromPressEvent(nativeEvent);
609 - if (touchEvent === null) {
610 - return;
611 - }
612 - state.touchEvent = touchEvent;
613 - state.activePointerId = touchEvent.identifier;
614 - }
615 -
616 - // Ignore any device buttons except primary/middle and touch/pen contact.
617 - // Additionally we ignore primary-button + ctrl-key with Macs as that
618 - // acts like right-click and opens the contextmenu.
619 - if (
620 - nativeEvent.buttons === 2 ||
621 - nativeEvent.buttons > 4 ||
622 - (isMac && isMouseEvent && nativeEvent.ctrlKey)
623 - ) {
624 - return;
625 - }
626 - // Exclude document targets
627 - if (!targetIsDocument(pressTarget)) {
628 - state.responderRegionOnActivation = calculateResponderRegion(
629 - context,
630 - ((pressTarget: any): Element),
631 - props,
632 - );
633 - }
634 - state.responderRegionOnDeactivation = null;
635 - state.isPressWithinResponderRegion = true;
636 - state.buttons = nativeEvent.buttons;
637 - if (nativeEvent.button === 1) {
638 - state.buttons = 4;
639 - }
640 - dispatchPressStartEvents(event, context, props, state);
641 - addRootEventTypes(context, state);
642 - } else {
643 - // Prevent spacebar press from scrolling the window
644 - const key = nativeEvent.key;
645 - if (
646 - isValidKeyboardEvent(nativeEvent) &&
647 - (key === ' ' || key === 'Spacebar')
648 - ) {
649 - nativeEvent.preventDefault();
650 - }
651 - }
652 - break;
653 - }
654 -
655 - case 'click': {
656 - if (state.shouldPreventClick) {
657 - nativeEvent.preventDefault();
658 - }
659 - const onPress = props.onPress;
660 -
661 - if (isFunction(onPress) && isScreenReaderVirtualClick(nativeEvent)) {
662 - state.pointerType = 'keyboard';
663 - state.pressTarget = context.getResponderNode();
664 - const preventDefault = props.preventDefault;
665 -
666 - if (preventDefault !== false) {
667 - nativeEvent.preventDefault();
668 - }
669 - dispatchEvent(event, onPress, context, state, 'press', DiscreteEvent);
670 - }
671 - break;
672 - }
673 - }
674 - },
675 - onRootEvent(
676 - event: ReactDOMResponderEvent,
677 - context: ReactDOMResponderContext,
678 - props: PressProps,
679 - state: PressState,
680 - ): void {
681 - const {pointerType, type} = event;
682 - let target = event.target;
683 -
684 - const nativeEvent: any = event.nativeEvent;
685 - const isPressed = state.isPressed;
686 - const activePointerId = state.activePointerId;
687 - const previousPointerType = state.pointerType;
688 -
689 - switch (type) {
690 - // MOVE
691 - case 'pointermove':
692 - case 'mousemove':
693 - case 'touchmove': {
694 - let touchEvent;
695 - // Ignore emulated events (pointermove will dispatch touch and mouse events)
696 - // Ignore pointermove events during a keyboard press.
697 - if (previousPointerType !== pointerType) {
698 - return;
699 - }
700 - if (
701 - type === 'pointermove' &&
702 - activePointerId !== nativeEvent.pointerId
703 - ) {
704 - return;
705 - } else if (type === 'touchmove') {
706 - touchEvent = getTouchById(nativeEvent, activePointerId);
707 - if (touchEvent === null) {
708 - return;
709 - }
710 - state.touchEvent = touchEvent;
711 - }
712 - const pressTarget = state.pressTarget;
713 -
714 - if (pressTarget !== null && !targetIsDocument(pressTarget)) {
715 - if (
716 - pointerType === 'mouse' &&
717 - context.isTargetWithinNode(target, pressTarget)
718 - ) {
719 - state.isPressWithinResponderRegion = true;
720 - } else {
721 - // Calculate the responder region we use for deactivation, as the
722 - // element dimensions may have changed since activation.
723 - updateIsPressWithinResponderRegion(
724 - touchEvent || nativeEvent,
725 - context,
726 - props,
727 - state,
728 - );
729 - }
730 - }
731 -
732 - if (state.isPressWithinResponderRegion) {
733 - if (isPressed) {
734 - const onPressMove = props.onPressMove;
735 -
736 - if (isFunction(onPressMove)) {
737 - dispatchEvent(
738 - event,
739 - onPressMove,
740 - context,
741 - state,
742 - 'pressmove',
743 - UserBlockingEvent,
744 - );
745 - }
746 - } else {
747 - dispatchPressStartEvents(event, context, props, state);
748 - }
749 - } else {
750 - dispatchPressEndEvents(event, context, props, state);
751 - }
752 - break;
753 - }
754 -
755 - // END
756 - case 'pointerup':
757 - case 'keyup':
758 - case 'mouseup':
759 - case 'touchend': {
760 - if (isPressed) {
761 - const buttons = state.buttons;
762 - let isKeyboardEvent = false;
763 - let touchEvent;
764 - if (
765 - type === 'pointerup' &&
766 - activePointerId !== nativeEvent.pointerId
767 - ) {
768 - return;
769 - } else if (type === 'touchend') {
770 - touchEvent = getTouchById(nativeEvent, activePointerId);
771 - if (touchEvent === null) {
772 - return;
773 - }
774 - state.touchEvent = touchEvent;
775 - target = getTouchTarget(context, touchEvent);
776 - } else if (type === 'keyup') {
777 - // Ignore unrelated keyboard events
778 - if (!isValidKeyboardEvent(nativeEvent)) {
779 - return;
780 - }
781 - isKeyboardEvent = true;
782 - removeRootEventTypes(context, state);
783 - } else if (buttons === 4) {
784 - // Remove the root events here as no 'click' event is dispatched when this 'button' is pressed.
785 - removeRootEventTypes(context, state);
786 - }
787 -
788 - // Determine whether to call preventDefault on subsequent native events.
789 - if (
790 - target !== null &&
791 - context.isTargetWithinResponder(target) &&
792 - context.isTargetWithinHostComponent(target, 'a')
793 - ) {
794 - const {
795 - altKey,
796 - ctrlKey,
797 - metaKey,
798 - shiftKey,
799 - } = (nativeEvent: MouseEvent);
800 - // Check "open in new window/tab" and "open context menu" key modifiers
801 - const preventDefault = props.preventDefault;
802 -
803 - if (
804 - preventDefault !== false &&
805 - !shiftKey &&
806 - !metaKey &&
807 - !ctrlKey &&
808 - !altKey
809 - ) {
810 - state.shouldPreventClick = true;
811 - }
812 - }
813 -
814 - const pressTarget = state.pressTarget;
815 - dispatchPressEndEvents(event, context, props, state);
816 - const onPress = props.onPress;
817 -
818 - if (pressTarget !== null && isFunction(onPress)) {
819 - if (
820 - !isKeyboardEvent &&
821 - pressTarget !== null &&
822 - target !== null &&
823 - !targetIsDocument(pressTarget)
824 - ) {
825 - if (
826 - pointerType === 'mouse' &&
827 - context.isTargetWithinNode(target, pressTarget)
828 - ) {
829 - state.isPressWithinResponderRegion = true;
830 - } else {
831 - // If the event target isn't within the press target, check if we're still
832 - // within the responder region. The region may have changed if the
833 - // element's layout was modified after activation.
834 - updateIsPressWithinResponderRegion(
835 - touchEvent || nativeEvent,
836 - context,
837 - props,
838 - state,
839 - );
840 - }
841 - }
842 -
843 - if (state.isPressWithinResponderRegion && buttons !== 4) {
844 - dispatchEvent(
845 - event,
846 - onPress,
847 - context,
848 - state,
849 - 'press',
850 - DiscreteEvent,
851 - );
852 - }
853 - }
854 - state.touchEvent = null;
855 - } else if (type === 'mouseup') {
856 - state.ignoreEmulatedMouseEvents = false;
857 - }
858 - break;
859 - }
860 -
861 - case 'click': {
862 - // "keyup" occurs after "click"
863 - if (previousPointerType !== 'keyboard') {
864 - removeRootEventTypes(context, state);
865 - }
866 - break;
867 - }
868 -
869 - // CANCEL
870 - case 'scroll': {
871 - // We ignore incoming scroll events when using mouse events
872 - if (previousPointerType === 'mouse') {
873 - return;
874 - }
875 - const pressTarget = state.pressTarget;
876 - const scrollTarget = nativeEvent.target;
877 - const doc = context.getActiveDocument();
878 - // If the scroll target is the document or if the press target
879 - // is inside the scroll target, then this a scroll that should
880 - // trigger a cancel.
881 - if (
882 - pressTarget !== null &&
883 - (scrollTarget === doc ||
884 - context.isTargetWithinNode(pressTarget, scrollTarget))
885 - ) {
886 - dispatchCancel(event, context, props, state);
887 - }
888 - break;
889 - }
890 - case 'pointercancel':
891 - case 'touchcancel':
892 - case 'dragstart': {
893 - dispatchCancel(event, context, props, state);
894 - break;
895 - }
896 - case 'blur': {
897 - // If we encounter a blur that happens on the pressed target
898 - // then disengage the blur.
899 - if (isPressed && target === state.pressTarget) {
900 - dispatchCancel(event, context, props, state);
901 - }
902 - }
903 - }
904 - },
905 - onUnmount(
906 - context: ReactDOMResponderContext,
907 - props: PressProps,
908 - state: PressState,
909 - ) {
910 - unmountResponder(context, props, state);
911 - },
912 -};
913 -
914 -// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
915 -export const PressResponder = React.DEPRECATED_createResponder(
916 - 'Press',
917 - pressResponderImpl,
918 -);
919 -
920 -export function usePress(
921 - props: PressProps,
922 -): ?ReactEventResponderListener<any, any> {
923 - return React.DEPRECATED_useResponder(PressResponder, props);
924 -}
packages/react-interactions/events/src/dom/Tap.js deleted
-734
@@ -1,734 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import type {
11 - ReactDOMResponderContext,
12 - ReactDOMResponderEvent,
13 - PointerType,
14 -} from 'react-dom/src/shared/ReactDOMTypes';
15 -import type {ReactEventResponderListener} from 'shared/ReactTypes';
16 -
17 -import * as React from 'react';
18 -import {
19 - buttonsEnum,
20 - dispatchDiscreteEvent,
21 - dispatchUserBlockingEvent,
22 - getTouchById,
23 - hasModifierKey,
24 - hasPointerEvents,
25 -} from './shared';
26 -
27 -type TapProps = $ReadOnly<{|
28 - disabled?: boolean,
29 - maximumDistance?: number,
30 - preventDefault?: boolean,
31 - onAuxiliaryTap?: (e: TapEvent) => void,
32 - onTapCancel?: (e: TapEvent) => void,
33 - onTapChange?: boolean => void,
34 - onTapEnd?: (e: TapEvent) => void,
35 - onTapStart?: (e: TapEvent) => void,
36 - onTapUpdate?: (e: TapEvent) => void,
37 -|}>;
38 -
39 -type TapGestureState = {|
40 - altKey: boolean,
41 - ctrlKey: boolean,
42 - height: number,
43 - metaKey: boolean,
44 - pageX: number,
45 - pageY: number,
46 - pointerType: PointerType,
47 - pressure: number,
48 - screenX: number,
49 - screenY: number,
50 - shiftKey: boolean,
51 - tangentialPressure: number,
52 - target: null | Element,
53 - tiltX: number,
54 - tiltY: number,
55 - timeStamp: number,
56 - twist: number,
57 - width: number,
58 - x: number,
59 - y: number,
60 -|};
61 -
62 -type TapState = {|
63 - activePointerId: null | number,
64 - buttons: 0 | 1 | 4,
65 - gestureState: TapGestureState,
66 - ignoreEmulatedEvents: boolean,
67 - initialPosition: {|x: number, y: number|},
68 - isActive: boolean,
69 - isAuxiliaryActive: boolean,
70 - pointerType: PointerType,
71 - responderTarget: null | Element,
72 - rootEvents: null | Array<string>,
73 - shouldPreventDefault: boolean,
74 -|};
75 -
76 -type TapEventType =
77 - | 'tap:auxiliary'
78 - | 'tap:cancel'
79 - | 'tap:change'
80 - | 'tap:end'
81 - | 'tap:start'
82 - | 'tap:update';
83 -
84 -type TapEvent = {|
85 - ...TapGestureState,
86 - defaultPrevented: boolean,
87 - type: TapEventType,
88 -|};
89 -
90 -/**
91 - * Native event dependencies
92 - */
93 -
94 -const targetEventTypes = hasPointerEvents
95 - ? ['pointerdown']
96 - : ['mousedown', 'touchstart'];
97 -
98 -const rootEventTypes = hasPointerEvents
99 - ? [
100 - 'click_active',
101 - 'contextmenu',
102 - 'pointerup',
103 - 'pointermove',
104 - 'pointercancel',
105 - 'scroll',
106 - 'blur',
107 - ]
108 - : [
109 - 'click_active',
110 - 'contextmenu',
111 - 'mouseup',
112 - 'mousemove',
113 - 'dragstart',
114 - 'touchend',
115 - 'touchmove',
116 - 'touchcancel',
117 - 'scroll',
118 - 'blur',
119 - ];
120 -
121 -/**
122 - * Responder and gesture state
123 - */
124 -
125 -function createInitialState(): TapState {
126 - return {
127 - activePointerId: null,
128 - buttons: 0,
129 - ignoreEmulatedEvents: false,
130 - isActive: false,
131 - isAuxiliaryActive: false,
132 - initialPosition: {x: 0, y: 0},
133 - pointerType: '',
134 - responderTarget: null,
135 - rootEvents: null,
136 - shouldPreventDefault: true,
137 - gestureState: {
138 - altKey: false,
139 - ctrlKey: false,
140 - height: 1,
141 - metaKey: false,
142 - pageX: 0,
143 - pageY: 0,
144 - pointerType: '',
145 - pressure: 0,
146 - screenX: 0,
147 - screenY: 0,
148 - shiftKey: false,
149 - tangentialPressure: 0,
150 - target: null,
151 - tiltX: 0,
152 - tiltY: 0,
153 - timeStamp: 0,
154 - twist: 0,
155 - width: 1,
156 - x: 0,
157 - y: 0,
158 - },
159 - };
160 -}
161 -
162 -function createPointerEventGestureState(
163 - context: ReactDOMResponderContext,
164 - props: TapProps,
165 - state: TapState,
166 - event: ReactDOMResponderEvent,
167 -): TapGestureState {
168 - const timeStamp = context.getTimeStamp();
169 - const nativeEvent = (event.nativeEvent: any);
170 - const {
171 - altKey,
172 - ctrlKey,
173 - height,
174 - metaKey,
175 - pageX,
176 - pageY,
177 - pointerType,
178 - pressure,
179 - screenX,
180 - screenY,
181 - shiftKey,
182 - tangentialPressure,
183 - tiltX,
184 - tiltY,
185 - twist,
186 - width,
187 - clientX,
188 - clientY,
189 - } = nativeEvent;
190 -
191 - return {
192 - altKey,
193 - ctrlKey,
194 - height,
195 - metaKey,
196 - pageX,
197 - pageY,
198 - pointerType,
199 - pressure,
200 - screenX,
201 - screenY,
202 - shiftKey,
203 - tangentialPressure,
204 - target: state.responderTarget,
205 - tiltX,
206 - tiltY,
207 - timeStamp,
208 - twist,
209 - width,
210 - x: clientX,
211 - y: clientY,
212 - };
213 -}
214 -
215 -function createFallbackGestureState(
216 - context: ReactDOMResponderContext,
217 - props: TapProps,
218 - state: TapState,
219 - event: ReactDOMResponderEvent,
220 -): TapGestureState {
221 - const timeStamp = context.getTimeStamp();
222 - const nativeEvent = (event.nativeEvent: any);
223 - const eType = event.type;
224 - const {altKey, ctrlKey, metaKey, shiftKey} = nativeEvent;
225 - const isCancelType = eType === 'dragstart' || eType === 'touchcancel';
226 - const isEndType = eType === 'mouseup' || eType === 'touchend';
227 - const isTouchEvent = event.pointerType === 'touch';
228 -
229 - let pointerEvent = nativeEvent;
230 - if (!hasPointerEvents && isTouchEvent) {
231 - const touch = getTouchById(nativeEvent, state.activePointerId);
232 - if (touch != null) {
233 - pointerEvent = touch;
234 - }
235 - }
236 -
237 - const {
238 - pageX,
239 - pageY,
240 - // $FlowExpectedError: missing from 'Touch' typedef
241 - radiusX,
242 - // $FlowExpectedError: missing from 'Touch' typedef
243 - radiusY,
244 - // $FlowExpectedError: missing from 'Touch' typedef
245 - rotationAngle,
246 - screenX,
247 - screenY,
248 - clientX,
249 - clientY,
250 - } = pointerEvent;
251 -
252 - return {
253 - altKey,
254 - ctrlKey,
255 - height: !isCancelType && radiusY != null ? radiusY * 2 : 1,
256 - metaKey,
257 - pageX: isCancelType ? 0 : pageX,
258 - pageY: isCancelType ? 0 : pageY,
259 - pointerType: event.pointerType,
260 - pressure: isEndType || isCancelType ? 0 : isTouchEvent ? 1 : 0.5,
261 - screenX: isCancelType ? 0 : screenX,
262 - screenY: isCancelType ? 0 : screenY,
263 - shiftKey,
264 - tangentialPressure: 0,
265 - target: state.responderTarget,
266 - tiltX: 0,
267 - tiltY: 0,
268 - timeStamp,
269 - twist: rotationAngle != null ? rotationAngle : 0,
270 - width: !isCancelType && radiusX != null ? radiusX * 2 : 1,
271 - x: isCancelType ? 0 : clientX,
272 - y: isCancelType ? 0 : clientY,
273 - };
274 -}
275 -
276 -const createGestureState = hasPointerEvents
277 - ? createPointerEventGestureState
278 - : createFallbackGestureState;
279 -
280 -/**
281 - * Managing root events
282 - */
283 -
284 -function addRootEventTypes(
285 - rootEvents: Array<string>,
286 - context: ReactDOMResponderContext,
287 - state: TapState,
288 -): void {
289 - if (!state.rootEvents) {
290 - state.rootEvents = rootEvents;
291 - context.addRootEventTypes(state.rootEvents);
292 - }
293 -}
294 -
295 -function removeRootEventTypes(
296 - context: ReactDOMResponderContext,
297 - state: TapState,
298 -): void {
299 - if (state.rootEvents != null) {
300 - context.removeRootEventTypes(state.rootEvents);
301 - state.rootEvents = null;
302 - }
303 -}
304 -
305 -/**
306 - * Managing pointers
307 - */
308 -
309 -function getHitTarget(
310 - event: ReactDOMResponderEvent,
311 - context: ReactDOMResponderContext,
312 - state: TapState,
313 -): null | Element | Document {
314 - if (!hasPointerEvents && event.pointerType === 'touch') {
315 - const doc = context.getActiveDocument();
316 - const nativeEvent: any = event.nativeEvent;
317 - const touch = getTouchById(nativeEvent, state.activePointerId);
318 - if (touch != null) {
319 - return doc.elementFromPoint(touch.clientX, touch.clientY);
320 - } else {
321 - return null;
322 - }
323 - }
324 - return event.target;
325 -}
326 -
327 -function isActivePointer(
328 - event: ReactDOMResponderEvent,
329 - state: TapState,
330 -): boolean {
331 - const nativeEvent: any = event.nativeEvent;
332 - const activePointerId = state.activePointerId;
333 -
334 - if (hasPointerEvents) {
335 - const eventPointerId = nativeEvent.pointerId;
336 - if (activePointerId != null && eventPointerId != null) {
337 - return (
338 - state.pointerType === event.pointerType &&
339 - activePointerId === eventPointerId
340 - );
341 - } else {
342 - return true;
343 - }
344 - } else {
345 - if (event.pointerType === 'touch') {
346 - const touch = getTouchById(nativeEvent, activePointerId);
347 - return touch != null;
348 - } else {
349 - // accept all events that don't have pointer ids
350 - return true;
351 - }
352 - }
353 -}
354 -
355 -function isAuxiliary(buttons: number, event: ReactDOMResponderEvent): boolean {
356 - const nativeEvent: any = event.nativeEvent;
357 - const isPrimaryPointer =
358 - buttons === buttonsEnum.primary || event.pointerType === 'touch';
359 - return (
360 - // middle-click
361 - buttons === buttonsEnum.auxiliary ||
362 - // open-in-new-tab
363 - (isPrimaryPointer && nativeEvent.metaKey) ||
364 - // open-in-new-window
365 - (isPrimaryPointer && nativeEvent.shiftKey)
366 - );
367 -}
368 -
369 -function shouldActivate(event: ReactDOMResponderEvent): boolean {
370 - const nativeEvent: any = event.nativeEvent;
371 - const isPrimaryPointer =
372 - nativeEvent.buttons === buttonsEnum.primary ||
373 - event.pointerType === 'touch';
374 - return isPrimaryPointer && !hasModifierKey(event);
375 -}
376 -
377 -/**
378 - * Communicating gesture state back to components
379 - */
380 -
381 -function dispatchStart(
382 - context: ReactDOMResponderContext,
383 - props: TapProps,
384 - state: TapState,
385 -): void {
386 - const type = 'tap:start';
387 - const onTapStart = props.onTapStart;
388 - if (onTapStart != null) {
389 - const payload = context.objectAssign({}, state.gestureState, {type});
390 - dispatchDiscreteEvent(context, payload, onTapStart);
391 - }
392 - dispatchChange(context, props, state);
393 -}
394 -
395 -function dispatchChange(
396 - context: ReactDOMResponderContext,
397 - props: TapProps,
398 - state: TapState,
399 -): void {
400 - const onTapChange = props.onTapChange;
401 - if (onTapChange != null) {
402 - const payload = state.isActive;
403 - dispatchDiscreteEvent(context, payload, onTapChange);
404 - }
405 -}
406 -
407 -function dispatchUpdate(
408 - context: ReactDOMResponderContext,
409 - props: TapProps,
410 - state: TapState,
411 -) {
412 - const type = 'tap:update';
413 - const onTapUpdate = props.onTapUpdate;
414 - if (onTapUpdate != null) {
415 - const payload = context.objectAssign({}, state.gestureState, {type});
416 - dispatchUserBlockingEvent(context, payload, onTapUpdate);
417 - }
418 -}
419 -
420 -function dispatchEnd(
421 - context: ReactDOMResponderContext,
422 - props: TapProps,
423 - state: TapState,
424 -): void {
425 - const type = 'tap:end';
426 - const onTapEnd = props.onTapEnd;
427 - dispatchChange(context, props, state);
428 - if (onTapEnd != null) {
429 - const defaultPrevented = state.shouldPreventDefault === true;
430 - const payload = context.objectAssign({}, state.gestureState, {
431 - defaultPrevented,
432 - type,
433 - });
434 - dispatchDiscreteEvent(context, payload, onTapEnd);
435 - }
436 -}
437 -
438 -function dispatchCancel(
439 - context: ReactDOMResponderContext,
440 - props: TapProps,
441 - state: TapState,
442 -): void {
443 - const type = 'tap:cancel';
444 - const onTapCancel = props.onTapCancel;
445 - dispatchChange(context, props, state);
446 - if (onTapCancel != null) {
447 - const payload = context.objectAssign({}, state.gestureState, {type});
448 - dispatchDiscreteEvent(context, payload, onTapCancel);
449 - }
450 -}
451 -
452 -function dispatchAuxiliaryTap(
453 - context: ReactDOMResponderContext,
454 - props: TapProps,
455 - state: TapState,
456 -): void {
457 - const type = 'tap:auxiliary';
458 - const onAuxiliaryTap = props.onAuxiliaryTap;
459 - if (onAuxiliaryTap != null) {
460 - const payload = context.objectAssign({}, state.gestureState, {
461 - defaultPrevented: false,
462 - type,
463 - });
464 - dispatchDiscreteEvent(context, payload, onAuxiliaryTap);
465 - }
466 -}
467 -
468 -/**
469 - * Responder implementation
470 - */
471 -
472 -const responderImpl = {
473 - targetEventTypes,
474 - getInitialState(): TapState {
475 - return createInitialState();
476 - },
477 - onEvent(
478 - event: ReactDOMResponderEvent,
479 - context: ReactDOMResponderContext,
480 - props: TapProps,
481 - state: TapState,
482 - ): void {
483 - if (props.disabled) {
484 - removeRootEventTypes(context, state);
485 - if (state.isActive) {
486 - state.isActive = false;
487 - dispatchCancel(context, props, state);
488 - }
489 - return;
490 - }
491 -
492 - const nativeEvent: any = event.nativeEvent;
493 - const eventTarget: Element = nativeEvent.target;
494 - const eventType = event.type;
495 -
496 - switch (eventType) {
497 - // START
498 - case 'pointerdown':
499 - case 'mousedown':
500 - case 'touchstart': {
501 - if (eventType === 'mousedown' && state.ignoreEmulatedEvents) {
502 - return;
503 - }
504 -
505 - if (!state.isActive) {
506 - if (hasPointerEvents) {
507 - const pointerId = nativeEvent.pointerId;
508 - state.activePointerId = pointerId;
509 - // Make mouse and touch pointers consistent.
510 - // Flow bug: https://github.com/facebook/flow/issues/8055
511 - // $FlowExpectedError
512 - eventTarget.releasePointerCapture(pointerId);
513 - } else {
514 - if (eventType === 'touchstart') {
515 - const targetTouches = nativeEvent.targetTouches;
516 - if (targetTouches.length === 1) {
517 - state.activePointerId = targetTouches[0].identifier;
518 - } else {
519 - return;
520 - }
521 - }
522 - }
523 -
524 - const activate = shouldActivate(event);
525 - const buttons =
526 - nativeEvent.button === 1
527 - ? buttonsEnum.auxiliary
528 - : nativeEvent.buttons;
529 - const activateAuxiliary = isAuxiliary(buttons, event);
530 -
531 - if (activate || activateAuxiliary) {
532 - state.buttons = buttons;
533 - state.pointerType = event.pointerType;
534 - state.responderTarget = context.getResponderNode();
535 - addRootEventTypes(rootEventTypes, context, state);
536 - if (!hasPointerEvents) {
537 - if (eventType === 'touchstart') {
538 - state.ignoreEmulatedEvents = true;
539 - }
540 - }
541 - }
542 -
543 - if (activateAuxiliary) {
544 - state.isAuxiliaryActive = true;
545 - } else if (activate) {
546 - const gestureState = createGestureState(
547 - context,
548 - props,
549 - state,
550 - event,
551 - );
552 - state.isActive = true;
553 - state.shouldPreventDefault = props.preventDefault !== false;
554 - state.gestureState = gestureState;
555 - state.initialPosition.x = gestureState.x;
556 - state.initialPosition.y = gestureState.y;
557 - dispatchStart(context, props, state);
558 - }
559 - } else if (
560 - !isActivePointer(event, state) ||
561 - (eventType === 'touchstart' && nativeEvent.targetTouches.length > 1)
562 - ) {
563 - // Cancel the gesture if a second pointer becomes active on the target.
564 - state.isActive = false;
565 - dispatchCancel(context, props, state);
566 - }
567 - break;
568 - }
569 - }
570 - },
571 - onRootEvent(
572 - event: ReactDOMResponderEvent,
573 - context: ReactDOMResponderContext,
574 - props: TapProps,
575 - state: TapState,
576 - ): void {
577 - const nativeEvent: any = event.nativeEvent;
578 - const eventType = event.type;
579 - const hitTarget = getHitTarget(event, context, state);
580 -
581 - switch (eventType) {
582 - // UPDATE
583 - case 'pointermove':
584 - case 'mousemove':
585 - case 'touchmove': {
586 - if (!hasPointerEvents) {
587 - if (eventType === 'mousemove' && state.ignoreEmulatedEvents) {
588 - return;
589 - }
590 - }
591 -
592 - if (state.isActive && isActivePointer(event, state)) {
593 - state.gestureState = createGestureState(context, props, state, event);
594 - let shouldUpdate = true;
595 -
596 - if (!context.isTargetWithinResponder(hitTarget)) {
597 - shouldUpdate = false;
598 - } else if (
599 - props.maximumDistance != null &&
600 - props.maximumDistance >= 10
601 - ) {
602 - const maxDistance = props.maximumDistance;
603 - const initialPosition = state.initialPosition;
604 - const currentPosition = state.gestureState;
605 - const moveX = initialPosition.x - currentPosition.x;
606 - const moveY = initialPosition.y - currentPosition.y;
607 - const moveDistance = Math.sqrt(moveX * moveX + moveY * moveY);
608 - if (moveDistance > maxDistance) {
609 - shouldUpdate = false;
610 - }
611 - }
612 -
613 - if (shouldUpdate) {
614 - dispatchUpdate(context, props, state);
615 - } else {
616 - state.isActive = false;
617 - dispatchCancel(context, props, state);
618 - }
619 - }
620 - break;
621 - }
622 -
623 - // END
624 - case 'pointerup':
625 - case 'mouseup':
626 - case 'touchend': {
627 - if (state.isActive && isActivePointer(event, state)) {
628 - state.gestureState = createGestureState(context, props, state, event);
629 - state.isActive = false;
630 - if (isAuxiliary(state.buttons, event)) {
631 - dispatchCancel(context, props, state);
632 - dispatchAuxiliaryTap(context, props, state);
633 - // Remove the root events here as no 'click' event is dispatched
634 - removeRootEventTypes(context, state);
635 - } else if (
636 - !context.isTargetWithinResponder(hitTarget) ||
637 - hasModifierKey(event)
638 - ) {
639 - dispatchCancel(context, props, state);
640 - } else {
641 - dispatchEnd(context, props, state);
642 - }
643 - } else if (
644 - state.isAuxiliaryActive &&
645 - isAuxiliary(state.buttons, event)
646 - ) {
647 - state.isAuxiliaryActive = false;
648 - state.gestureState = createGestureState(context, props, state, event);
649 - dispatchAuxiliaryTap(context, props, state);
650 - // Remove the root events here as no 'click' event is dispatched
651 - removeRootEventTypes(context, state);
652 - }
653 -
654 - if (!hasPointerEvents) {
655 - if (eventType === 'mouseup') {
656 - state.ignoreEmulatedEvents = false;
657 - }
658 - }
659 - break;
660 - }
661 -
662 - // CANCEL
663 - case 'contextmenu':
664 - case 'pointercancel':
665 - case 'touchcancel':
666 - case 'dragstart': {
667 - if (state.isActive && isActivePointer(event, state)) {
668 - state.gestureState = createGestureState(context, props, state, event);
669 - state.isActive = false;
670 - dispatchCancel(context, props, state);
671 - removeRootEventTypes(context, state);
672 - }
673 - break;
674 - }
675 -
676 - // CANCEL
677 - case 'scroll': {
678 - if (
679 - state.isActive &&
680 - state.responderTarget != null &&
681 - // We ignore incoming scroll events when using mouse events
682 - state.pointerType !== 'mouse' &&
683 - // If the scroll target is the document or if the pointer target
684 - // is within the 'scroll' target, then cancel the gesture
685 - context.isTargetWithinNode(state.responderTarget, nativeEvent.target)
686 - ) {
687 - state.gestureState = createGestureState(context, props, state, event);
688 - state.isActive = false;
689 - dispatchCancel(context, props, state);
690 - removeRootEventTypes(context, state);
691 - }
692 - break;
693 - }
694 -
695 - case 'click': {
696 - if (state.shouldPreventDefault) {
697 - nativeEvent.preventDefault();
698 - }
699 - removeRootEventTypes(context, state);
700 - break;
701 - }
702 - case 'blur': {
703 - // If we encounter a blur that happens on the pressed target
704 - // then disengage the blur.
705 - if (state.isActive && nativeEvent.target === state.responderTarget) {
706 - dispatchCancel(context, props, state);
707 - }
708 - }
709 - }
710 - },
711 - onUnmount(
712 - context: ReactDOMResponderContext,
713 - props: TapProps,
714 - state: TapState,
715 - ): void {
716 - removeRootEventTypes(context, state);
717 - if (state.isActive) {
718 - state.isActive = false;
719 - dispatchCancel(context, props, state);
720 - }
721 - },
722 -};
723 -
724 -// $FlowFixMe Can't add generic types without causing a parsing/syntax errors
725 -export const TapResponder = React.DEPRECATED_createResponder(
726 - 'Tap',
727 - responderImpl,
728 -);
729 -
730 -export function useTap(
731 - props: TapProps,
732 -): ?ReactEventResponderListener<any, any> {
733 - return React.DEPRECATED_useResponder(TapResponder, props);
734 -}
packages/react-interactions/events/src/dom/__tests__/ContextMenu-test.internal.js deleted
-204
@@ -1,204 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {
13 - buttonsType,
14 - createEventTarget,
15 - platform,
16 - setPointerEvent,
17 -} from 'dom-event-testing-library';
18 -
19 -let React;
20 -let ReactFeatureFlags;
21 -let ReactDOM;
22 -let useContextMenu;
23 -
24 -function initializeModules(hasPointerEvents) {
25 - setPointerEvent(hasPointerEvents);
26 - jest.resetModules();
27 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
28 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
29 - React = require('react');
30 - ReactDOM = require('react-dom');
31 -
32 - // TODO: This import throws outside of experimental mode. Figure out better
33 - // strategy for gated imports.
34 - if (__EXPERIMENTAL__) {
35 - useContextMenu = require('react-interactions/events/context-menu')
36 - .useContextMenu;
37 - }
38 -}
39 -
40 -const forcePointerEvents = true;
41 -const table = [[forcePointerEvents], [!forcePointerEvents]];
42 -
43 -describe.each(table)('ContextMenu responder', hasPointerEvents => {
44 - let container;
45 -
46 - beforeEach(() => {
47 - initializeModules(hasPointerEvents);
48 - container = document.createElement('div');
49 - document.body.appendChild(container);
50 - });
51 -
52 - afterEach(() => {
53 - ReactDOM.render(null, container);
54 - document.body.removeChild(container);
55 - container = null;
56 - });
57 -
58 - describe('all platforms', () => {
59 - // @gate experimental
60 - it('mouse right-click', () => {
61 - const onContextMenu = jest.fn();
62 - const preventDefault = jest.fn();
63 - const ref = React.createRef();
64 - const Component = () => {
65 - const listener = useContextMenu({onContextMenu});
66 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
67 - };
68 - ReactDOM.render(<Component />, container);
69 -
70 - const target = createEventTarget(ref.current);
71 - target.contextmenu({preventDefault});
72 - expect(preventDefault).toHaveBeenCalledTimes(1);
73 - expect(onContextMenu).toHaveBeenCalledTimes(1);
74 - expect(onContextMenu).toHaveBeenCalledWith(
75 - expect.objectContaining({
76 - buttons: buttonsType.secondary,
77 - pointerType: 'mouse',
78 - type: 'contextmenu',
79 - }),
80 - );
81 - });
82 -
83 - // @gate experimental
84 - it('touch long-press', () => {
85 - const onContextMenu = jest.fn();
86 - const preventDefault = jest.fn();
87 - const ref = React.createRef();
88 - const Component = () => {
89 - const listener = useContextMenu({onContextMenu});
90 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
91 - };
92 - ReactDOM.render(<Component />, container);
93 -
94 - const target = createEventTarget(ref.current);
95 - target.contextmenu({preventDefault}, {pointerType: 'touch'});
96 - expect(preventDefault).toHaveBeenCalledTimes(1);
97 - expect(onContextMenu).toHaveBeenCalledTimes(1);
98 - expect(onContextMenu).toHaveBeenCalledWith(
99 - expect.objectContaining({
100 - buttons: buttonsType.none,
101 - pointerType: 'touch',
102 - type: 'contextmenu',
103 - }),
104 - );
105 - });
106 -
107 - // @gate experimental
108 - it('"disabled" is true', () => {
109 - const onContextMenu = jest.fn();
110 - const ref = React.createRef();
111 - const Component = () => {
112 - const listener = useContextMenu({
113 - onContextMenu,
114 - disabled: true,
115 - });
116 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
117 - };
118 - ReactDOM.render(<Component />, container);
119 -
120 - const target = createEventTarget(ref.current);
121 - target.contextmenu();
122 - expect(onContextMenu).toHaveBeenCalledTimes(0);
123 - });
124 -
125 - // @gate experimental
126 - it('"preventDefault" is false', () => {
127 - const preventDefault = jest.fn();
128 - const onContextMenu = jest.fn();
129 - const ref = React.createRef();
130 - const Component = () => {
131 - const listener = useContextMenu({
132 - onContextMenu,
133 - preventDefault: false,
134 - });
135 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
136 - };
137 - ReactDOM.render(<Component />, container);
138 -
139 - const target = createEventTarget(ref.current);
140 - target.contextmenu({preventDefault});
141 - expect(preventDefault).toHaveBeenCalledTimes(0);
142 - expect(onContextMenu).toHaveBeenCalledTimes(1);
143 - });
144 - });
145 -
146 - describe('mac platform', () => {
147 - beforeEach(() => {
148 - platform.set('mac');
149 - jest.resetModules();
150 - });
151 -
152 - afterEach(() => {
153 - platform.clear();
154 - });
155 -
156 - // @gate experimental
157 - it('mouse modified left-click', () => {
158 - const onContextMenu = jest.fn();
159 - const ref = React.createRef();
160 - const Component = () => {
161 - const listener = useContextMenu({onContextMenu});
162 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
163 - };
164 - ReactDOM.render(<Component />, container);
165 -
166 - const target = createEventTarget(ref.current);
167 - target.contextmenu({}, {modified: true});
168 - expect(onContextMenu).toHaveBeenCalledTimes(1);
169 - expect(onContextMenu).toHaveBeenCalledWith(
170 - expect.objectContaining({
171 - buttons: buttonsType.primary,
172 - pointerType: 'mouse',
173 - type: 'contextmenu',
174 - }),
175 - );
176 - });
177 - });
178 -
179 - describe('windows platform', () => {
180 - beforeEach(() => {
181 - platform.set('windows');
182 - jest.resetModules();
183 - });
184 -
185 - afterEach(() => {
186 - platform.clear();
187 - });
188 -
189 - // @gate experimental
190 - it('mouse modified left-click', () => {
191 - const onContextMenu = jest.fn();
192 - const ref = React.createRef();
193 - const Component = () => {
194 - const listener = useContextMenu({onContextMenu});
195 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
196 - };
197 - ReactDOM.render(<Component />, container);
198 -
199 - const target = createEventTarget(ref.current);
200 - target.contextmenu({}, {modified: true});
201 - expect(onContextMenu).toHaveBeenCalledTimes(0);
202 - });
203 - });
204 -});
packages/react-interactions/events/src/dom/__tests__/Focus-test.internal.js deleted
-403
@@ -1,403 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {
13 - createEventTarget,
14 - setPointerEvent,
15 - platform,
16 -} from 'dom-event-testing-library';
17 -
18 -let React;
19 -let ReactFeatureFlags;
20 -let ReactDOM;
21 -let FocusResponder;
22 -let useFocus;
23 -
24 -function initializeModules(hasPointerEvents) {
25 - setPointerEvent(hasPointerEvents);
26 - jest.resetModules();
27 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
28 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
29 - React = require('react');
30 - ReactDOM = require('react-dom');
31 -
32 - // TODO: This import throws outside of experimental mode. Figure out better
33 - // strategy for gated imports.
34 - if (__EXPERIMENTAL__) {
35 - FocusResponder = require('react-interactions/events/deprecated-focus')
36 - .FocusResponder;
37 - useFocus = require('react-interactions/events/deprecated-focus').useFocus;
38 - }
39 -}
40 -
41 -const forcePointerEvents = true;
42 -const table = [[forcePointerEvents], [!forcePointerEvents]];
43 -
44 -describe.each(table)('Focus responder', hasPointerEvents => {
45 - let container;
46 -
47 - beforeEach(() => {
48 - initializeModules(hasPointerEvents);
49 - container = document.createElement('div');
50 - document.body.appendChild(container);
51 - });
52 -
53 - afterEach(() => {
54 - ReactDOM.render(null, container);
55 - document.body.removeChild(container);
56 - container = null;
57 - });
58 -
59 - describe('disabled', () => {
60 - let onBlur, onFocus, ref;
61 -
62 - const componentInit = () => {
63 - onBlur = jest.fn();
64 - onFocus = jest.fn();
65 - ref = React.createRef();
66 - const Component = () => {
67 - const listener = useFocus({
68 - disabled: true,
69 - onBlur,
70 - onFocus,
71 - });
72 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
73 - };
74 - ReactDOM.render(<Component />, container);
75 - };
76 -
77 - // @gate experimental
78 - it('does not call callbacks', () => {
79 - componentInit();
80 - const target = createEventTarget(ref.current);
81 - target.focus();
82 - target.blur();
83 - expect(onFocus).not.toBeCalled();
84 - expect(onBlur).not.toBeCalled();
85 - });
86 - });
87 -
88 - describe('onBlur', () => {
89 - let onBlur, ref;
90 -
91 - const componentInit = () => {
92 - onBlur = jest.fn();
93 - ref = React.createRef();
94 - const Component = () => {
95 - const listener = useFocus({
96 - onBlur,
97 - });
98 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
99 - };
100 - ReactDOM.render(<Component />, container);
101 - };
102 -
103 - // @gate experimental
104 - it('is called after "blur" event', () => {
105 - componentInit();
106 - const target = createEventTarget(ref.current);
107 - target.focus();
108 - target.blur();
109 - expect(onBlur).toHaveBeenCalledTimes(1);
110 - });
111 - });
112 -
113 - describe('onFocus', () => {
114 - let onFocus, ref, innerRef;
115 -
116 - const componentInit = () => {
117 - onFocus = jest.fn();
118 - ref = React.createRef();
119 - innerRef = React.createRef();
120 - const Component = () => {
121 - const listener = useFocus({
122 - onFocus,
123 - });
124 - return (
125 - <div ref={ref} DEPRECATED_flareListeners={listener}>
126 - <a ref={innerRef} />
127 - </div>
128 - );
129 - };
130 - ReactDOM.render(<Component />, container);
131 - };
132 -
133 - // @gate experimental
134 - it('is called after "focus" event', () => {
135 - componentInit();
136 - const target = createEventTarget(ref.current);
137 - target.focus();
138 - expect(onFocus).toHaveBeenCalledTimes(1);
139 - });
140 -
141 - // @gate experimental
142 - it('is not called if descendants of target receive focus', () => {
143 - componentInit();
144 - const target = createEventTarget(innerRef.current);
145 - target.focus();
146 - expect(onFocus).not.toBeCalled();
147 - });
148 -
149 - // @gate experimental
150 - it('is called with the correct pointerType: mouse', () => {
151 - componentInit();
152 - const target = createEventTarget(ref.current);
153 - target.pointerdown();
154 - target.pointerup();
155 - expect(onFocus).toHaveBeenCalledTimes(1);
156 - expect(onFocus).toHaveBeenCalledWith(
157 - expect.objectContaining({pointerType: 'mouse'}),
158 - );
159 - });
160 -
161 - // @gate experimental
162 - it('is called with the correct pointerType: touch', () => {
163 - componentInit();
164 - const target = createEventTarget(ref.current);
165 - const pointerType = 'touch';
166 - target.pointerdown({pointerType});
167 - target.pointerup({pointerType});
168 - expect(onFocus).toHaveBeenCalledTimes(1);
169 - expect(onFocus).toHaveBeenCalledWith(
170 - expect.objectContaining({pointerType: 'touch'}),
171 - );
172 - });
173 -
174 - if (hasPointerEvents) {
175 - // @gate experimental
176 - it('is called with the correct pointerType: pen', () => {
177 - componentInit();
178 - const target = createEventTarget(ref.current);
179 - const pointerType = 'pen';
180 - target.pointerdown({pointerType});
181 - target.pointerup({pointerType});
182 - expect(onFocus).toHaveBeenCalledTimes(1);
183 - expect(onFocus).toHaveBeenCalledWith(
184 - expect.objectContaining({pointerType: 'pen'}),
185 - );
186 - });
187 - }
188 -
189 - // @gate experimental
190 - it('is called with the correct pointerType using a keyboard', () => {
191 - componentInit();
192 - const target = createEventTarget(ref.current);
193 - target.keydown({key: 'LeftArrow'});
194 - target.focus();
195 - expect(onFocus).toHaveBeenCalledTimes(1);
196 - expect(onFocus).toHaveBeenCalledWith(
197 - expect.objectContaining({pointerType: 'keyboard'}),
198 - );
199 - });
200 -
201 - // @gate experimental
202 - it('is called with the correct pointerType using Tab+altKey on Mac', () => {
203 - platform.set('mac');
204 - jest.resetModules();
205 - initializeModules();
206 - componentInit();
207 -
208 - const target = createEventTarget(ref.current);
209 - target.keydown({key: 'Tab', altKey: true});
210 - target.focus();
211 -
212 - expect(onFocus).toHaveBeenCalledTimes(1);
213 - expect(onFocus).toHaveBeenCalledWith(
214 - expect.objectContaining({
215 - pointerType: 'keyboard',
216 - }),
217 - );
218 -
219 - platform.clear();
220 - });
221 - });
222 -
223 - describe('onFocusChange', () => {
224 - let onFocusChange, ref, innerRef;
225 -
226 - const componentInit = () => {
227 - onFocusChange = jest.fn();
228 - ref = React.createRef();
229 - innerRef = React.createRef();
230 - const Component = () => {
231 - const listener = useFocus({
232 - onFocusChange,
233 - });
234 - return (
235 - <div ref={ref} DEPRECATED_flareListeners={listener}>
236 - <div ref={innerRef} />
237 - </div>
238 - );
239 - };
240 - ReactDOM.render(<Component />, container);
241 - };
242 -
243 - // @gate experimental
244 - it('is called after "blur" and "focus" events', () => {
245 - componentInit();
246 - const target = createEventTarget(ref.current);
247 - target.focus();
248 - expect(onFocusChange).toHaveBeenCalledTimes(1);
249 - expect(onFocusChange).toHaveBeenCalledWith(true);
250 - target.blur();
251 - expect(onFocusChange).toHaveBeenCalledTimes(2);
252 - expect(onFocusChange).toHaveBeenCalledWith(false);
253 - });
254 -
255 - // @gate experimental
256 - it('is not called after "blur" and "focus" events on descendants', () => {
257 - componentInit();
258 - const target = createEventTarget(innerRef.current);
259 - target.focus();
260 - expect(onFocusChange).toHaveBeenCalledTimes(0);
261 - target.blur();
262 - expect(onFocusChange).toHaveBeenCalledTimes(0);
263 - });
264 - });
265 -
266 - describe('onFocusVisibleChange', () => {
267 - let onFocusVisibleChange, ref, innerRef;
268 -
269 - const componentInit = () => {
270 - onFocusVisibleChange = jest.fn();
271 - ref = React.createRef();
272 - innerRef = React.createRef();
273 - const Component = () => {
274 - const listener = useFocus({
275 - onFocusVisibleChange,
276 - });
277 - return (
278 - <div ref={ref} DEPRECATED_flareListeners={listener}>
279 - <div ref={innerRef} />
280 - </div>
281 - );
282 - };
283 - ReactDOM.render(<Component />, container);
284 - };
285 -
286 - // @gate experimental
287 - it('is called after "focus" and "blur" if keyboard navigation is active', () => {
288 - componentInit();
289 - const target = createEventTarget(ref.current);
290 - const containerTarget = createEventTarget(container);
291 - // use keyboard first
292 - containerTarget.keydown({key: 'Tab'});
293 - target.focus();
294 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(1);
295 - expect(onFocusVisibleChange).toHaveBeenCalledWith(true);
296 - target.blur({relatedTarget: container});
297 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(2);
298 - expect(onFocusVisibleChange).toHaveBeenCalledWith(false);
299 - });
300 -
301 - // @gate experimental
302 - it('is called if non-keyboard event is dispatched on target previously focused with keyboard', () => {
303 - componentInit();
304 - const target = createEventTarget(ref.current);
305 - const containerTarget = createEventTarget(container);
306 - // use keyboard first
307 - containerTarget.keydown({key: 'Tab'});
308 - target.focus();
309 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(1);
310 - expect(onFocusVisibleChange).toHaveBeenCalledWith(true);
311 - // then use pointer on the target, focus should no longer be visible
312 - target.pointerdown();
313 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(2);
314 - expect(onFocusVisibleChange).toHaveBeenCalledWith(false);
315 - // onFocusVisibleChange should not be called again
316 - target.blur({relatedTarget: container});
317 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(2);
318 - });
319 -
320 - // @gate experimental
321 - it('is not called after "focus" and "blur" events without keyboard', () => {
322 - componentInit();
323 - const target = createEventTarget(ref.current);
324 - const containerTarget = createEventTarget(container);
325 - target.pointerdown();
326 - target.pointerup();
327 - containerTarget.pointerdown();
328 - target.blur({relatedTarget: container});
329 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(0);
330 - });
331 -
332 - // @gate experimental
333 - it('is not called after "blur" and "focus" events on descendants', () => {
334 - componentInit();
335 - const innerTarget = createEventTarget(innerRef.current);
336 - const containerTarget = createEventTarget(container);
337 - containerTarget.keydown({key: 'Tab'});
338 - innerTarget.focus();
339 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(0);
340 - innerTarget.blur({relatedTarget: container});
341 - expect(onFocusVisibleChange).toHaveBeenCalledTimes(0);
342 - });
343 - });
344 -
345 - describe('nested Focus components', () => {
346 - // @gate experimental
347 - it('propagates events in the correct order', () => {
348 - const events = [];
349 - const innerRef = React.createRef();
350 - const outerRef = React.createRef();
351 - const createEventHandler = msg => () => {
352 - events.push(msg);
353 - };
354 -
355 - const Inner = () => {
356 - const listener = useFocus({
357 - onBlur: createEventHandler('inner: onBlur'),
358 - onFocus: createEventHandler('inner: onFocus'),
359 - onFocusChange: createEventHandler('inner: onFocusChange'),
360 - });
361 - return <div ref={innerRef} DEPRECATED_flareListeners={listener} />;
362 - };
363 -
364 - const Outer = () => {
365 - const listener = useFocus({
366 - onBlur: createEventHandler('outer: onBlur'),
367 - onFocus: createEventHandler('outer: onFocus'),
368 - onFocusChange: createEventHandler('outer: onFocusChange'),
369 - });
370 - return (
371 - <div ref={outerRef} DEPRECATED_flareListeners={listener}>
372 - <Inner />
373 - </div>
374 - );
375 - };
376 -
377 - ReactDOM.render(<Outer />, container);
378 -
379 - const innerTarget = createEventTarget(innerRef.current);
380 - const outerTarget = createEventTarget(outerRef.current);
381 -
382 - outerTarget.focus();
383 - outerTarget.blur();
384 - innerTarget.focus();
385 - innerTarget.blur();
386 - expect(events).toEqual([
387 - 'outer: onFocus',
388 - 'outer: onFocusChange',
389 - 'outer: onBlur',
390 - 'outer: onFocusChange',
391 - 'inner: onFocus',
392 - 'inner: onFocusChange',
393 - 'inner: onBlur',
394 - 'inner: onFocusChange',
395 - ]);
396 - });
397 - });
398 -
399 - // @gate experimental
400 - it('expect displayName to show up for event component', () => {
401 - expect(FocusResponder.displayName).toBe('Focus');
402 - });
403 -});
packages/react-interactions/events/src/dom/__tests__/FocusWithin-test.internal.js deleted
-574
@@ -1,574 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {createEventTarget, setPointerEvent} from 'dom-event-testing-library';
13 -
14 -let React;
15 -let ReactFeatureFlags;
16 -let ReactDOM;
17 -let FocusWithinResponder;
18 -let useFocusWithin;
19 -let ReactTestRenderer;
20 -let act;
21 -
22 -const initializeModules = hasPointerEvents => {
23 - setPointerEvent(hasPointerEvents);
24 - jest.resetModules();
25 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
26 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
27 - ReactFeatureFlags.enableScopeAPI = true;
28 - React = require('react');
29 - ReactDOM = require('react-dom');
30 - ReactTestRenderer = require('react-test-renderer');
31 - act = ReactTestRenderer.act;
32 -
33 - // TODO: This import throws outside of experimental mode. Figure out better
34 - // strategy for gated imports.
35 - if (__EXPERIMENTAL__) {
36 - FocusWithinResponder = require('react-interactions/events/deprecated-focus')
37 - .FocusWithinResponder;
38 - useFocusWithin = require('react-interactions/events/deprecated-focus')
39 - .useFocusWithin;
40 - }
41 -};
42 -
43 -const forcePointerEvents = true;
44 -const table = [[forcePointerEvents], [!forcePointerEvents]];
45 -
46 -describe.each(table)('FocusWithin responder', hasPointerEvents => {
47 - let container;
48 - let container2;
49 -
50 - beforeEach(() => {
51 - initializeModules();
52 - container = document.createElement('div');
53 - document.body.appendChild(container);
54 - container2 = document.createElement('div');
55 - document.body.appendChild(container2);
56 - });
57 -
58 - afterEach(() => {
59 - ReactDOM.render(null, container);
60 - document.body.removeChild(container);
61 - document.body.removeChild(container2);
62 - container = null;
63 - container2 = null;
64 - });
65 -
66 - describe('disabled', () => {
67 - let onFocusWithinChange, onFocusWithinVisibleChange, ref;
68 -
69 - const componentInit = () => {
70 - onFocusWithinChange = jest.fn();
71 - onFocusWithinVisibleChange = jest.fn();
72 - ref = React.createRef();
73 - const Component = () => {
74 - const listener = useFocusWithin({
75 - disabled: true,
76 - onFocusWithinChange,
77 - onFocusWithinVisibleChange,
78 - });
79 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
80 - };
81 - ReactDOM.render(<Component />, container);
82 - };
83 -
84 - // @gate experimental
85 - it('prevents custom events being dispatched', () => {
86 - componentInit();
87 - const target = createEventTarget(ref.current);
88 - target.focus();
89 - target.blur();
90 - expect(onFocusWithinChange).not.toBeCalled();
91 - expect(onFocusWithinVisibleChange).not.toBeCalled();
92 - });
93 - });
94 -
95 - describe('onFocusWithinChange', () => {
96 - let onFocusWithinChange, ref, innerRef, innerRef2;
97 -
98 - const Component = ({show}) => {
99 - const listener = useFocusWithin({
100 - onFocusWithinChange,
101 - });
102 - return (
103 - <div ref={ref} DEPRECATED_flareListeners={listener}>
104 - {show && <input ref={innerRef} />}
105 - <div ref={innerRef2} />
106 - </div>
107 - );
108 - };
109 -
110 - const componentInit = () => {
111 - onFocusWithinChange = jest.fn();
112 - ref = React.createRef();
113 - innerRef = React.createRef();
114 - innerRef2 = React.createRef();
115 - ReactDOM.render(<Component show={true} />, container);
116 - };
117 -
118 - // @gate experimental
119 - it('is called after "blur" and "focus" events on focus target', () => {
120 - componentInit();
121 - const target = createEventTarget(ref.current);
122 - target.focus();
123 - expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
124 - expect(onFocusWithinChange).toHaveBeenCalledWith(true);
125 - target.blur({relatedTarget: container});
126 - expect(onFocusWithinChange).toHaveBeenCalledTimes(2);
127 - expect(onFocusWithinChange).toHaveBeenCalledWith(false);
128 - });
129 -
130 - // @gate experimental
131 - it('is called after "blur" and "focus" events on descendants', () => {
132 - componentInit();
133 - const target = createEventTarget(innerRef.current);
134 - target.focus();
135 - expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
136 - expect(onFocusWithinChange).toHaveBeenCalledWith(true);
137 - target.blur({relatedTarget: container});
138 - expect(onFocusWithinChange).toHaveBeenCalledTimes(2);
139 - expect(onFocusWithinChange).toHaveBeenCalledWith(false);
140 - });
141 -
142 - // @gate experimental
143 - it('is only called once when focus moves within and outside the subtree', () => {
144 - componentInit();
145 - const node = ref.current;
146 - const innerNode1 = innerRef.current;
147 - const innerNode2 = innerRef.current;
148 - const target = createEventTarget(node);
149 - const innerTarget1 = createEventTarget(innerNode1);
150 - const innerTarget2 = createEventTarget(innerNode2);
151 -
152 - // focus shifts into subtree
153 - innerTarget1.focus();
154 - expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
155 - expect(onFocusWithinChange).toHaveBeenCalledWith(true);
156 - // focus moves around subtree
157 - innerTarget1.blur({relatedTarget: innerNode2});
158 - innerTarget2.focus();
159 - innerTarget2.blur({relatedTarget: node});
160 - target.focus();
161 - target.blur({relatedTarget: innerNode1});
162 - expect(onFocusWithinChange).toHaveBeenCalledTimes(1);
163 - // focus shifts outside subtree
164 - innerTarget1.blur({relatedTarget: container});
165 - expect(onFocusWithinChange).toHaveBeenCalledTimes(2);
166 - expect(onFocusWithinChange).toHaveBeenCalledWith(false);
167 - });
168 - });
169 -
170 - describe('onFocusWithinVisibleChange', () => {
171 - let onFocusWithinVisibleChange, ref, innerRef, innerRef2;
172 -
173 - const Component = ({show}) => {
174 - const listener = useFocusWithin({
175 - onFocusWithinVisibleChange,
176 - });
177 - return (
178 - <div ref={ref} DEPRECATED_flareListeners={listener}>
179 - {show && <input ref={innerRef} />}
180 - <div ref={innerRef2} />
181 - </div>
182 - );
183 - };
184 -
185 - const componentInit = () => {
186 - onFocusWithinVisibleChange = jest.fn();
187 - ref = React.createRef();
188 - innerRef = React.createRef();
189 - innerRef2 = React.createRef();
190 - ReactDOM.render(<Component show={true} />, container);
191 - };
192 -
193 - // @gate experimental
194 - it('is called after "focus" and "blur" on focus target if keyboard was used', () => {
195 - componentInit();
196 - const target = createEventTarget(ref.current);
197 - const containerTarget = createEventTarget(container);
198 - // use keyboard first
199 - containerTarget.keydown({key: 'Tab'});
200 - target.focus();
201 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
202 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
203 - target.blur({relatedTarget: container});
204 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
205 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
206 - });
207 -
208 - // @gate experimental
209 - it('is called after "focus" and "blur" on descendants if keyboard was used', () => {
210 - componentInit();
211 - const innerTarget = createEventTarget(innerRef.current);
212 - const containerTarget = createEventTarget(container);
213 - // use keyboard first
214 - containerTarget.keydown({key: 'Tab'});
215 - innerTarget.focus();
216 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
217 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
218 - innerTarget.blur({relatedTarget: container});
219 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
220 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
221 - });
222 -
223 - // @gate experimental
224 - it('is called if non-keyboard event is dispatched on target previously focused with keyboard', () => {
225 - componentInit();
226 - const node = ref.current;
227 - const innerNode1 = innerRef.current;
228 - const innerNode2 = innerRef2.current;
229 -
230 - const target = createEventTarget(node);
231 - const innerTarget1 = createEventTarget(innerNode1);
232 - const innerTarget2 = createEventTarget(innerNode2);
233 - // use keyboard first
234 - target.focus();
235 - target.keydown({key: 'Tab'});
236 - target.blur({relatedTarget: innerNode1});
237 - innerTarget1.focus();
238 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
239 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
240 - // then use pointer on the next target, focus should no longer be visible
241 - innerTarget2.pointerdown();
242 - innerTarget1.blur({relatedTarget: innerNode2});
243 - innerTarget2.focus();
244 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
245 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
246 - // then use keyboard again
247 - innerTarget2.keydown({key: 'Tab', shiftKey: true});
248 - innerTarget2.blur({relatedTarget: innerNode1});
249 - innerTarget1.focus();
250 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(3);
251 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
252 - // then use pointer on the target, focus should no longer be visible
253 - innerTarget1.pointerdown();
254 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(4);
255 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
256 - // onFocusVisibleChange should not be called again
257 - innerTarget1.blur({relatedTarget: container});
258 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(4);
259 - });
260 -
261 - // @gate experimental
262 - it('is not called after "focus" and "blur" events without keyboard', () => {
263 - componentInit();
264 - const innerTarget = createEventTarget(innerRef.current);
265 - innerTarget.pointerdown();
266 - innerTarget.pointerup();
267 - innerTarget.blur({relatedTarget: container});
268 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(0);
269 - });
270 -
271 - // @gate experimental
272 - it('is only called once when focus moves within and outside the subtree', () => {
273 - componentInit();
274 - const node = ref.current;
275 - const innerNode1 = innerRef.current;
276 - const innerNode2 = innerRef2.current;
277 - const target = createEventTarget(node);
278 - const innerTarget1 = createEventTarget(innerNode1);
279 - const innerTarget2 = createEventTarget(innerNode2);
280 -
281 - // focus shifts into subtree
282 - innerTarget1.focus();
283 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
284 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(true);
285 - // focus moves around subtree
286 - innerTarget1.blur({relatedTarget: innerNode2});
287 - innerTarget2.focus();
288 - innerTarget2.blur({relatedTarget: node});
289 - target.focus();
290 - target.blur({relatedTarget: innerNode1});
291 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(1);
292 - // focus shifts outside subtree
293 - innerTarget1.blur({relatedTarget: container});
294 - expect(onFocusWithinVisibleChange).toHaveBeenCalledTimes(2);
295 - expect(onFocusWithinVisibleChange).toHaveBeenCalledWith(false);
296 - });
297 - });
298 -
299 - describe('onBeforeBlurWithin', () => {
300 - let onBeforeBlurWithin, onAfterBlurWithin, ref, innerRef, innerRef2;
301 -
302 - beforeEach(() => {
303 - onBeforeBlurWithin = jest.fn();
304 - onAfterBlurWithin = jest.fn();
305 - ref = React.createRef();
306 - innerRef = React.createRef();
307 - innerRef2 = React.createRef();
308 - });
309 -
310 - // @gate experimental
311 - it('is called after a focused element is unmounted', () => {
312 - const Component = ({show}) => {
313 - const listener = useFocusWithin({
314 - onBeforeBlurWithin,
315 - onAfterBlurWithin,
316 - });
317 - return (
318 - <div ref={ref} DEPRECATED_flareListeners={listener}>
319 - {show && <input ref={innerRef} />}
320 - <div ref={innerRef2} />
321 - </div>
322 - );
323 - };
324 -
325 - ReactDOM.render(<Component show={true} />, container);
326 -
327 - const inner = innerRef.current;
328 - const target = createEventTarget(inner);
329 - target.keydown({key: 'Tab'});
330 - target.focus();
331 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
332 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
333 - ReactDOM.render(<Component show={false} />, container);
334 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
335 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
336 - expect(onAfterBlurWithin).toHaveBeenCalledWith(
337 - expect.objectContaining({relatedTarget: inner}),
338 - );
339 - });
340 -
341 - // @gate experimental
342 - it('is called after a nested focused element is unmounted', () => {
343 - const Component = ({show}) => {
344 - const listener = useFocusWithin({
345 - onBeforeBlurWithin,
346 - onAfterBlurWithin,
347 - });
348 - return (
349 - <div ref={ref} DEPRECATED_flareListeners={listener}>
350 - {show && (
351 - <div>
352 - <input ref={innerRef} />
353 - </div>
354 - )}
355 - <div ref={innerRef2} />
356 - </div>
357 - );
358 - };
359 -
360 - ReactDOM.render(<Component show={true} />, container);
361 -
362 - const inner = innerRef.current;
363 - const target = createEventTarget(inner);
364 - target.keydown({key: 'Tab'});
365 - target.focus();
366 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
367 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
368 - ReactDOM.render(<Component show={false} />, container);
369 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
370 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
371 - expect(onAfterBlurWithin).toHaveBeenCalledWith(
372 - expect.objectContaining({relatedTarget: inner}),
373 - );
374 - });
375 -
376 - // @gate experimental
377 - it('is called after many elements are unmounted', () => {
378 - const buttonRef = React.createRef();
379 - const inputRef = React.createRef();
380 -
381 - const Component = ({show}) => {
382 - const listener = useFocusWithin({
383 - onBeforeBlurWithin,
384 - onAfterBlurWithin,
385 - });
386 - return (
387 - <div ref={ref} DEPRECATED_flareListeners={listener}>
388 - {show && <button>Press me!</button>}
389 - {show && <button>Press me!</button>}
390 - {show && <input ref={inputRef} />}
391 - {show && <button>Press me!</button>}
392 - {!show && <button ref={buttonRef}>Press me!</button>}
393 - {show && <button>Press me!</button>}
394 - <button>Press me!</button>
395 - <button>Press me!</button>
396 - </div>
397 - );
398 - };
399 -
400 - ReactDOM.render(<Component show={true} />, container);
401 -
402 - inputRef.current.focus();
403 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
404 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
405 - ReactDOM.render(<Component show={false} />, container);
406 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
407 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
408 - });
409 -
410 - // @gate experimental
411 - it('is called after a nested focused element is unmounted (with scope query)', () => {
412 - const TestScope = React.unstable_Scope;
413 - const testScopeQuery = (type, props) => true;
414 - let targetNodes;
415 - let targetNode;
416 -
417 - const Component = ({show}) => {
418 - const scopeRef = React.useRef(null);
419 - const listener = useFocusWithin({
420 - onBeforeBlurWithin(event) {
421 - const scope = scopeRef.current;
422 - targetNode = innerRef.current;
423 - targetNodes = scope.DO_NOT_USE_queryAllNodes(testScopeQuery);
424 - },
425 - });
426 -
427 - return (
428 - <TestScope ref={scopeRef} DEPRECATED_flareListeners={[listener]}>
429 - {show && <input ref={innerRef} />}
430 - </TestScope>
431 - );
432 - };
433 -
434 - ReactDOM.render(<Component show={true} />, container);
435 -
436 - const inner = innerRef.current;
437 - const target = createEventTarget(inner);
438 - target.keydown({key: 'Tab'});
439 - target.focus();
440 - ReactDOM.render(<Component show={false} />, container);
441 - expect(targetNodes).toEqual([targetNode]);
442 - });
443 -
444 - // @gate experimental
445 - it('is called after a focused suspended element is hidden', () => {
446 - const Suspense = React.Suspense;
447 - let suspend = false;
448 - let resolve;
449 - const promise = new Promise(resolvePromise => (resolve = resolvePromise));
450 -
451 - function Child() {
452 - if (suspend) {
453 - throw promise;
454 - } else {
455 - return <input ref={innerRef} />;
456 - }
457 - }
458 -
459 - const Component = ({show}) => {
460 - const listener = useFocusWithin({
461 - onBeforeBlurWithin,
462 - onAfterBlurWithin,
463 - });
464 -
465 - return (
466 - <div DEPRECATED_flareListeners={listener}>
467 - <Suspense fallback="Loading...">
468 - <Child />
469 - </Suspense>
470 - </div>
471 - );
472 - };
473 -
474 - const root = ReactDOM.createRoot(container2);
475 - act(() => {
476 - root.render(<Component />);
477 - });
478 - jest.runAllTimers();
479 - expect(container2.innerHTML).toBe('<div><input></div>');
480 -
481 - const inner = innerRef.current;
482 - const target = createEventTarget(inner);
483 - target.keydown({key: 'Tab'});
484 - target.focus();
485 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
486 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
487 -
488 - suspend = true;
489 - act(() => {
490 - root.render(<Component />);
491 - });
492 - jest.runAllTimers();
493 - expect(container2.innerHTML).toBe(
494 - '<div><input style="display: none;">Loading...</div>',
495 - );
496 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
497 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
498 - resolve();
499 - });
500 -
501 - // @gate experimental
502 - it('is called after a focused suspended element is hidden then shown', () => {
503 - const Suspense = React.Suspense;
504 - let suspend = false;
505 - let resolve;
506 - const promise = new Promise(resolvePromise => (resolve = resolvePromise));
507 - const buttonRef = React.createRef();
508 -
509 - function Child() {
510 - if (suspend) {
511 - throw promise;
512 - } else {
513 - return <input ref={innerRef} />;
514 - }
515 - }
516 -
517 - const Component = ({show}) => {
518 - const listener = useFocusWithin({
519 - onBeforeBlurWithin,
520 - onAfterBlurWithin,
521 - });
522 -
523 - return (
524 - <div ref={ref} DEPRECATED_flareListeners={listener}>
525 - <Suspense fallback={<button ref={buttonRef}>Loading...</button>}>
526 - <Child />
527 - </Suspense>
528 - </div>
529 - );
530 - };
531 -
532 - const root = ReactDOM.createRoot(container2);
533 -
534 - act(() => {
535 - root.render(<Component />);
536 - });
537 - jest.runAllTimers();
538 -
539 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
540 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
541 -
542 - suspend = true;
543 - act(() => {
544 - root.render(<Component />);
545 - });
546 - jest.runAllTimers();
547 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
548 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
549 -
550 - act(() => {
551 - root.render(<Component />);
552 - });
553 - jest.runAllTimers();
554 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0);
555 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(0);
556 -
557 - buttonRef.current.focus();
558 - suspend = false;
559 - act(() => {
560 - root.render(<Component />);
561 - });
562 - jest.runAllTimers();
563 - expect(onBeforeBlurWithin).toHaveBeenCalledTimes(1);
564 - expect(onAfterBlurWithin).toHaveBeenCalledTimes(1);
565 -
566 - resolve();
567 - });
568 - });
569 -
570 - // @gate experimental
571 - it('expect displayName to show up for event component', () => {
572 - expect(FocusWithinResponder.displayName).toBe('FocusWithin');
573 - });
574 -});
packages/react-interactions/events/src/dom/__tests__/Hover-test.internal.js deleted
-430
@@ -1,430 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {createEventTarget, setPointerEvent} from 'dom-event-testing-library';
13 -
14 -let React;
15 -let ReactFeatureFlags;
16 -let ReactDOM;
17 -let HoverResponder;
18 -let useHover;
19 -
20 -function initializeModules(hasPointerEvents) {
21 - jest.resetModules();
22 - setPointerEvent(hasPointerEvents);
23 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
24 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
25 - React = require('react');
26 - ReactDOM = require('react-dom');
27 -
28 - // TODO: This import throws outside of experimental mode. Figure out better
29 - // strategy for gated imports.
30 - if (__EXPERIMENTAL__) {
31 - HoverResponder = require('react-interactions/events/hover').HoverResponder;
32 - useHover = require('react-interactions/events/hover').useHover;
33 - }
34 -}
35 -
36 -const forcePointerEvents = true;
37 -const table = [[forcePointerEvents], [!forcePointerEvents]];
38 -
39 -describe.each(table)('Hover responder', hasPointerEvents => {
40 - let container;
41 -
42 - beforeEach(() => {
43 - initializeModules(hasPointerEvents);
44 - container = document.createElement('div');
45 - document.body.appendChild(container);
46 - });
47 -
48 - afterEach(() => {
49 - ReactDOM.render(null, container);
50 - document.body.removeChild(container);
51 - container = null;
52 - });
53 -
54 - describe('disabled', () => {
55 - let onHoverChange, onHoverStart, onHoverMove, onHoverEnd, ref;
56 -
57 - const componentInit = () => {
58 - onHoverChange = jest.fn();
59 - onHoverStart = jest.fn();
60 - onHoverMove = jest.fn();
61 - onHoverEnd = jest.fn();
62 - ref = React.createRef();
63 - const Component = () => {
64 - const listener = useHover({
65 - disabled: true,
66 - onHoverChange,
67 - onHoverStart,
68 - onHoverMove,
69 - onHoverEnd,
70 - });
71 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
72 - };
73 - ReactDOM.render(<Component />, container);
74 - };
75 -
76 - // @gate experimental
77 - it('does not call callbacks', () => {
78 - componentInit();
79 - const target = createEventTarget(ref.current);
80 - target.pointerenter();
81 - target.pointerexit();
82 - expect(onHoverChange).not.toBeCalled();
83 - expect(onHoverStart).not.toBeCalled();
84 - expect(onHoverMove).not.toBeCalled();
85 - expect(onHoverEnd).not.toBeCalled();
86 - });
87 - });
88 -
89 - describe('onHoverStart', () => {
90 - let onHoverStart, ref;
91 -
92 - const componentInit = () => {
93 - onHoverStart = jest.fn();
94 - ref = React.createRef();
95 - const Component = () => {
96 - const listener = useHover({
97 - onHoverStart: onHoverStart,
98 - });
99 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
100 - };
101 - ReactDOM.render(<Component />, container);
102 - };
103 -
104 - // @gate experimental
105 - it('is called for mouse pointers', () => {
106 - componentInit();
107 - const target = createEventTarget(ref.current);
108 - target.pointerenter();
109 - expect(onHoverStart).toHaveBeenCalledTimes(1);
110 - });
111 -
112 - // @gate experimental
113 - it('is not called for touch pointers', () => {
114 - componentInit();
115 - const target = createEventTarget(ref.current);
116 - target.pointerdown({pointerType: 'touch'});
117 - target.pointerup({pointerType: 'touch'});
118 - expect(onHoverStart).not.toBeCalled();
119 - });
120 -
121 - // @gate experimental
122 - it('is called if a mouse pointer is used after a touch pointer', () => {
123 - componentInit();
124 - const target = createEventTarget(ref.current);
125 - target.pointerdown({pointerType: 'touch'});
126 - target.pointerup({pointerType: 'touch'});
127 - target.pointerenter();
128 - expect(onHoverStart).toHaveBeenCalledTimes(1);
129 - });
130 - });
131 -
132 - describe('onHoverChange', () => {
133 - let onHoverChange, ref;
134 -
135 - const componentInit = () => {
136 - onHoverChange = jest.fn();
137 - ref = React.createRef();
138 - const Component = () => {
139 - const listener = useHover({
140 - onHoverChange,
141 - });
142 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
143 - };
144 - ReactDOM.render(<Component />, container);
145 - };
146 -
147 - // @gate experimental
148 - it('is called for mouse pointers', () => {
149 - componentInit();
150 - const target = createEventTarget(ref.current);
151 - target.pointerenter();
152 - expect(onHoverChange).toHaveBeenCalledTimes(1);
153 - expect(onHoverChange).toHaveBeenCalledWith(true);
154 - target.pointerexit();
155 - expect(onHoverChange).toHaveBeenCalledTimes(2);
156 - expect(onHoverChange).toHaveBeenCalledWith(false);
157 - });
158 -
159 - // @gate experimental
160 - it('is not called for touch pointers', () => {
161 - componentInit();
162 - const target = createEventTarget(ref.current);
163 - target.pointerdown({pointerType: 'touch'});
164 - target.pointerup({pointerType: 'touch'});
165 - expect(onHoverChange).not.toBeCalled();
166 - });
167 - });
168 -
169 - describe('onHoverEnd', () => {
170 - let onHoverEnd, ref;
171 -
172 - const componentInit = () => {
173 - onHoverEnd = jest.fn();
174 - ref = React.createRef();
175 - const Component = () => {
176 - const listener = useHover({
177 - onHoverEnd,
178 - });
179 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
180 - };
181 - ReactDOM.render(<Component />, container);
182 - };
183 -
184 - // @gate experimental
185 - it('is called for mouse pointers', () => {
186 - componentInit();
187 - const target = createEventTarget(ref.current);
188 - target.pointerenter();
189 - target.pointerexit();
190 - expect(onHoverEnd).toHaveBeenCalledTimes(1);
191 - });
192 -
193 - if (hasPointerEvents) {
194 - // @gate experimental
195 - it('is called once for cancelled mouse pointers', () => {
196 - componentInit();
197 - const target = createEventTarget(ref.current);
198 - target.pointerenter();
199 - target.pointercancel();
200 - expect(onHoverEnd).toHaveBeenCalledTimes(1);
201 -
202 - // only called once if cancel follows exit
203 - onHoverEnd.mockReset();
204 - target.pointerenter();
205 - target.pointerexit();
206 - target.pointercancel();
207 - expect(onHoverEnd).toHaveBeenCalledTimes(1);
208 - });
209 - }
210 -
211 - // @gate experimental
212 - it('is not called for touch pointers', () => {
213 - componentInit();
214 - const target = createEventTarget(ref.current);
215 - target.pointerdown({pointerType: 'touch'});
216 - target.pointerup({pointerType: 'touch'});
217 - expect(onHoverEnd).not.toBeCalled();
218 - });
219 -
220 - // @gate experimental
221 - it('should correctly work with React Portals', () => {
222 - componentInit();
223 - const portalNode = document.createElement('div');
224 - const divRef = React.createRef();
225 - const spanRef = React.createRef();
226 -
227 - function Test() {
228 - const listener = useHover({
229 - onHoverEnd,
230 - });
231 - return (
232 - <div ref={divRef} DEPRECATED_flareListeners={listener}>
233 - {ReactDOM.createPortal(<span ref={spanRef} />, portalNode)}
234 - </div>
235 - );
236 - }
237 - ReactDOM.render(<Test />, container);
238 - const div = createEventTarget(divRef.current);
239 - div.pointerenter();
240 - const span = createEventTarget(spanRef.current);
241 - span.pointerexit();
242 - expect(onHoverEnd).not.toBeCalled();
243 - const body = createEventTarget(document.body);
244 - body.pointerexit();
245 - expect(onHoverEnd).toBeCalled();
246 - });
247 - });
248 -
249 - describe('onHoverMove', () => {
250 - // @gate experimental
251 - it('is called after the active pointer moves"', () => {
252 - const onHoverMove = jest.fn();
253 - const ref = React.createRef();
254 - const Component = () => {
255 - const listener = useHover({
256 - onHoverMove,
257 - });
258 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
259 - };
260 - ReactDOM.render(<Component />, container);
261 -
262 - const target = createEventTarget(ref.current);
263 - target.pointerenter();
264 - target.pointerhover({x: 0, y: 0});
265 - target.pointerhover({x: 1, y: 1});
266 - expect(onHoverMove).toHaveBeenCalledTimes(2);
267 - expect(onHoverMove).toHaveBeenCalledWith(
268 - expect.objectContaining({type: 'hovermove'}),
269 - );
270 - });
271 - });
272 -
273 - describe('nested Hover components', () => {
274 - // @gate experimental
275 - it('not propagate by default', () => {
276 - const events = [];
277 - const innerRef = React.createRef();
278 - const outerRef = React.createRef();
279 - const createEventHandler = msg => () => {
280 - events.push(msg);
281 - };
282 -
283 - const Inner = () => {
284 - const listener = useHover({
285 - onHoverStart: createEventHandler('inner: onHoverStart'),
286 - onHoverEnd: createEventHandler('inner: onHoverEnd'),
287 - onHoverChange: createEventHandler('inner: onHoverChange'),
288 - });
289 - return <div ref={innerRef} DEPRECATED_flareListeners={listener} />;
290 - };
291 -
292 - const Outer = () => {
293 - const listener = useHover({
294 - onHoverStart: createEventHandler('outer: onHoverStart'),
295 - onHoverEnd: createEventHandler('outer: onHoverEnd'),
296 - onHoverChange: createEventHandler('outer: onHoverChange'),
297 - });
298 - return (
299 - <div ref={outerRef} DEPRECATED_flareListeners={listener}>
300 - <Inner />
301 - </div>
302 - );
303 - };
304 - ReactDOM.render(<Outer />, container);
305 -
306 - const innerNode = innerRef.current;
307 - const outerNode = outerRef.current;
308 - const innerTarget = createEventTarget(innerNode);
309 - const outerTarget = createEventTarget(outerNode);
310 -
311 - outerTarget.pointerenter({relatedTarget: container});
312 - outerTarget.pointerexit({relatedTarget: innerNode});
313 - innerTarget.pointerenter({relatedTarget: outerNode});
314 - innerTarget.pointerexit({relatedTarget: outerNode});
315 - outerTarget.pointerenter({relatedTarget: innerNode});
316 - outerTarget.pointerexit({relatedTarget: container});
317 -
318 - expect(events).toEqual([
319 - 'outer: onHoverStart',
320 - 'outer: onHoverChange',
321 - 'outer: onHoverEnd',
322 - 'outer: onHoverChange',
323 - 'inner: onHoverStart',
324 - 'inner: onHoverChange',
325 - 'inner: onHoverEnd',
326 - 'inner: onHoverChange',
327 - 'outer: onHoverStart',
328 - 'outer: onHoverChange',
329 - 'outer: onHoverEnd',
330 - 'outer: onHoverChange',
331 - ]);
332 - });
333 - });
334 -
335 - // @gate experimental
336 - it('expect displayName to show up for event component', () => {
337 - expect(HoverResponder.displayName).toBe('Hover');
338 - });
339 -
340 - // @gate experimental
341 - it('should correctly pass through event properties', () => {
342 - const timeStamps = [];
343 - const ref = React.createRef();
344 - const eventLog = [];
345 - const logEvent = event => {
346 - const propertiesWeCareAbout = {
347 - x: event.x,
348 - y: event.y,
349 - pageX: event.pageX,
350 - pageY: event.pageY,
351 - clientX: event.clientX,
352 - clientY: event.clientY,
353 - pointerType: event.pointerType,
354 - target: event.target,
355 - timeStamp: event.timeStamp,
356 - type: event.type,
357 - };
358 - timeStamps.push(event.timeStamp);
359 - eventLog.push(propertiesWeCareAbout);
360 - };
361 - const Component = () => {
362 - const listener = useHover({
363 - onHoverStart: logEvent,
364 - onHoverEnd: logEvent,
365 - onHoverMove: logEvent,
366 - });
367 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
368 - };
369 - ReactDOM.render(<Component />, container);
370 -
371 - const node = ref.current;
372 - const target = createEventTarget(node);
373 -
374 - target.pointerenter({x: 10, y: 10});
375 - target.pointerhover({x: 10, y: 10});
376 - target.pointerhover({x: 20, y: 20});
377 - target.pointerexit({x: 20, y: 20});
378 -
379 - expect(eventLog).toEqual([
380 - {
381 - x: 10,
382 - y: 10,
383 - pageX: 10,
384 - pageY: 10,
385 - clientX: 10,
386 - clientY: 10,
387 - target: node,
388 - timeStamp: timeStamps[0],
389 - type: 'hoverstart',
390 - pointerType: 'mouse',
391 - },
392 - {
393 - x: 10,
394 - y: 10,
395 - pageX: 10,
396 - pageY: 10,
397 - clientX: 10,
398 - clientY: 10,
399 - target: node,
400 - timeStamp: timeStamps[1],
401 - type: 'hovermove',
402 - pointerType: 'mouse',
403 - },
404 - {
405 - x: 20,
406 - y: 20,
407 - pageX: 20,
408 - pageY: 20,
409 - clientX: 20,
410 - clientY: 20,
411 - target: node,
412 - timeStamp: timeStamps[2],
413 - type: 'hovermove',
414 - pointerType: 'mouse',
415 - },
416 - {
417 - x: 20,
418 - y: 20,
419 - pageX: 20,
420 - pageY: 20,
421 - clientX: 20,
422 - clientY: 20,
423 - target: node,
424 - timeStamp: timeStamps[3],
425 - type: 'hoverend',
426 - pointerType: 'mouse',
427 - },
428 - ]);
429 - });
430 -});
packages/react-interactions/events/src/dom/__tests__/Input-test.internal.js deleted
-1001
@@ -1,1001 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -let React;
13 -let ReactFeatureFlags;
14 -let ReactDOM;
15 -let InputResponder;
16 -let useInput;
17 -let Scheduler;
18 -
19 -const setUntrackedChecked = Object.getOwnPropertyDescriptor(
20 - HTMLInputElement.prototype,
21 - 'checked',
22 -).set;
23 -
24 -const setUntrackedValue = Object.getOwnPropertyDescriptor(
25 - HTMLInputElement.prototype,
26 - 'value',
27 -).set;
28 -
29 -const setUntrackedTextareaValue = Object.getOwnPropertyDescriptor(
30 - HTMLTextAreaElement.prototype,
31 - 'value',
32 -).set;
33 -
34 -const modulesInit = () => {
35 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
36 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
37 -
38 - React = require('react');
39 - ReactDOM = require('react-dom');
40 - Scheduler = require('scheduler');
41 -
42 - // TODO: This import throws outside of experimental mode. Figure out better
43 - // strategy for gated imports.
44 - if (__EXPERIMENTAL__) {
45 - InputResponder = require('react-interactions/events/input').InputResponder;
46 - useInput = require('react-interactions/events/input').useInput;
47 - }
48 -};
49 -
50 -describe('Input event responder', () => {
51 - let container;
52 -
53 - beforeEach(() => {
54 - jest.resetModules();
55 - modulesInit();
56 -
57 - container = document.createElement('div');
58 - document.body.appendChild(container);
59 - });
60 -
61 - afterEach(() => {
62 - document.body.removeChild(container);
63 - container = null;
64 - });
65 -
66 - describe('disabled', () => {
67 - let onChange, onValueChange, ref;
68 -
69 - const componentInit = () => {
70 - onChange = jest.fn();
71 - onValueChange = jest.fn();
72 - ref = React.createRef();
73 -
74 - function Component() {
75 - const listener = useInput({
76 - disabled: true,
77 - onChange,
78 - onValueChange,
79 - });
80 - return <input ref={ref} DEPRECATED_flareListeners={listener} />;
81 - }
82 - ReactDOM.render(<Component />, container);
83 - };
84 -
85 - // @gate experimental
86 - it('prevents custom events being dispatched', () => {
87 - componentInit();
88 - ref.current.dispatchEvent(
89 - new Event('change', {bubbles: true, cancelable: true}),
90 - );
91 - ref.current.dispatchEvent(
92 - new Event('input', {bubbles: true, cancelable: true}),
93 - );
94 - expect(onChange).not.toBeCalled();
95 - expect(onValueChange).not.toBeCalled();
96 - });
97 - });
98 -
99 - // These were taken from the original ChangeEventPlugin-test.
100 - // They've been updated and cleaned up for React Flare.
101 - describe('onChange', () => {
102 - // We try to avoid firing "duplicate" React change events.
103 - // However, to tell which events are "duplicates" and should be ignored,
104 - // we are tracking the "current" input value, and only respect events
105 - // that occur after it changes. In most of these tests, we verify that we
106 - // keep track of the "current" value and only fire events when it changes.
107 - // See https://github.com/facebook/react/pull/5746.
108 -
109 - // @gate experimental
110 - it('should consider initial text value to be current', () => {
111 - let onChangeCalled = 0;
112 - let onValueChangeCalled = 0;
113 - const ref = React.createRef();
114 -
115 - function onChange(e) {
116 - onChangeCalled++;
117 - expect(e.type).toBe('change');
118 - }
119 -
120 - function onValueChange(e) {
121 - onValueChangeCalled++;
122 - }
123 -
124 - function Component() {
125 - const listener = useInput({
126 - onChange,
127 - onValueChange,
128 - });
129 - return (
130 - <input
131 - type="text"
132 - ref={ref}
133 - defaultValue="foo"
134 - DEPRECATED_flareListeners={listener}
135 - />
136 - );
137 - }
138 - ReactDOM.render(<Component />, container);
139 -
140 - ref.current.dispatchEvent(
141 - new Event('change', {bubbles: true, cancelable: true}),
142 - );
143 - ref.current.dispatchEvent(
144 - new Event('input', {bubbles: true, cancelable: true}),
145 - );
146 -
147 - if (ReactFeatureFlags.disableInputAttributeSyncing) {
148 - // TODO: figure out why. This might be a bug.
149 - expect(onChangeCalled).toBe(1);
150 - expect(onValueChangeCalled).toBe(1);
151 - } else {
152 - expect(onChangeCalled).toBe(0);
153 - expect(onValueChangeCalled).toBe(0);
154 - }
155 - });
156 -
157 - // @gate experimental
158 - it('should consider initial checkbox checked=true to be current', () => {
159 - let onChangeCalled = 0;
160 - let onValueChangeCalled = 0;
161 - const ref = React.createRef();
162 -
163 - function onChange(e) {
164 - onChangeCalled++;
165 - expect(e.type).toBe('change');
166 - }
167 -
168 - function onValueChange(e) {
169 - onValueChangeCalled++;
170 - }
171 -
172 - function Component() {
173 - const listener = useInput({
174 - onChange,
175 - onValueChange,
176 - });
177 - return (
178 - <input
179 - type="checkbox"
180 - ref={ref}
181 - defaultChecked={true}
182 - DEPRECATED_flareListeners={listener}
183 - />
184 - );
185 - }
186 - ReactDOM.render(<Component />, container);
187 -
188 - // Secretly, set `checked` to false, so that dispatching the `click` will
189 - // make it `true` again. Thus, at the time of the event, React should not
190 - // consider it a change from the initial `true` value.
191 - setUntrackedChecked.call(ref.current, false);
192 - ref.current.dispatchEvent(
193 - new MouseEvent('click', {bubbles: true, cancelable: true}),
194 - );
195 -
196 - // There should be no React change events because the value stayed the same.
197 - expect(onChangeCalled).toBe(0);
198 - expect(onValueChangeCalled).toBe(0);
199 - });
200 -
201 - // @gate experimental
202 - it('should consider initial checkbox checked=false to be current', () => {
203 - let onChangeCalled = 0;
204 - let onValueChangeCalled = 0;
205 - const ref = React.createRef();
206 -
207 - function onChange(e) {
208 - onChangeCalled++;
209 - expect(e.type).toBe('change');
210 - }
211 -
212 - function onValueChange(e) {
213 - onValueChangeCalled++;
214 - }
215 -
216 - function Component() {
217 - const listener = useInput({
218 - onChange,
219 - onValueChange,
220 - });
221 - return (
222 - <input
223 - type="checkbox"
224 - ref={ref}
225 - defaultChecked={false}
226 - DEPRECATED_flareListeners={listener}
227 - />
228 - );
229 - }
230 - ReactDOM.render(<Component />, container);
231 -
232 - // Secretly, set `checked` to true, so that dispatching the `click` will
233 - // make it `false` again. Thus, at the time of the event, React should not
234 - // consider it a change from the initial `false` value.
235 - setUntrackedChecked.call(ref.current, true);
236 - ref.current.dispatchEvent(
237 - new MouseEvent('click', {bubbles: true, cancelable: true}),
238 - );
239 - // There should be no React change events because the value stayed the same.
240 - expect(onChangeCalled).toBe(0);
241 - expect(onValueChangeCalled).toBe(0);
242 - });
243 -
244 - // @gate experimental
245 - it('should fire change for checkbox input', () => {
246 - let onChangeCalled = 0;
247 - let onValueChangeCalled = 0;
248 - const ref = React.createRef();
249 -
250 - function onChange(e) {
251 - onChangeCalled++;
252 - expect(e.type).toBe('change');
253 - }
254 -
255 - function onValueChange(e) {
256 - onValueChangeCalled++;
257 - }
258 -
259 - function Component() {
260 - const listener = useInput({
261 - onChange,
262 - onValueChange,
263 - });
264 - return (
265 - <input
266 - type="checkbox"
267 - ref={ref}
268 - DEPRECATED_flareListeners={listener}
269 - />
270 - );
271 - }
272 - ReactDOM.render(<Component />, container);
273 -
274 - ref.current.dispatchEvent(
275 - new MouseEvent('click', {bubbles: true, cancelable: true}),
276 - );
277 - // Note: unlike with text input events, dispatching `click` actually
278 - // toggles the checkbox and updates its `checked` value.
279 - expect(ref.current.checked).toBe(true);
280 - expect(onChangeCalled).toBe(1);
281 - expect(onValueChangeCalled).toBe(1);
282 -
283 - expect(ref.current.checked).toBe(true);
284 - ref.current.dispatchEvent(
285 - new MouseEvent('click', {bubbles: true, cancelable: true}),
286 - );
287 - expect(ref.current.checked).toBe(false);
288 - expect(onChangeCalled).toBe(2);
289 - expect(onValueChangeCalled).toBe(2);
290 - });
291 -
292 - // @gate experimental
293 - it('should not fire change setting the value programmatically', () => {
294 - let onChangeCalled = 0;
295 - let onValueChangeCalled = 0;
296 - const ref = React.createRef();
297 -
298 - function onChange(e) {
299 - onChangeCalled++;
300 - expect(e.type).toBe('change');
301 - }
302 -
303 - function onValueChange(e) {
304 - onValueChangeCalled++;
305 - }
306 -
307 - function Component() {
308 - const listener = useInput({
309 - onChange,
310 - onValueChange,
311 - });
312 - return (
313 - <input
314 - type="text"
315 - defaultValue="foo"
316 - ref={ref}
317 - DEPRECATED_flareListeners={listener}
318 - />
319 - );
320 - }
321 - ReactDOM.render(<Component />, container);
322 -
323 - // Set it programmatically.
324 - ref.current.value = 'bar';
325 - // Even if a DOM input event fires, React sees that the real input value now
326 - // ('bar') is the same as the "current" one we already recorded.
327 - ref.current.dispatchEvent(
328 - new Event('input', {bubbles: true, cancelable: true}),
329 - );
330 - expect(ref.current.value).toBe('bar');
331 - // In this case we don't expect to get a React event.
332 - expect(onChangeCalled).toBe(0);
333 - expect(onValueChangeCalled).toBe(0);
334 -
335 - // However, we can simulate user typing by calling the underlying setter.
336 - setUntrackedValue.call(ref.current, 'foo');
337 - // Now, when the event fires, the real input value ('foo') differs from the
338 - // "current" one we previously recorded ('bar').
339 - ref.current.dispatchEvent(
340 - new Event('input', {bubbles: true, cancelable: true}),
341 - );
342 - expect(ref.current.value).toBe('foo');
343 - // In this case React should fire an event for it.
344 - expect(onChangeCalled).toBe(1);
345 - expect(onValueChangeCalled).toBe(1);
346 -
347 - // Verify again that extra events without real changes are ignored.
348 - ref.current.dispatchEvent(
349 - new Event('input', {bubbles: true, cancelable: true}),
350 - );
351 - expect(onChangeCalled).toBe(1);
352 - expect(onValueChangeCalled).toBe(1);
353 - });
354 -
355 - // @gate experimental
356 - it('should not distinguish equal string and number values', () => {
357 - let onChangeCalled = 0;
358 - let onValueChangeCalled = 0;
359 - const ref = React.createRef();
360 -
361 - function onChange(e) {
362 - onChangeCalled++;
363 - expect(e.type).toBe('change');
364 - }
365 -
366 - function onValueChange(e) {
367 - onValueChangeCalled++;
368 - }
369 -
370 - function Component() {
371 - const listener = useInput({
372 - onChange,
373 - onValueChange,
374 - });
375 - return (
376 - <input
377 - type="text"
378 - defaultValue="42"
379 - ref={ref}
380 - DEPRECATED_flareListeners={listener}
381 - />
382 - );
383 - }
384 - ReactDOM.render(<Component />, container);
385 -
386 - // When we set `value` as a property, React updates the "current" value
387 - // that it tracks internally. The "current" value is later used to determine
388 - // whether a change event is a duplicate or not.
389 - // Even though we set value to a number, we still shouldn't get a change
390 - // event because as a string, it's equal to the initial value ('42').
391 - ref.current.value = 42;
392 - ref.current.dispatchEvent(
393 - new Event('input', {bubbles: true, cancelable: true}),
394 - );
395 - expect(ref.current.value).toBe('42');
396 - expect(onChangeCalled).toBe(0);
397 - expect(onValueChangeCalled).toBe(0);
398 - });
399 -
400 - // See a similar input test above for a detailed description of why.
401 - // @gate experimental
402 - it('should not fire change when setting checked programmatically', () => {
403 - let onChangeCalled = 0;
404 - let onValueChangeCalled = 0;
405 - const ref = React.createRef();
406 -
407 - function onChange(e) {
408 - onChangeCalled++;
409 - expect(e.type).toBe('change');
410 - }
411 -
412 - function onValueChange(e) {
413 - onValueChangeCalled++;
414 - }
415 -
416 - function Component() {
417 - const listener = useInput({
418 - onChange,
419 - onValueChange,
420 - });
421 - return (
422 - <input
423 - type="checkbox"
424 - defaultChecked={false}
425 - ref={ref}
426 - DEPRECATED_flareListeners={listener}
427 - />
428 - );
429 - }
430 - ReactDOM.render(<Component />, container);
431 -
432 - // Set the value, updating the "current" value that React tracks to true.
433 - ref.current.checked = true;
434 - // Under the hood, uncheck the box so that the click will "check" it again.
435 - setUntrackedChecked.call(ref.current, false);
436 - ref.current.dispatchEvent(
437 - new MouseEvent('click', {bubbles: true, cancelable: true}),
438 - );
439 - expect(ref.current.checked).toBe(true);
440 - // We don't expect a React event because at the time of the click, the real
441 - // checked value (true) was the same as the last recorded "current" value
442 - // (also true).
443 - expect(onChangeCalled).toBe(0);
444 - expect(onValueChangeCalled).toBe(0);
445 -
446 - // However, simulating a normal click should fire a React event because the
447 - // real value (false) would have changed from the last tracked value (true).
448 - ref.current.click();
449 - expect(onChangeCalled).toBe(1);
450 - expect(onValueChangeCalled).toBe(1);
451 - });
452 -
453 - // @gate experimental
454 - it('should only fire change for checked radio button once', () => {
455 - let onChangeCalled = 0;
456 - let onValueChangeCalled = 0;
457 - const ref = React.createRef();
458 -
459 - function onChange(e) {
460 - onChangeCalled++;
461 - expect(e.type).toBe('change');
462 - }
463 -
464 - function onValueChange(e) {
465 - onValueChangeCalled++;
466 - }
467 -
468 - function Component() {
469 - const listener = useInput({
470 - onChange,
471 - onValueChange,
472 - });
473 - return (
474 - <input type="radio" ref={ref} DEPRECATED_flareListeners={listener} />
475 - );
476 - }
477 - ReactDOM.render(<Component />, container);
478 -
479 - setUntrackedChecked.call(ref.current, true);
480 - ref.current.dispatchEvent(
481 - new Event('click', {bubbles: true, cancelable: true}),
482 - );
483 - ref.current.dispatchEvent(
484 - new Event('click', {bubbles: true, cancelable: true}),
485 - );
486 - expect(onChangeCalled).toBe(1);
487 - expect(onValueChangeCalled).toBe(1);
488 - });
489 -
490 - // @gate experimental
491 - it('should track radio button cousins in a group', () => {
492 - let onChangeCalled1 = 0;
493 - let onValueChangeCalled1 = 0;
494 - let onChangeCalled2 = 0;
495 - let onValueChangeCalled2 = 0;
496 - const ref = React.createRef();
497 -
498 - function onChange1(e) {
499 - onChangeCalled1++;
500 - expect(e.type).toBe('change');
501 - }
502 -
503 - function onValueChange1(e) {
504 - onValueChangeCalled1++;
505 - }
506 -
507 - function onChange2(e) {
508 - onChangeCalled2++;
509 - expect(e.type).toBe('change');
510 - }
511 -
512 - function onValueChange2(e) {
513 - onValueChangeCalled2++;
514 - }
515 -
516 - function Radio1() {
517 - const listener = useInput({
518 - onChange: onChange1,
519 - onValueChange: onValueChange1,
520 - });
521 - return (
522 - <input
523 - type="radio"
524 - name="group"
525 - DEPRECATED_flareListeners={listener}
526 - />
527 - );
528 - }
529 -
530 - function Radio2() {
531 - const listener = useInput({
532 - onChange: onChange2,
533 - onValueChange: onValueChange2,
534 - });
535 - return (
536 - <input
537 - type="radio"
538 - name="group"
539 - DEPRECATED_flareListeners={listener}
540 - />
541 - );
542 - }
543 -
544 - function Component() {
545 - return (
546 - <div ref={ref}>
547 - <Radio1 />
548 - <Radio2 />
549 - </div>
550 - );
551 - }
552 - ReactDOM.render(<Component />, container);
553 -
554 - const option1 = ref.current.childNodes[0];
555 - const option2 = ref.current.childNodes[1];
556 -
557 - // Select first option.
558 - option1.click();
559 - expect(onChangeCalled1).toBe(1);
560 - expect(onValueChangeCalled1).toBe(1);
561 - expect(onChangeCalled2).toBe(0);
562 - expect(onValueChangeCalled2).toBe(0);
563 -
564 - // Select second option.
565 - option2.click();
566 - expect(onChangeCalled1).toBe(1);
567 - expect(onValueChangeCalled1).toBe(1);
568 - expect(onChangeCalled2).toBe(1);
569 - expect(onValueChangeCalled2).toBe(1);
570 -
571 - // Select the first option.
572 - // It should receive the React change event again.
573 - option1.click();
574 - expect(onChangeCalled1).toBe(2);
575 - expect(onValueChangeCalled1).toBe(2);
576 - expect(onChangeCalled2).toBe(1);
577 - expect(onValueChangeCalled2).toBe(1);
578 - });
579 -
580 - // @gate experimental
581 - it('should deduplicate input value change events', () => {
582 - let onChangeCalled = 0;
583 - let onValueChangeCalled = 0;
584 - const ref = React.createRef();
585 -
586 - function onChange(e) {
587 - onChangeCalled++;
588 - expect(e.type).toBe('change');
589 - }
590 -
591 - function onValueChange(e) {
592 - onValueChangeCalled++;
593 - }
594 -
595 - ['text', 'number', 'range'].forEach(type => {
596 - onChangeCalled = 0;
597 - onValueChangeCalled = 0;
598 - function Component() {
599 - const listener = useInput({
600 - onChange,
601 - onValueChange,
602 - });
603 - return (
604 - <input
605 - type={type}
606 - name="group"
607 - ref={ref}
608 - DEPRECATED_flareListeners={listener}
609 - />
610 - );
611 - }
612 - ReactDOM.render(<Component />, container);
613 - // Should be ignored (no change):
614 - ref.current.dispatchEvent(
615 - new Event('change', {bubbles: true, cancelable: true}),
616 - );
617 - setUntrackedValue.call(ref.current, '42');
618 - ref.current.dispatchEvent(
619 - new Event('change', {bubbles: true, cancelable: true}),
620 - );
621 - // Should be ignored (no change):
622 - ref.current.dispatchEvent(
623 - new Event('change', {bubbles: true, cancelable: true}),
624 - );
625 - expect(onChangeCalled).toBe(1);
626 - expect(onValueChangeCalled).toBe(1);
627 - ReactDOM.unmountComponentAtNode(container);
628 -
629 - onChangeCalled = 0;
630 - onValueChangeCalled = 0;
631 - function Component2() {
632 - const listener = useInput({
633 - onChange,
634 - onValueChange,
635 - });
636 - return (
637 - <input type={type} ref={ref} DEPRECATED_flareListeners={listener} />
638 - );
639 - }
640 - ReactDOM.render(<Component2 />, container);
641 - // Should be ignored (no change):
642 - ref.current.dispatchEvent(
643 - new Event('input', {bubbles: true, cancelable: true}),
644 - );
645 - setUntrackedValue.call(ref.current, '42');
646 - ref.current.dispatchEvent(
647 - new Event('input', {bubbles: true, cancelable: true}),
648 - );
649 - // Should be ignored (no change):
650 - ref.current.dispatchEvent(
651 - new Event('input', {bubbles: true, cancelable: true}),
652 - );
653 - expect(onChangeCalled).toBe(1);
654 - expect(onValueChangeCalled).toBe(1);
655 - ReactDOM.unmountComponentAtNode(container);
656 -
657 - onChangeCalled = 0;
658 - onValueChangeCalled = 0;
659 - function Component3() {
660 - const listener = useInput({
661 - onChange,
662 - onValueChange,
663 - });
664 - return (
665 - <input type={type} ref={ref} DEPRECATED_flareListeners={listener} />
666 - );
667 - }
668 - ReactDOM.render(<Component3 />, container);
669 - // Should be ignored (no change):
670 - ref.current.dispatchEvent(
671 - new Event('change', {bubbles: true, cancelable: true}),
672 - );
673 - setUntrackedValue.call(ref.current, '42');
674 - ref.current.dispatchEvent(
675 - new Event('input', {bubbles: true, cancelable: true}),
676 - );
677 - // Should be ignored (no change):
678 - ref.current.dispatchEvent(
679 - new Event('change', {bubbles: true, cancelable: true}),
680 - );
681 - expect(onChangeCalled).toBe(1);
682 - expect(onValueChangeCalled).toBe(1);
683 - ReactDOM.unmountComponentAtNode(container);
684 - });
685 - });
686 -
687 - // @gate experimental
688 - it('should listen for both change and input events when supported', () => {
689 - let onChangeCalled = 0;
690 - let onValueChangeCalled = 0;
691 - const ref = React.createRef();
692 -
693 - function onChange(e) {
694 - onChangeCalled++;
695 - expect(e.type).toBe('change');
696 - }
697 -
698 - function onValueChange(e) {
699 - onValueChangeCalled++;
700 - }
701 -
702 - function Component() {
703 - const listener = useInput({
704 - onChange,
705 - onValueChange,
706 - });
707 - return (
708 - <input type="range" ref={ref} DEPRECATED_flareListeners={listener} />
709 - );
710 - }
711 - ReactDOM.render(<Component />, container);
712 -
713 - setUntrackedValue.call(ref.current, 10);
714 - ref.current.dispatchEvent(
715 - new Event('input', {bubbles: true, cancelable: true}),
716 - );
717 -
718 - setUntrackedValue.call(ref.current, 20);
719 - ref.current.dispatchEvent(
720 - new Event('change', {bubbles: true, cancelable: true}),
721 - );
722 -
723 - expect(onChangeCalled).toBe(2);
724 - expect(onValueChangeCalled).toBe(2);
725 - });
726 -
727 - // @gate experimental
728 - it('should only fire events when the value changes for range inputs', () => {
729 - let onChangeCalled = 0;
730 - let onValueChangeCalled = 0;
731 - const ref = React.createRef();
732 -
733 - function onChange(e) {
734 - onChangeCalled++;
735 - expect(e.type).toBe('change');
736 - }
737 -
738 - function onValueChange(e) {
739 - onValueChangeCalled++;
740 - }
741 -
742 - function Component() {
743 - const listener = useInput({
744 - onChange,
745 - onValueChange,
746 - });
747 - return (
748 - <input type="range" ref={ref} DEPRECATED_flareListeners={listener} />
749 - );
750 - }
751 - ReactDOM.render(<Component />, container);
752 -
753 - setUntrackedValue.call(ref.current, '40');
754 - ref.current.dispatchEvent(
755 - new Event('input', {bubbles: true, cancelable: true}),
756 - );
757 - ref.current.dispatchEvent(
758 - new Event('change', {bubbles: true, cancelable: true}),
759 - );
760 -
761 - setUntrackedValue.call(ref.current, 'foo');
762 - ref.current.dispatchEvent(
763 - new Event('input', {bubbles: true, cancelable: true}),
764 - );
765 - ref.current.dispatchEvent(
766 - new Event('change', {bubbles: true, cancelable: true}),
767 - );
768 -
769 - expect(onChangeCalled).toBe(2);
770 - expect(onValueChangeCalled).toBe(2);
771 - });
772 -
773 - // @gate experimental || build === "production"
774 - it('does not crash for nodes with custom value property', () => {
775 - let originalCreateElement;
776 - // https://github.com/facebook/react/issues/10196
777 - try {
778 - originalCreateElement = document.createElement;
779 - document.createElement = function() {
780 - const node = originalCreateElement.apply(this, arguments);
781 - Object.defineProperty(node, 'value', {
782 - get() {},
783 - set() {},
784 - });
785 - return node;
786 - };
787 - const ref = React.createRef();
788 - const div = document.createElement('div');
789 - // Mount
790 - ReactDOM.render(
791 - <input type="text" ref={ref} responders={<InputResponder />} />,
792 - div,
793 - );
794 - // Update
795 - ReactDOM.render(
796 - <input type="text" ref={ref} responders={<InputResponder />} />,
797 - div,
798 - );
799 - // Change
800 - ref.current.dispatchEvent(
801 - new Event('change', {bubbles: true, cancelable: true}),
802 - );
803 - // Unmount
804 - ReactDOM.unmountComponentAtNode(div);
805 - } finally {
806 - document.createElement = originalCreateElement;
807 - }
808 - });
809 -
810 - describe('concurrent mode', () => {
811 - // @gate experimental
812 - // @gate experimental
813 - it('text input', () => {
814 - const root = ReactDOM.createRoot(container);
815 - let input;
816 -
817 - function Component({innerRef, onChange, controlledValue}) {
818 - const listener = useInput({
819 - onChange,
820 - });
821 - return (
822 - <input
823 - type="text"
824 - ref={innerRef}
825 - value={controlledValue}
826 - DEPRECATED_flareListeners={listener}
827 - />
828 - );
829 - }
830 -
831 - class ControlledInput extends React.Component {
832 - state = {value: 'initial'};
833 - onChange = event => this.setState({value: event.target.value});
834 - render() {
835 - Scheduler.unstable_yieldValue(`render: ${this.state.value}`);
836 - const controlledValue =
837 - this.state.value === 'changed' ? 'changed [!]' : this.state.value;
838 - return (
839 - <Component
840 - onChange={this.onChange}
841 - innerRef={el => (input = el)}
842 - controlledValue={controlledValue}
843 - />
844 - );
845 - }
846 - }
847 -
848 - // Initial mount. Test that this is async.
849 - root.render(<ControlledInput />);
850 - // Should not have flushed yet.
851 - expect(Scheduler).toHaveYielded([]);
852 - expect(input).toBe(undefined);
853 - // Flush callbacks.
854 - expect(Scheduler).toFlushAndYield(['render: initial']);
855 - expect(input.value).toBe('initial');
856 -
857 - // Trigger a change event.
858 - setUntrackedValue.call(input, 'changed');
859 - input.dispatchEvent(
860 - new Event('input', {bubbles: true, cancelable: true}),
861 - );
862 - // Change should synchronously flush
863 - expect(Scheduler).toHaveYielded(['render: changed']);
864 - // Value should be the controlled value, not the original one
865 - expect(input.value).toBe('changed [!]');
866 - });
867 -
868 - // @gate experimental
869 - // @gate experimental
870 - it('checkbox input', () => {
871 - const root = ReactDOM.createRoot(container);
872 - let input;
873 -
874 - function Component({innerRef, onChange, controlledValue}) {
875 - const listener = useInput({
876 - onChange,
877 - });
878 - return (
879 - <input
880 - type="checkbox"
881 - ref={innerRef}
882 - checked={controlledValue}
883 - DEPRECATED_flareListeners={listener}
884 - />
885 - );
886 - }
887 -
888 - class ControlledInput extends React.Component {
889 - state = {checked: false};
890 - onChange = event => {
891 - this.setState({checked: event.target.checked});
892 - };
893 - render() {
894 - Scheduler.unstable_yieldValue(`render: ${this.state.checked}`);
895 - const controlledValue = this.props.reverse
896 - ? !this.state.checked
897 - : this.state.checked;
898 - return (
899 - <Component
900 - controlledValue={controlledValue}
901 - onChange={this.onChange}
902 - innerRef={el => (input = el)}
903 - />
904 - );
905 - }
906 - }
907 -
908 - // Initial mount. Test that this is async.
909 - root.render(<ControlledInput reverse={false} />);
910 - // Should not have flushed yet.
911 - expect(Scheduler).toHaveYielded([]);
912 - expect(input).toBe(undefined);
913 - // Flush callbacks.
914 - expect(Scheduler).toFlushAndYield(['render: false']);
915 - expect(input.checked).toBe(false);
916 -
917 - // Trigger a change event.
918 - input.dispatchEvent(
919 - new MouseEvent('click', {bubbles: true, cancelable: true}),
920 - );
921 - // Change should synchronously flush
922 - expect(Scheduler).toHaveYielded(['render: true']);
923 - expect(input.checked).toBe(true);
924 -
925 - // Now let's make sure we're using the controlled value.
926 - root.render(<ControlledInput reverse={true} />);
927 - expect(Scheduler).toFlushAndYield(['render: true']);
928 -
929 - // Trigger another change event.
930 - input.dispatchEvent(
931 - new MouseEvent('click', {bubbles: true, cancelable: true}),
932 - );
933 - // Change should synchronously flush
934 - expect(Scheduler).toHaveYielded(['render: true']);
935 - expect(input.checked).toBe(false);
936 - });
937 -
938 - // @gate experimental
939 - // @gate experimental
940 - it('textarea', () => {
941 - const root = ReactDOM.createRoot(container);
942 - let textarea;
943 -
944 - function Component({innerRef, onChange, controlledValue}) {
945 - const listener = useInput({
946 - onChange,
947 - });
948 - return (
949 - <textarea
950 - type="text"
951 - ref={innerRef}
952 - value={controlledValue}
953 - DEPRECATED_flareListeners={listener}
954 - />
955 - );
956 - }
957 -
958 - class ControlledTextarea extends React.Component {
959 - state = {value: 'initial'};
960 - onChange = event => this.setState({value: event.target.value});
961 - render() {
962 - Scheduler.unstable_yieldValue(`render: ${this.state.value}`);
963 - const controlledValue =
964 - this.state.value === 'changed' ? 'changed [!]' : this.state.value;
965 - return (
966 - <Component
967 - onChange={this.onChange}
968 - innerRef={el => (textarea = el)}
969 - controlledValue={controlledValue}
970 - />
971 - );
972 - }
973 - }
974 -
975 - // Initial mount. Test that this is async.
976 - root.render(<ControlledTextarea />);
977 - // Should not have flushed yet.
978 - expect(Scheduler).toHaveYielded([]);
979 - expect(textarea).toBe(undefined);
980 - // Flush callbacks.
981 - expect(Scheduler).toFlushAndYield(['render: initial']);
982 - expect(textarea.value).toBe('initial');
983 -
984 - // Trigger a change event.
985 - setUntrackedTextareaValue.call(textarea, 'changed');
986 - textarea.dispatchEvent(
987 - new Event('input', {bubbles: true, cancelable: true}),
988 - );
989 - // Change should synchronously flush
990 - expect(Scheduler).toHaveYielded(['render: changed']);
991 - // Value should be the controlled value, not the original one
992 - expect(textarea.value).toBe('changed [!]');
993 - });
994 - });
995 - });
996 -
997 - // @gate experimental
998 - it('expect displayName to show up for event component', () => {
999 - expect(InputResponder.displayName).toBe('Input');
1000 - });
1001 -});
packages/react-interactions/events/src/dom/__tests__/MixedResponders-test-internal.js deleted
-255
@@ -1,255 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {createEventTarget} from 'dom-event-testing-library';
13 -
14 -let React;
15 -let ReactFeatureFlags;
16 -let ReactDOM;
17 -let Scheduler;
18 -
19 -describe('mixing responders with the heritage event system', () => {
20 - let container;
21 -
22 - beforeEach(() => {
23 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
24 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
25 - React = require('react');
26 - ReactDOM = require('react-dom');
27 - Scheduler = require('scheduler');
28 - container = document.createElement('div');
29 - document.body.appendChild(container);
30 - });
31 -
32 - afterEach(() => {
33 - document.body.removeChild(container);
34 - container = null;
35 - });
36 -
37 - // @gate experimental
38 - it('should properly only flush sync once when the event systems are mixed', () => {
39 - const useTap = require('react-interactions/events/tap').useTap;
40 - const ref = React.createRef();
41 - let renderCounts = 0;
42 -
43 - function MyComponent() {
44 - const [, updateCounter] = React.useState(0);
45 - renderCounts++;
46 -
47 - function handleTap() {
48 - updateCounter(count => count + 1);
49 - }
50 -
51 - const listener = useTap({
52 - onTapEnd: handleTap,
53 - });
54 -
55 - return (
56 - <div>
57 - <button
58 - ref={ref}
59 - DEPRECATED_flareListeners={listener}
60 - onClick={() => {
61 - updateCounter(count => count + 1);
62 - }}>
63 - Press me
64 - </button>
65 - </div>
66 - );
67 - }
68 -
69 - const newContainer = document.createElement('div');
70 - const root = ReactDOM.createRoot(newContainer);
71 - document.body.appendChild(newContainer);
72 - root.render(<MyComponent />);
73 - Scheduler.unstable_flushAll();
74 -
75 - const target = createEventTarget(ref.current);
76 - target.pointerdown({timeStamp: 100});
77 - target.pointerup({timeStamp: 100});
78 - target.click({timeStamp: 100});
79 -
80 - if (__DEV__) {
81 - expect(renderCounts).toBe(2);
82 - } else {
83 - expect(renderCounts).toBe(1);
84 - }
85 - Scheduler.unstable_flushAll();
86 - if (__DEV__) {
87 - expect(renderCounts).toBe(4);
88 - } else {
89 - expect(renderCounts).toBe(2);
90 - }
91 -
92 - target.pointerdown({timeStamp: 100});
93 - target.pointerup({timeStamp: 100});
94 - // Ensure the timeStamp logic works
95 - target.click({timeStamp: 101});
96 -
97 - if (__DEV__) {
98 - expect(renderCounts).toBe(6);
99 - } else {
100 - expect(renderCounts).toBe(3);
101 - }
102 -
103 - Scheduler.unstable_flushAll();
104 - document.body.removeChild(newContainer);
105 - });
106 -
107 - // @gate experimental
108 - it(
109 - 'should only flush before outermost discrete event handler when mixing ' +
110 - 'event systems',
111 - async () => {
112 - const {useState} = React;
113 - const useTap = require('react-interactions/events/tap').useTap;
114 -
115 - const button = React.createRef();
116 -
117 - function MyComponent() {
118 - const [pressesCount, updatePressesCount] = useState(0);
119 - const [clicksCount, updateClicksCount] = useState(0);
120 -
121 - function handleTap() {
122 - // This dispatches a synchronous, discrete event in the legacy event
123 - // system. However, because it's nested inside the new event system,
124 - // its updates should not flush until the end of the outer handler.
125 - const target = createEventTarget(button.current);
126 - target.click();
127 - // Text context should not have changed
128 - Scheduler.unstable_yieldValue(newContainer.textContent);
129 - updatePressesCount(pressesCount + 1);
130 - }
131 -
132 - const tap = useTap({
133 - onTapEnd: handleTap,
134 - });
135 -
136 - return (
137 - <div>
138 - <button
139 - DEPRECATED_flareListeners={tap}
140 - ref={button}
141 - onClick={() => updateClicksCount(clicksCount + 1)}>
142 - Presses: {pressesCount}, Clicks: {clicksCount}
143 - </button>
144 - </div>
145 - );
146 - }
147 -
148 - const newContainer = document.createElement('div');
149 - document.body.appendChild(newContainer);
150 - const root = ReactDOM.createRoot(newContainer);
151 -
152 - root.render(<MyComponent />);
153 - expect(Scheduler).toFlushWithoutYielding();
154 - expect(newContainer.textContent).toEqual('Presses: 0, Clicks: 0');
155 -
156 - const target = createEventTarget(button.current);
157 - target.pointerdown({timeStamp: 100});
158 - target.pointerup({timeStamp: 100});
159 -
160 - expect(Scheduler).toHaveYielded(['Presses: 0, Clicks: 0']);
161 - expect(Scheduler).toFlushWithoutYielding();
162 - expect(newContainer.textContent).toEqual('Presses: 1, Clicks: 1');
163 - },
164 - );
165 -
166 - describe('mixing the Input and Press responders', () => {
167 - // @gate experimental
168 - it('is async for non-input events', () => {
169 - const useTap = require('react-interactions/events/tap').useTap;
170 - const useInput = require('react-interactions/events/input').useInput;
171 - const root = ReactDOM.createRoot(container);
172 - let input;
173 -
174 - function Component({innerRef, onChange, controlledValue, listeners}) {
175 - const inputListener = useInput({onChange});
176 - return (
177 - <input
178 - type="text"
179 - ref={innerRef}
180 - value={controlledValue}
181 - DEPRECATED_flareListeners={[inputListener, listeners]}
182 - />
183 - );
184 - }
185 -
186 - function PressWrapper({innerRef, onTap, onChange, controlledValue}) {
187 - const tap = useTap({
188 - onTapEnd: onTap,
189 - });
190 - return (
191 - <Component
192 - onChange={onChange}
193 - innerRef={el => (input = el)}
194 - controlledValue={controlledValue}
195 - listeners={tap}
196 - />
197 - );
198 - }
199 -
200 - class ControlledInput extends React.Component {
201 - state = {value: 'initial'};
202 - onChange = event => this.setState({value: event.target.value});
203 - reset = () => {
204 - this.setState({value: ''});
205 - };
206 - render() {
207 - Scheduler.unstable_yieldValue(`render: ${this.state.value}`);
208 - const controlledValue =
209 - this.state.value === 'changed' ? 'changed [!]' : this.state.value;
210 - return (
211 - <PressWrapper
212 - onTap={this.reset}
213 - onChange={this.onChange}
214 - innerRef={el => (input = el)}
215 - controlledValue={controlledValue}
216 - />
217 - );
218 - }
219 - }
220 -
221 - // Initial mount. Test that this is async.
222 - root.render(<ControlledInput />);
223 - // Should not have flushed yet.
224 - expect(Scheduler).toHaveYielded([]);
225 - expect(input).toBe(undefined);
226 - // Flush callbacks.
227 - expect(Scheduler).toFlushAndYield(['render: initial']);
228 - expect(input.value).toBe('initial');
229 -
230 - // Trigger a click event
231 - input.dispatchEvent(
232 - new MouseEvent('mousedown', {
233 - bubbles: true,
234 - cancelable: true,
235 - buttons: 1,
236 - }),
237 - );
238 - input.dispatchEvent(
239 - new MouseEvent('mouseup', {
240 - bubbles: true,
241 - cancelable: true,
242 - buttons: 0,
243 - }),
244 - );
245 - // Nothing should have changed
246 - expect(Scheduler).toHaveYielded([]);
247 - expect(input.value).toBe('initial');
248 -
249 - // Flush callbacks.
250 - // Now the click update has flushed.
251 - expect(Scheduler).toFlushAndYield(['render: ']);
252 - expect(input.value).toBe('');
253 - });
254 - });
255 -});
packages/react-interactions/events/src/dom/__tests__/PressLegacy-test.internal.js deleted
-1346
@@ -1,1346 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {
13 - buttonType,
14 - buttonsType,
15 - createEventTarget,
16 - resetActivePointers,
17 - setPointerEvent,
18 -} from 'dom-event-testing-library';
19 -
20 -let React;
21 -let ReactFeatureFlags;
22 -let ReactDOM;
23 -let PressResponder;
24 -let usePress;
25 -
26 -function initializeModules(hasPointerEvents) {
27 - jest.resetModules();
28 - setPointerEvent(hasPointerEvents);
29 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
30 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
31 - React = require('react');
32 - ReactDOM = require('react-dom');
33 -
34 - // TODO: This import throws outside of experimental mode. Figure out better
35 - // strategy for gated imports.
36 - if (__EXPERIMENTAL__) {
37 - PressResponder = require('react-interactions/events/press-legacy')
38 - .PressResponder;
39 - usePress = require('react-interactions/events/press-legacy').usePress;
40 - }
41 -}
42 -
43 -function removePressMoveStrings(eventString) {
44 - if (eventString === 'onPressMove') {
45 - return false;
46 - }
47 - return true;
48 -}
49 -
50 -const forcePointerEvents = true;
51 -const environmentTable = [[forcePointerEvents], [!forcePointerEvents]];
52 -
53 -const pointerTypesTable = [['mouse'], ['touch']];
54 -
55 -describe.each(environmentTable)('Press responder', hasPointerEvents => {
56 - let container;
57 -
58 - beforeEach(() => {
59 - initializeModules(hasPointerEvents);
60 - container = document.createElement('div');
61 - document.body.appendChild(container);
62 - });
63 -
64 - afterEach(() => {
65 - ReactDOM.render(null, container);
66 - document.body.removeChild(container);
67 - container = null;
68 - resetActivePointers();
69 - });
70 -
71 - describe('disabled', () => {
72 - let onPressStart, onPress, onPressEnd, ref;
73 -
74 - const componentInit = () => {
75 - onPressStart = jest.fn();
76 - onPress = jest.fn();
77 - onPressEnd = jest.fn();
78 - ref = React.createRef();
79 - const Component = () => {
80 - const listener = usePress({
81 - disabled: true,
82 - onPressStart,
83 - onPress,
84 - onPressEnd,
85 - });
86 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
87 - };
88 - ReactDOM.render(<Component />, container);
89 - document.elementFromPoint = () => ref.current;
90 - };
91 -
92 - // @gate experimental
93 - it('does not call callbacks', () => {
94 - componentInit();
95 - const target = createEventTarget(ref.current);
96 - target.pointerdown();
97 - target.pointerup();
98 - expect(onPressStart).not.toBeCalled();
99 - expect(onPress).not.toBeCalled();
100 - expect(onPressEnd).not.toBeCalled();
101 - });
102 - });
103 -
104 - describe('onPressStart', () => {
105 - let onPressStart, ref;
106 -
107 - const componentInit = () => {
108 - onPressStart = jest.fn();
109 - ref = React.createRef();
110 - const Component = () => {
111 - const listener = usePress({
112 - onPressStart,
113 - });
114 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
115 - };
116 - ReactDOM.render(<Component />, container);
117 - document.elementFromPoint = () => ref.current;
118 - };
119 -
120 - // @gate experimental
121 - it('is called after pointer down: mouse', () => {
122 - componentInit();
123 - const target = createEventTarget(ref.current);
124 - target.pointerdown({pointerType: 'mouse'});
125 - expect(onPressStart).toHaveBeenCalledTimes(1);
126 - expect(onPressStart).toHaveBeenCalledWith(
127 - expect.objectContaining({pointerType: 'mouse', type: 'pressstart'}),
128 - );
129 - });
130 -
131 - // @gate experimental
132 - it('is called after pointer down: touch', () => {
133 - componentInit();
134 - const target = createEventTarget(ref.current);
135 - target.pointerdown({pointerType: 'touch'});
136 - expect(onPressStart).toHaveBeenCalledTimes(1);
137 - expect(onPressStart).toHaveBeenCalledWith(
138 - expect.objectContaining({pointerType: 'touch', type: 'pressstart'}),
139 - );
140 - });
141 -
142 - // @gate experimental
143 - it('is called after middle-button pointer down', () => {
144 - componentInit();
145 - const target = createEventTarget(ref.current);
146 - target.pointerdown({
147 - button: buttonType.auxiliary,
148 - buttons: buttonsType.auxiliary,
149 - pointerType: 'mouse',
150 - });
151 - expect(onPressStart).toHaveBeenCalledTimes(1);
152 - expect(onPressStart).toHaveBeenCalledWith(
153 - expect.objectContaining({
154 - buttons: buttonsType.auxiliary,
155 - pointerType: 'mouse',
156 - type: 'pressstart',
157 - }),
158 - );
159 - });
160 -
161 - // @gate experimental
162 - it('is not called after pointer move following middle-button press', () => {
163 - componentInit();
164 - const node = ref.current;
165 - const target = createEventTarget(node);
166 - target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
167 - target.pointerdown({
168 - button: buttonType.auxiliary,
169 - buttons: buttonsType.auxiliary,
170 - pointerType: 'mouse',
171 - });
172 - target.pointerup({pointerType: 'mouse'});
173 - target.pointerhover({x: 110, y: 110});
174 - target.pointerhover({x: 50, y: 50});
175 - expect(onPressStart).toHaveBeenCalledTimes(1);
176 - });
177 -
178 - // @gate experimental
179 - it('ignores any events not caused by primary/middle-click or touch/pen contact', () => {
180 - componentInit();
181 - const target = createEventTarget(ref.current);
182 - target.pointerdown({buttons: buttonsType.secondary});
183 - target.pointerup({buttons: buttonsType.secondary});
184 - target.pointerdown({buttons: buttonsType.eraser});
185 - target.pointerup({buttons: buttonsType.eraser});
186 - expect(onPressStart).toHaveBeenCalledTimes(0);
187 - });
188 -
189 - // @gate experimental
190 - it('is called once after "keydown" events for Enter', () => {
191 - componentInit();
192 - const target = createEventTarget(ref.current);
193 - target.keydown({key: 'Enter'});
194 - target.keydown({key: 'Enter'});
195 - target.keydown({key: 'Enter'});
196 - expect(onPressStart).toHaveBeenCalledTimes(1);
197 - expect(onPressStart).toHaveBeenCalledWith(
198 - expect.objectContaining({pointerType: 'keyboard', type: 'pressstart'}),
199 - );
200 - });
201 -
202 - // @gate experimental
203 - it('is called once after "keydown" events for Spacebar', () => {
204 - componentInit();
205 - const target = createEventTarget(ref.current);
206 - const preventDefault = jest.fn();
207 - target.keydown({key: ' ', preventDefault});
208 - expect(preventDefault).toBeCalled();
209 - target.keydown({key: ' ', preventDefault});
210 - expect(onPressStart).toHaveBeenCalledTimes(1);
211 - expect(onPressStart).toHaveBeenCalledWith(
212 - expect.objectContaining({
213 - pointerType: 'keyboard',
214 - type: 'pressstart',
215 - }),
216 - );
217 - });
218 -
219 - // @gate experimental
220 - it('is not called after "keydown" for other keys', () => {
221 - componentInit();
222 - const target = createEventTarget(ref.current);
223 - target.keydown({key: 'a'});
224 - expect(onPressStart).not.toBeCalled();
225 - });
226 - });
227 -
228 - describe('onPressEnd', () => {
229 - let onPressEnd, ref;
230 -
231 - const componentInit = () => {
232 - onPressEnd = jest.fn();
233 - ref = React.createRef();
234 - const Component = () => {
235 - const listener = usePress({
236 - onPressEnd,
237 - });
238 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
239 - };
240 - ReactDOM.render(<Component />, container);
241 - document.elementFromPoint = () => ref.current;
242 - };
243 -
244 - // @gate experimental
245 - it('is called after pointer up: mouse', () => {
246 - componentInit();
247 - const target = createEventTarget(ref.current);
248 - target.pointerdown({pointerType: 'mouse'});
249 - target.pointerup({pointerType: 'mouse'});
250 - expect(onPressEnd).toHaveBeenCalledTimes(1);
251 - expect(onPressEnd).toHaveBeenCalledWith(
252 - expect.objectContaining({pointerType: 'mouse', type: 'pressend'}),
253 - );
254 - });
255 -
256 - // @gate experimental
257 - it('is called after pointer up: touch', () => {
258 - componentInit();
259 - const target = createEventTarget(ref.current);
260 - target.pointerdown({pointerType: 'touch'});
261 - target.pointerup({pointerType: 'touch'});
262 - expect(onPressEnd).toHaveBeenCalledTimes(1);
263 - expect(onPressEnd).toHaveBeenCalledWith(
264 - expect.objectContaining({pointerType: 'touch', type: 'pressend'}),
265 - );
266 - });
267 -
268 - // @gate experimental
269 - it('is called after middle-button pointer up', () => {
270 - componentInit();
271 - const target = createEventTarget(ref.current);
272 - target.pointerdown({
273 - buttons: buttonsType.auxiliary,
274 - pointerType: 'mouse',
275 - });
276 - target.pointerup({pointerType: 'mouse'});
277 - expect(onPressEnd).toHaveBeenCalledTimes(1);
278 - expect(onPressEnd).toHaveBeenCalledWith(
279 - expect.objectContaining({
280 - buttons: buttonsType.auxiliary,
281 - pointerType: 'mouse',
282 - type: 'pressend',
283 - }),
284 - );
285 - });
286 -
287 - // @gate experimental
288 - it('is called after "keyup" event for Enter', () => {
289 - componentInit();
290 - const target = createEventTarget(ref.current);
291 - target.keydown({key: 'Enter'});
292 - // click occurs before keyup
293 - target.click();
294 - target.keyup({key: 'Enter'});
295 - expect(onPressEnd).toHaveBeenCalledTimes(1);
296 - expect(onPressEnd).toHaveBeenCalledWith(
297 - expect.objectContaining({pointerType: 'keyboard', type: 'pressend'}),
298 - );
299 - });
300 -
301 - // @gate experimental
302 - it('is called after "keyup" event for Spacebar', () => {
303 - componentInit();
304 - const target = createEventTarget(ref.current);
305 - target.keydown({key: ' '});
306 - target.keyup({key: ' '});
307 - expect(onPressEnd).toHaveBeenCalledTimes(1);
308 - expect(onPressEnd).toHaveBeenCalledWith(
309 - expect.objectContaining({pointerType: 'keyboard', type: 'pressend'}),
310 - );
311 - });
312 -
313 - // @gate experimental
314 - it('is not called after "keyup" event for other keys', () => {
315 - componentInit();
316 - const target = createEventTarget(ref.current);
317 - target.keydown({key: 'Enter'});
318 - target.keyup({key: 'a'});
319 - expect(onPressEnd).not.toBeCalled();
320 - });
321 -
322 - // @gate experimental
323 - it('is called with keyboard modifiers', () => {
324 - componentInit();
325 - const target = createEventTarget(ref.current);
326 - target.keydown({key: 'Enter'});
327 - target.keyup({
328 - key: 'Enter',
329 - metaKey: true,
330 - ctrlKey: true,
331 - altKey: true,
332 - shiftKey: true,
333 - });
334 - expect(onPressEnd).toHaveBeenCalledWith(
335 - expect.objectContaining({
336 - pointerType: 'keyboard',
337 - type: 'pressend',
338 - metaKey: true,
339 - ctrlKey: true,
340 - altKey: true,
341 - shiftKey: true,
342 - }),
343 - );
344 - });
345 - });
346 -
347 - describe('onPressChange', () => {
348 - let onPressChange, ref;
349 -
350 - const componentInit = () => {
351 - onPressChange = jest.fn();
352 - ref = React.createRef();
353 - const Component = () => {
354 - const listener = usePress({
355 - onPressChange,
356 - });
357 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
358 - };
359 - ReactDOM.render(<Component />, container);
360 - document.elementFromPoint = () => ref.current;
361 - };
362 -
363 - // @gate experimental
364 - it('is called after pointer down and up: mouse', () => {
365 - componentInit();
366 - const target = createEventTarget(ref.current);
367 - target.pointerdown({pointerType: 'mouse'});
368 - expect(onPressChange).toHaveBeenCalledTimes(1);
369 - expect(onPressChange).toHaveBeenCalledWith(true);
370 - target.pointerup({pointerType: 'mouse'});
371 - expect(onPressChange).toHaveBeenCalledTimes(2);
372 - expect(onPressChange).toHaveBeenCalledWith(false);
373 - });
374 -
375 - // @gate experimental
376 - it('is called after pointer down and up: touch', () => {
377 - componentInit();
378 - const target = createEventTarget(ref.current);
379 - target.pointerdown({pointerType: 'touch'});
380 - expect(onPressChange).toHaveBeenCalledTimes(1);
381 - expect(onPressChange).toHaveBeenCalledWith(true);
382 - target.pointerup({pointerType: 'touch'});
383 - expect(onPressChange).toHaveBeenCalledTimes(2);
384 - expect(onPressChange).toHaveBeenCalledWith(false);
385 - });
386 -
387 - // @gate experimental
388 - it('is called after valid "keydown" and "keyup" events', () => {
389 - componentInit();
390 - const target = createEventTarget(ref.current);
391 - target.keydown({key: 'Enter'});
392 - expect(onPressChange).toHaveBeenCalledTimes(1);
393 - expect(onPressChange).toHaveBeenCalledWith(true);
394 - target.keyup({key: 'Enter'});
395 - expect(onPressChange).toHaveBeenCalledTimes(2);
396 - expect(onPressChange).toHaveBeenCalledWith(false);
397 - });
398 - });
399 -
400 - describe('onPress', () => {
401 - let onPress, ref;
402 -
403 - const componentInit = () => {
404 - onPress = jest.fn();
405 - ref = React.createRef();
406 - const Component = () => {
407 - const listener = usePress({
408 - onPress,
409 - });
410 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
411 - };
412 - ReactDOM.render(<Component />, container);
413 - ref.current.getBoundingClientRect = () => ({
414 - top: 0,
415 - left: 0,
416 - bottom: 100,
417 - right: 100,
418 - });
419 - document.elementFromPoint = () => ref.current;
420 - };
421 -
422 - // @gate experimental
423 - it('is called after pointer up: mouse', () => {
424 - componentInit();
425 - const target = createEventTarget(ref.current);
426 - target.pointerdown({pointerType: 'mouse'});
427 - target.pointerup({pointerType: 'mouse', x: 10, y: 10});
428 - expect(onPress).toHaveBeenCalledTimes(1);
429 - expect(onPress).toHaveBeenCalledWith(
430 - expect.objectContaining({pointerType: 'mouse', type: 'press'}),
431 - );
432 - });
433 -
434 - // @gate experimental
435 - it('is called after pointer up: touch', () => {
436 - componentInit();
437 - const target = createEventTarget(ref.current);
438 - target.pointerdown({pointerType: 'touch'});
439 - target.pointerup({pointerType: 'touch', x: 10, y: 10});
440 - expect(onPress).toHaveBeenCalledTimes(1);
441 - expect(onPress).toHaveBeenCalledWith(
442 - expect.objectContaining({pointerType: 'touch', type: 'press'}),
443 - );
444 - });
445 -
446 - // @gate experimental
447 - it('is not called after middle-button press', () => {
448 - componentInit();
449 - const target = createEventTarget(ref.current);
450 - target.pointerdown({
451 - buttons: buttonsType.auxiliary,
452 - pointerType: 'mouse',
453 - });
454 - target.pointerup({pointerType: 'mouse'});
455 - expect(onPress).not.toHaveBeenCalled();
456 - });
457 -
458 - // @gate experimental
459 - it('is not called after virtual middle-button press', () => {
460 - componentInit();
461 - const target = createEventTarget(ref.current);
462 - target.pointerdown({
463 - button: buttonType.auxiliary,
464 - buttons: 0,
465 - pointerType: 'mouse',
466 - });
467 - target.pointerup({pointerType: 'mouse'});
468 - expect(onPress).not.toHaveBeenCalled();
469 - });
470 -
471 - // @gate experimental
472 - it('is called after valid "keyup" event', () => {
473 - componentInit();
474 - const target = createEventTarget(ref.current);
475 - target.keydown({key: 'Enter'});
476 - target.keyup({key: 'Enter'});
477 - expect(onPress).toHaveBeenCalledTimes(1);
478 - expect(onPress).toHaveBeenCalledWith(
479 - expect.objectContaining({pointerType: 'keyboard', type: 'press'}),
480 - );
481 - });
482 -
483 - // @gate experimental
484 - it('is not called after invalid "keyup" event', () => {
485 - componentInit();
486 - const inputRef = React.createRef();
487 - const Component = () => {
488 - const listener = usePress({onPress});
489 - return <input ref={inputRef} DEPRECATED_flareListeners={listener} />;
490 - };
491 - ReactDOM.render(<Component />, container);
492 - const target = createEventTarget(inputRef.current);
493 - target.keydown({key: 'Enter'});
494 - target.keyup({key: 'Enter'});
495 - target.keydown({key: ' '});
496 - target.keyup({key: ' '});
497 - expect(onPress).not.toBeCalled();
498 - });
499 -
500 - // @gate experimental
501 - it('is called with modifier keys', () => {
502 - componentInit();
503 - const target = createEventTarget(ref.current);
504 - target.pointerdown({metaKey: true, pointerType: 'mouse'});
505 - target.pointerup({metaKey: true, pointerType: 'mouse'});
506 - expect(onPress).toHaveBeenCalledWith(
507 - expect.objectContaining({
508 - pointerType: 'mouse',
509 - type: 'press',
510 - metaKey: true,
511 - }),
512 - );
513 - });
514 -
515 - // @gate experimental
516 - it('is called if target rect is not right but the target is (for mouse events)', () => {
517 - componentInit();
518 - const buttonRef = React.createRef();
519 - const divRef = React.createRef();
520 -
521 - const Component = () => {
522 - const listener = usePress({onPress});
523 - return (
524 - <div ref={divRef} DEPRECATED_flareListeners={listener}>
525 - <button ref={buttonRef} />
526 - </div>
527 - );
528 - };
529 - ReactDOM.render(<Component />, container);
530 -
531 - const target = createEventTarget(divRef.current);
532 - target.setBoundingClientRect({x: 0, y: 0, width: 0, height: 0});
533 - const innerTarget = createEventTarget(buttonRef.current);
534 - innerTarget.pointerdown({pointerType: 'mouse'});
535 - innerTarget.pointerup({pointerType: 'mouse'});
536 - expect(onPress).toBeCalled();
537 - });
538 -
539 - // @gate experimental
540 - it('is called once after virtual screen reader "click" event', () => {
541 - componentInit();
542 - const target = createEventTarget(ref.current);
543 - const preventDefault = jest.fn();
544 - target.virtualclick({preventDefault});
545 - expect(preventDefault).toBeCalled();
546 - expect(onPress).toHaveBeenCalledTimes(1);
547 - expect(onPress).toHaveBeenCalledWith(
548 - expect.objectContaining({
549 - pointerType: 'keyboard',
550 - type: 'press',
551 - }),
552 - );
553 - });
554 - });
555 -
556 - describe('onPressMove', () => {
557 - let onPressMove, ref;
558 -
559 - const componentInit = () => {
560 - onPressMove = jest.fn();
561 - ref = React.createRef();
562 - const Component = () => {
563 - const listener = usePress({
564 - onPressMove,
565 - });
566 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
567 - };
568 - ReactDOM.render(<Component />, container);
569 - ref.current.getBoundingClientRect = () => ({
570 - top: 0,
571 - left: 0,
572 - bottom: 100,
573 - right: 100,
574 - });
575 - document.elementFromPoint = () => ref.current;
576 - };
577 -
578 - // @gate experimental
579 - it('is called after pointer move: mouse', () => {
580 - componentInit();
581 - const node = ref.current;
582 - const target = createEventTarget(node);
583 - target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
584 - target.pointerdown({pointerType: 'mouse'});
585 - target.pointermove({pointerType: 'mouse', x: 10, y: 10});
586 - target.pointermove({pointerType: 'mouse', x: 20, y: 20});
587 - expect(onPressMove).toHaveBeenCalledTimes(2);
588 - expect(onPressMove).toHaveBeenCalledWith(
589 - expect.objectContaining({pointerType: 'mouse', type: 'pressmove'}),
590 - );
591 - });
592 -
593 - // @gate experimental
594 - it('is called after pointer move: touch', () => {
595 - componentInit();
596 - const node = ref.current;
597 - const target = createEventTarget(node);
598 - target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
599 - target.pointerdown({pointerType: 'touch'});
600 - target.pointermove({pointerType: 'touch', x: 10, y: 10});
601 - target.pointermove({pointerType: 'touch', x: 20, y: 20});
602 - expect(onPressMove).toHaveBeenCalledTimes(2);
603 - expect(onPressMove).toHaveBeenCalledWith(
604 - expect.objectContaining({pointerType: 'touch', type: 'pressmove'}),
605 - );
606 - });
607 -
608 - // @gate experimental
609 - it('is not called if pointer move occurs during keyboard press', () => {
610 - componentInit();
611 - const target = createEventTarget(ref.current);
612 - target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
613 - target.keydown({key: 'Enter'});
614 - target.pointermove({
615 - buttons: buttonsType.none,
616 - pointerType: 'mouse',
617 - x: 10,
618 - y: 10,
619 - });
620 - expect(onPressMove).not.toBeCalled();
621 - });
622 - });
623 -
624 - describe.each(pointerTypesTable)('press with movement: %s', pointerType => {
625 - let events, ref, outerRef;
626 -
627 - const componentInit = () => {
628 - events = [];
629 - ref = React.createRef();
630 - outerRef = React.createRef();
631 - const createEventHandler = msg => () => {
632 - events.push(msg);
633 - };
634 - const Component = () => {
635 - const listener = usePress({
636 - onPress: createEventHandler('onPress'),
637 - onPressChange: createEventHandler('onPressChange'),
638 - onPressMove: createEventHandler('onPressMove'),
639 - onPressStart: createEventHandler('onPressStart'),
640 - onPressEnd: createEventHandler('onPressEnd'),
641 - });
642 - return (
643 - <div ref={outerRef}>
644 - <div ref={ref} DEPRECATED_flareListeners={listener} />
645 - </div>
646 - );
647 - };
648 - ReactDOM.render(<Component />, container);
649 - document.elementFromPoint = () => ref.current;
650 - };
651 -
652 - const rectMock = {width: 100, height: 100, x: 50, y: 50};
653 - const pressRectOffset = 20;
654 - const coordinatesInside = {
655 - x: rectMock.x - pressRectOffset,
656 - y: rectMock.y - pressRectOffset,
657 - };
658 - const coordinatesOutside = {
659 - x: rectMock.x - pressRectOffset - 1,
660 - y: rectMock.y - pressRectOffset - 1,
661 - };
662 -
663 - describe('within bounds of hit rect', () => {
664 - /** ┌──────────────────┐
665 - * │ ┌────────────┐ │
666 - * │ │ VisualRect │ │
667 - * │ └────────────┘ │
668 - * │ HitRect X │ <= Move to X and release
669 - * └──────────────────┘
670 - */
671 - // @gate experimental
672 - it('"onPress*" events are called immediately', () => {
673 - componentInit();
674 - const target = createEventTarget(ref.current);
675 - target.setBoundingClientRect(rectMock);
676 - target.pointerdown({pointerType});
677 - target.pointermove({pointerType, ...coordinatesInside});
678 - target.pointerup({pointerType, ...coordinatesInside});
679 - expect(events).toEqual([
680 - 'onPressStart',
681 - 'onPressChange',
682 - 'onPressMove',
683 - 'onPressEnd',
684 - 'onPressChange',
685 - 'onPress',
686 - ]);
687 - });
688 -
689 - // @gate experimental
690 - it('"onPress*" events are correctly called with target change', () => {
691 - componentInit();
692 - const target = createEventTarget(ref.current);
693 - const outerTarget = createEventTarget(outerRef.current);
694 - target.setBoundingClientRect(rectMock);
695 - target.pointerdown({pointerType});
696 - target.pointermove({pointerType, ...coordinatesInside});
697 - // TODO: this sequence may differ in the future between PointerEvent and mouse fallback when
698 - // use 'setPointerCapture'.
699 - if (pointerType === 'touch') {
700 - target.pointermove({pointerType, ...coordinatesOutside});
701 - } else {
702 - outerTarget.pointermove({pointerType, ...coordinatesOutside});
703 - }
704 - target.pointermove({pointerType, ...coordinatesInside});
705 - target.pointerup({pointerType, ...coordinatesInside});
706 -
707 - expect(events.filter(removePressMoveStrings)).toEqual([
708 - 'onPressStart',
709 - 'onPressChange',
710 - 'onPressEnd',
711 - 'onPressChange',
712 - 'onPressStart',
713 - 'onPressChange',
714 - 'onPressEnd',
715 - 'onPressChange',
716 - 'onPress',
717 - ]);
718 - });
719 -
720 - // @gate experimental
721 - it('press retention offset can be configured', () => {
722 - componentInit();
723 - const localEvents = [];
724 - const localRef = React.createRef();
725 - const createEventHandler = msg => () => {
726 - localEvents.push(msg);
727 - };
728 - const pressRetentionOffset = {top: 40, bottom: 40, left: 40, right: 40};
729 -
730 - const Component = () => {
731 - const listener = usePress({
732 - onPress: createEventHandler('onPress'),
733 - onPressChange: createEventHandler('onPressChange'),
734 - onPressMove: createEventHandler('onPressMove'),
735 - onPressStart: createEventHandler('onPressStart'),
736 - onPressEnd: createEventHandler('onPressEnd'),
737 - pressRetentionOffset,
738 - });
739 - return <div ref={localRef} DEPRECATED_flareListeners={listener} />;
740 - };
741 - ReactDOM.render(<Component />, container);
742 -
743 - const target = createEventTarget(localRef.current);
744 - target.setBoundingClientRect(rectMock);
745 - target.pointerdown({pointerType});
746 - target.pointermove({
747 - pointerType,
748 - x: rectMock.x,
749 - y: rectMock.y,
750 - });
751 - target.pointerup({pointerType, ...coordinatesInside});
752 - expect(localEvents).toEqual([
753 - 'onPressStart',
754 - 'onPressChange',
755 - 'onPressMove',
756 - 'onPressEnd',
757 - 'onPressChange',
758 - 'onPress',
759 - ]);
760 - });
761 -
762 - // @gate experimental
763 - it('responder region accounts for decrease in element dimensions', () => {
764 - componentInit();
765 - const target = createEventTarget(ref.current);
766 - target.setBoundingClientRect(rectMock);
767 - target.pointerdown({pointerType});
768 - // emulate smaller dimensions change on activation
769 - target.setBoundingClientRect({width: 80, height: 80, y: 60, x: 60});
770 - const coordinates = {x: rectMock.x, y: rectMock.y};
771 - // move to an area within the pre-activation region
772 - target.pointermove({pointerType, ...coordinates});
773 - target.pointerup({pointerType, ...coordinates});
774 - expect(events).toEqual([
775 - 'onPressStart',
776 - 'onPressChange',
777 - 'onPressMove',
778 - 'onPressEnd',
779 - 'onPressChange',
780 - 'onPress',
781 - ]);
782 - });
783 -
784 - // @gate experimental
785 - it('responder region accounts for increase in element dimensions', () => {
786 - componentInit();
787 - const target = createEventTarget(ref.current);
788 - target.setBoundingClientRect(rectMock);
789 - target.pointerdown({pointerType});
790 - // emulate larger dimensions change on activation
791 - target.setBoundingClientRect({width: 200, height: 200, y: 0, x: 0});
792 - const coordinates = {x: rectMock.x - 50, y: rectMock.y - 50};
793 - // move to an area within the post-activation region
794 - target.pointermove({pointerType, ...coordinates});
795 - target.pointerup({pointerType, ...coordinates});
796 - expect(events).toEqual([
797 - 'onPressStart',
798 - 'onPressChange',
799 - 'onPressMove',
800 - 'onPressEnd',
801 - 'onPressChange',
802 - 'onPress',
803 - ]);
804 - });
805 - });
806 -
807 - describe('beyond bounds of hit rect', () => {
808 - /** ┌──────────────────┐
809 - * │ ┌────────────┐ │
810 - * │ │ VisualRect │ │
811 - * │ └────────────┘ │
812 - * │ HitRect │
813 - * └──────────────────┘
814 - * X <= Move to X and release
815 - */
816 - // @gate experimental
817 - it('"onPress" is not called on release', () => {
818 - componentInit();
819 - const target = createEventTarget(ref.current);
820 - const targetContainer = createEventTarget(container);
821 - target.setBoundingClientRect(rectMock);
822 - target.pointerdown({pointerType});
823 - target.pointermove({pointerType, ...coordinatesInside});
824 - if (pointerType === 'mouse') {
825 - // TODO: use setPointerCapture so this is only true for fallback mouse events.
826 - targetContainer.pointermove({pointerType, ...coordinatesOutside});
827 - targetContainer.pointerup({pointerType, ...coordinatesOutside});
828 - } else {
829 - target.pointermove({pointerType, ...coordinatesOutside});
830 - target.pointerup({pointerType, ...coordinatesOutside});
831 - }
832 - expect(events.filter(removePressMoveStrings)).toEqual([
833 - 'onPressStart',
834 - 'onPressChange',
835 - 'onPressEnd',
836 - 'onPressChange',
837 - ]);
838 - });
839 - });
840 -
841 - // @gate experimental
842 - it('"onPress" is called on re-entry to hit rect', () => {
843 - componentInit();
844 - const target = createEventTarget(ref.current);
845 - const targetContainer = createEventTarget(container);
846 - target.setBoundingClientRect(rectMock);
847 - target.pointerdown({pointerType});
848 - target.pointermove({pointerType, ...coordinatesInside});
849 - if (pointerType === 'mouse') {
850 - // TODO: use setPointerCapture so this is only true for fallback mouse events.
851 - targetContainer.pointermove({pointerType, ...coordinatesOutside});
852 - } else {
853 - target.pointermove({pointerType, ...coordinatesOutside});
854 - }
855 - target.pointermove({pointerType, ...coordinatesInside});
856 - target.pointerup({pointerType, ...coordinatesInside});
857 -
858 - expect(events).toEqual([
859 - 'onPressStart',
860 - 'onPressChange',
861 - 'onPressMove',
862 - 'onPressEnd',
863 - 'onPressChange',
864 - 'onPressStart',
865 - 'onPressChange',
866 - 'onPressEnd',
867 - 'onPressChange',
868 - 'onPress',
869 - ]);
870 - });
871 - });
872 -
873 - describe('nested responders', () => {
874 - if (hasPointerEvents) {
875 - // @gate experimental
876 - it('dispatch events in the correct order', () => {
877 - const events = [];
878 - const ref = React.createRef();
879 - const createEventHandler = msg => () => {
880 - events.push(msg);
881 - };
882 -
883 - const Inner = () => {
884 - const listener = usePress({
885 - onPress: createEventHandler('inner: onPress'),
886 - onPressChange: createEventHandler('inner: onPressChange'),
887 - onPressMove: createEventHandler('inner: onPressMove'),
888 - onPressStart: createEventHandler('inner: onPressStart'),
889 - onPressEnd: createEventHandler('inner: onPressEnd'),
890 - });
891 - return (
892 - <div
893 - ref={ref}
894 - DEPRECATED_flareListeners={listener}
895 - onPointerDown={createEventHandler('pointerdown')}
896 - onPointerUp={createEventHandler('pointerup')}
897 - onKeyDown={createEventHandler('keydown')}
898 - onKeyUp={createEventHandler('keyup')}
899 - />
900 - );
901 - };
902 -
903 - const Outer = () => {
904 - const listener = usePress({
905 - onPress: createEventHandler('outer: onPress'),
906 - onPressChange: createEventHandler('outer: onPressChange'),
907 - onPressMove: createEventHandler('outer: onPressMove'),
908 - onPressStart: createEventHandler('outer: onPressStart'),
909 - onPressEnd: createEventHandler('outer: onPressEnd'),
910 - });
911 - return (
912 - <div DEPRECATED_flareListeners={listener}>
913 - <Inner />
914 - </div>
915 - );
916 - };
917 - ReactDOM.render(<Outer />, container);
918 -
919 - const target = createEventTarget(ref.current);
920 - target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
921 - target.pointerdown();
922 - target.pointerup();
923 - expect(events).toEqual([
924 - 'inner: onPressStart',
925 - 'inner: onPressChange',
926 - 'pointerdown',
927 - 'inner: onPressEnd',
928 - 'inner: onPressChange',
929 - 'inner: onPress',
930 - 'pointerup',
931 - ]);
932 - });
933 - }
934 -
935 - describe('correctly not propagate', () => {
936 - // @gate experimental
937 - it('for onPress', () => {
938 - const ref = React.createRef();
939 - const onPress = jest.fn();
940 -
941 - const Inner = () => {
942 - const listener = usePress({onPress});
943 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
944 - };
945 -
946 - const Outer = () => {
947 - const listener = usePress({onPress});
948 - return (
949 - <div DEPRECATED_flareListeners={listener}>
950 - <Inner />
951 - </div>
952 - );
953 - };
954 - ReactDOM.render(<Outer />, container);
955 -
956 - const target = createEventTarget(ref.current);
957 - target.setBoundingClientRect({x: 0, y: 0, width: 100, height: 100});
958 - target.pointerdown();
959 - target.pointerup();
960 - expect(onPress).toHaveBeenCalledTimes(1);
961 - });
962 -
963 - // @gate experimental
964 - it('for onPressStart/onPressEnd', () => {
965 - const ref = React.createRef();
966 - const onPressStart = jest.fn();
967 - const onPressEnd = jest.fn();
968 -
969 - const Inner = () => {
970 - const listener = usePress({onPressStart, onPressEnd});
971 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
972 - };
973 -
974 - const Outer = () => {
975 - const listener = usePress({onPressStart, onPressEnd});
976 - return (
977 - <div DEPRECATED_flareListeners={listener}>
978 - <Inner />
979 - </div>
980 - );
981 - };
982 - ReactDOM.render(<Outer />, container);
983 -
984 - const target = createEventTarget(ref.current);
985 - target.pointerdown();
986 - expect(onPressStart).toHaveBeenCalledTimes(1);
987 - expect(onPressEnd).toHaveBeenCalledTimes(0);
988 - target.pointerup();
989 - expect(onPressStart).toHaveBeenCalledTimes(1);
990 - expect(onPressEnd).toHaveBeenCalledTimes(1);
991 - });
992 -
993 - // @gate experimental
994 - it('for onPressChange', () => {
995 - const ref = React.createRef();
996 - const onPressChange = jest.fn();
997 -
998 - const Inner = () => {
999 - const listener = usePress({onPressChange});
1000 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
1001 - };
1002 -
1003 - const Outer = () => {
1004 - const listener = usePress({onPressChange});
1005 - return (
1006 - <div DEPRECATED_flareListeners={listener}>
1007 - <Inner />
1008 - </div>
1009 - );
1010 - };
1011 - ReactDOM.render(<Outer />, container);
1012 -
1013 - const target = createEventTarget(ref.current);
1014 - target.pointerdown();
1015 - expect(onPressChange).toHaveBeenCalledTimes(1);
1016 - target.pointerup();
1017 - expect(onPressChange).toHaveBeenCalledTimes(2);
1018 - });
1019 - });
1020 - });
1021 -
1022 - describe('link components', () => {
1023 - // @gate experimental
1024 - it('prevents native behavior by default', () => {
1025 - const onPress = jest.fn();
1026 - const preventDefault = jest.fn();
1027 - const ref = React.createRef();
1028 -
1029 - const Component = () => {
1030 - const listener = usePress({onPress});
1031 - return <a href="#" ref={ref} DEPRECATED_flareListeners={listener} />;
1032 - };
1033 - ReactDOM.render(<Component />, container);
1034 -
1035 - const target = createEventTarget(ref.current);
1036 - target.pointerdown();
1037 - target.pointerup({preventDefault});
1038 - expect(preventDefault).toBeCalled();
1039 - expect(onPress).toHaveBeenCalledWith(
1040 - expect.objectContaining({defaultPrevented: true}),
1041 - );
1042 - });
1043 -
1044 - // @gate experimental
1045 - it('prevents native behaviour for keyboard events by default', () => {
1046 - const onPress = jest.fn();
1047 - const preventDefault = jest.fn();
1048 - const ref = React.createRef();
1049 -
1050 - const Component = () => {
1051 - const listener = usePress({onPress});
1052 - return <a href="#" ref={ref} DEPRECATED_flareListeners={listener} />;
1053 - };
1054 - ReactDOM.render(<Component />, container);
1055 -
1056 - const target = createEventTarget(ref.current);
1057 - target.keydown({key: 'Enter'});
1058 - target.keyup({key: 'Enter'});
1059 - target.click({preventDefault});
1060 - expect(preventDefault).toBeCalled();
1061 - expect(onPress).toHaveBeenCalledWith(
1062 - expect.objectContaining({defaultPrevented: true}),
1063 - );
1064 - });
1065 -
1066 - // @gate experimental
1067 - it('deeply prevents native behaviour by default', () => {
1068 - const onPress = jest.fn();
1069 - const preventDefault = jest.fn();
1070 - const buttonRef = React.createRef();
1071 -
1072 - const Component = () => {
1073 - const listener = usePress({onPress});
1074 - return (
1075 - <a href="#">
1076 - <button ref={buttonRef} DEPRECATED_flareListeners={listener} />
1077 - </a>
1078 - );
1079 - };
1080 - ReactDOM.render(<Component />, container);
1081 -
1082 - const target = createEventTarget(buttonRef.current);
1083 - target.pointerdown();
1084 - target.pointerup({preventDefault});
1085 - expect(preventDefault).toBeCalled();
1086 - });
1087 -
1088 - // @gate experimental
1089 - it('prevents native behaviour by default with nested elements', () => {
1090 - const onPress = jest.fn();
1091 - const preventDefault = jest.fn();
1092 - const ref = React.createRef();
1093 -
1094 - const Component = () => {
1095 - const listener = usePress({onPress});
1096 - return (
1097 - <a href="#" DEPRECATED_flareListeners={listener}>
1098 - <div ref={ref} />
1099 - </a>
1100 - );
1101 - };
1102 - ReactDOM.render(<Component />, container);
1103 -
1104 - const target = createEventTarget(ref.current);
1105 - target.pointerdown();
1106 - target.pointerup({preventDefault});
1107 - expect(preventDefault).toBeCalled();
1108 - expect(onPress).toHaveBeenCalledWith(
1109 - expect.objectContaining({defaultPrevented: true}),
1110 - );
1111 - });
1112 -
1113 - // @gate experimental
1114 - it('uses native behaviour for interactions with modifier keys', () => {
1115 - const onPress = jest.fn();
1116 - const preventDefault = jest.fn();
1117 - const ref = React.createRef();
1118 -
1119 - const Component = () => {
1120 - const listener = usePress({onPress});
1121 - return <a href="#" ref={ref} DEPRECATED_flareListeners={listener} />;
1122 - };
1123 - ReactDOM.render(<Component />, container);
1124 -
1125 - ['metaKey', 'ctrlKey', 'shiftKey'].forEach(modifierKey => {
1126 - const target = createEventTarget(ref.current);
1127 - target.pointerdown({[modifierKey]: true});
1128 - target.pointerup({[modifierKey]: true, preventDefault});
1129 - expect(preventDefault).not.toBeCalled();
1130 - expect(onPress).toHaveBeenCalledWith(
1131 - expect.objectContaining({defaultPrevented: false}),
1132 - );
1133 - });
1134 - });
1135 -
1136 - // @gate experimental
1137 - it('uses native behaviour for pointer events if preventDefault is false', () => {
1138 - const onPress = jest.fn();
1139 - const preventDefault = jest.fn();
1140 - const ref = React.createRef();
1141 -
1142 - const Component = () => {
1143 - const listener = usePress({onPress, preventDefault: false});
1144 - return <a href="#" ref={ref} DEPRECATED_flareListeners={listener} />;
1145 - };
1146 - ReactDOM.render(<Component />, container);
1147 -
1148 - const target = createEventTarget(ref.current);
1149 - target.pointerdown();
1150 - target.pointerup({preventDefault});
1151 - expect(preventDefault).not.toBeCalled();
1152 - expect(onPress).toHaveBeenCalledWith(
1153 - expect.objectContaining({defaultPrevented: false}),
1154 - );
1155 - });
1156 -
1157 - // @gate experimental
1158 - it('uses native behaviour for keyboard events if preventDefault is false', () => {
1159 - const onPress = jest.fn();
1160 - const preventDefault = jest.fn();
1161 - const ref = React.createRef();
1162 -
1163 - const Component = () => {
1164 - const listener = usePress({onPress, preventDefault: false});
1165 - return <a href="#" ref={ref} DEPRECATED_flareListeners={listener} />;
1166 - };
1167 - ReactDOM.render(<Component />, container);
1168 -
1169 - const target = createEventTarget(ref.current);
1170 - target.keydown({key: 'Enter'});
1171 - target.click({preventDefault});
1172 - target.keyup({key: 'Enter'});
1173 - expect(preventDefault).not.toBeCalled();
1174 - expect(onPress).toHaveBeenCalledWith(
1175 - expect.objectContaining({defaultPrevented: false}),
1176 - );
1177 - });
1178 - });
1179 -
1180 - describe('responder cancellation', () => {
1181 - // @gate experimental
1182 - it('ends on pointer cancel: mouse', () => {
1183 - const onPressEnd = jest.fn();
1184 - const ref = React.createRef();
1185 -
1186 - const Component = () => {
1187 - const listener = usePress({onPressEnd});
1188 - return <a href="#" ref={ref} DEPRECATED_flareListeners={listener} />;
1189 - };
1190 - ReactDOM.render(<Component />, container);
1191 -
1192 - const target = createEventTarget(ref.current);
1193 - target.pointerdown({pointerType: 'mouse'});
1194 - target.pointercancel({pointerType: 'mouse'});
1195 - expect(onPressEnd).toHaveBeenCalledTimes(1);
1196 - });
1197 -
1198 - // @gate experimental
1199 - it('ends on pointer cancel: touch', () => {
1200 - const onPressEnd = jest.fn();
1201 - const ref = React.createRef();
1202 -
1203 - const Component = () => {
1204 - const listener = usePress({onPressEnd});
1205 - return <a href="#" ref={ref} DEPRECATED_flareListeners={listener} />;
1206 - };
1207 - ReactDOM.render(<Component />, container);
1208 -
1209 - const target = createEventTarget(ref.current);
1210 - target.pointerdown({pointerType: 'touch'});
1211 - target.pointercancel({pointerType: 'touch'});
1212 - expect(onPressEnd).toHaveBeenCalledTimes(1);
1213 - });
1214 - });
1215 -
1216 - // @gate experimental
1217 - it('does end on "scroll" to document (not mouse)', () => {
1218 - const onPressEnd = jest.fn();
1219 - const ref = React.createRef();
1220 -
1221 - const Component = () => {
1222 - const listener = usePress({onPressEnd});
1223 - return <a href="#" ref={ref} DEPRECATED_flareListeners={listener} />;
1224 - };
1225 - ReactDOM.render(<Component />, container);
1226 -
1227 - const target = createEventTarget(ref.current);
1228 - const targetDocument = createEventTarget(document);
1229 - target.pointerdown({pointerType: 'touch'});
1230 - targetDocument.scroll();
1231 - expect(onPressEnd).toHaveBeenCalledTimes(1);
1232 - });
1233 -
1234 - // @gate experimental
1235 - it('does end on "scroll" to a parent container (not mouse)', () => {
1236 - const onPressEnd = jest.fn();
1237 - const ref = React.createRef();
1238 - const containerRef = React.createRef();
1239 -
1240 - const Component = () => {
1241 - const listener = usePress({onPressEnd});
1242 - return (
1243 - <div ref={containerRef}>
1244 - <a ref={ref} DEPRECATED_flareListeners={listener} />
1245 - </div>
1246 - );
1247 - };
1248 - ReactDOM.render(<Component />, container);
1249 -
1250 - const target = createEventTarget(ref.current);
1251 - const targetContainer = createEventTarget(containerRef.current);
1252 - target.pointerdown({pointerType: 'touch'});
1253 - targetContainer.scroll();
1254 - expect(onPressEnd).toHaveBeenCalledTimes(1);
1255 - });
1256 -
1257 - // @gate experimental
1258 - it('does not end on "scroll" to an element outside', () => {
1259 - const onPressEnd = jest.fn();
1260 - const ref = React.createRef();
1261 - const outsideRef = React.createRef();
1262 -
1263 - const Component = () => {
1264 - const listener = usePress({onPressEnd});
1265 - return (
1266 - <div>
1267 - <a ref={ref} DEPRECATED_flareListeners={listener} />
1268 - <span ref={outsideRef} />
1269 - </div>
1270 - );
1271 - };
1272 - ReactDOM.render(<Component />, container);
1273 -
1274 - const target = createEventTarget(ref.current);
1275 - const targetOutside = createEventTarget(outsideRef.current);
1276 - target.pointerdown();
1277 - targetOutside.scroll();
1278 - expect(onPressEnd).not.toBeCalled();
1279 - });
1280 -
1281 - // @gate experimental
1282 - it('expect displayName to show up for event component', () => {
1283 - expect(PressResponder.displayName).toBe('Press');
1284 - });
1285 -
1286 - // @gate experimental
1287 - it('should not trigger an invariant in addRootEventTypes()', () => {
1288 - const ref = React.createRef();
1289 -
1290 - const Component = () => {
1291 - const listener = usePress();
1292 - return <button ref={ref} DEPRECATED_flareListeners={listener} />;
1293 - };
1294 - ReactDOM.render(<Component />, container);
1295 -
1296 - const target = createEventTarget(ref.current);
1297 - target.pointerdown();
1298 - target.pointermove();
1299 - target.pointerup();
1300 - target.pointerdown();
1301 - });
1302 -
1303 - // @gate experimental
1304 - it('event.preventDefault works as expected', () => {
1305 - const onPress = jest.fn(e => e.preventDefault());
1306 - const onPressStart = jest.fn(e => e.preventDefault());
1307 - const onPressEnd = jest.fn(e => e.preventDefault());
1308 - const preventDefault = jest.fn();
1309 - const buttonRef = React.createRef();
1310 -
1311 - const Component = () => {
1312 - const listener = usePress({onPress, onPressStart, onPressEnd});
1313 - return <button ref={buttonRef} DEPRECATED_flareListeners={listener} />;
1314 - };
1315 - ReactDOM.render(<Component />, container);
1316 -
1317 - const target = createEventTarget(buttonRef.current);
1318 - target.pointerdown();
1319 - target.pointerup({preventDefault});
1320 - expect(preventDefault).toBeCalled();
1321 - expect(onPressStart).toBeCalled();
1322 - expect(onPressEnd).toBeCalled();
1323 - });
1324 -
1325 - // @gate experimental
1326 - it('when blur occurs on a pressed target, we should disengage press', () => {
1327 - const onPress = jest.fn();
1328 - const onPressStart = jest.fn();
1329 - const onPressEnd = jest.fn();
1330 - const buttonRef = React.createRef();
1331 -
1332 - const Component = () => {
1333 - const listener = usePress({onPress, onPressStart, onPressEnd});
1334 - return <button ref={buttonRef} DEPRECATED_flareListeners={listener} />;
1335 - };
1336 - ReactDOM.render(<Component />, container);
1337 -
1338 - const target = createEventTarget(buttonRef.current);
1339 - target.pointerdown();
1340 - expect(onPressStart).toBeCalled();
1341 - target.blur();
1342 - expect(onPressEnd).toBeCalled();
1343 - target.pointerup();
1344 - expect(onPress).not.toBeCalled();
1345 - });
1346 -});
packages/react-interactions/events/src/dom/__tests__/Tap-test.internal.js deleted
-1010
@@ -1,1010 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {
13 - buttonType,
14 - buttonsType,
15 - createEventTarget,
16 - describeWithPointerEvent,
17 - setPointerEvent,
18 - testWithPointerType,
19 - resetActivePointers,
20 -} from 'dom-event-testing-library';
21 -
22 -let React;
23 -let ReactFeatureFlags;
24 -let ReactDOM;
25 -let useTap;
26 -
27 -function initializeModules(hasPointerEvents) {
28 - jest.resetModules();
29 - setPointerEvent(hasPointerEvents);
30 - ReactFeatureFlags = require('shared/ReactFeatureFlags');
31 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
32 - React = require('react');
33 - ReactDOM = require('react-dom');
34 -
35 - // TODO: This import throws outside of experimental mode. Figure out better
36 - // strategy for gated imports.
37 - if (__EXPERIMENTAL__) {
38 - useTap = require('react-interactions/events/tap').useTap;
39 - }
40 -}
41 -
42 -const coordinatesInside = {x: 51, y: 51};
43 -const coordinatesOutside = {x: 49, y: 49};
44 -
45 -function tapAndMoveOutside({
46 - hasPointerEvents,
47 - pointerType,
48 - downTarget,
49 - upTarget,
50 -}) {
51 - downTarget.setBoundingClientRect({width: 100, height: 100, x: 50, y: 50});
52 - downTarget.pointerdown({pointerType, ...coordinatesInside});
53 - downTarget.pointermove({pointerType, ...coordinatesInside});
54 - // NOTE: this assumes the PointerEvent implementation calls
55 - // 'releasePointerCapture' for touch pointers
56 - if (!hasPointerEvents && pointerType === 'touch') {
57 - document.elementFromPoint = () => upTarget.node;
58 - downTarget.pointermove({pointerType, ...coordinatesOutside});
59 - } else {
60 - upTarget.pointermove({pointerType, ...coordinatesOutside});
61 - }
62 -}
63 -
64 -function tapAndReleaseOutside({
65 - hasPointerEvents,
66 - pointerType,
67 - downTarget,
68 - upTarget,
69 -}) {
70 - tapAndMoveOutside({hasPointerEvents, pointerType, downTarget, upTarget});
71 - if (!hasPointerEvents && pointerType === 'touch') {
72 - downTarget.pointerup({pointerType, ...coordinatesOutside});
73 - } else {
74 - upTarget.pointerup({pointerType, ...coordinatesOutside});
75 - }
76 -}
77 -
78 -describeWithPointerEvent('Tap responder', hasPointerEvents => {
79 - let container;
80 -
81 - beforeEach(() => {
82 - initializeModules(hasPointerEvents);
83 - container = document.createElement('div');
84 - document.body.appendChild(container);
85 - });
86 -
87 - afterEach(() => {
88 - ReactDOM.render(null, container);
89 - document.body.removeChild(container);
90 - container = null;
91 - resetActivePointers();
92 - });
93 -
94 - // @gate experimental
95 - test('supports repeated use', () => {
96 - const ref = React.createRef();
97 - const Component = () => {
98 - const listener = useTap();
99 - return <button ref={ref} DEPRECATED_flareListeners={listener} />;
100 - };
101 - ReactDOM.render(<Component />, container);
102 -
103 - const target = createEventTarget(ref.current);
104 - function interact() {
105 - target.pointerdown();
106 - target.pointermove();
107 - target.pointerup();
108 - }
109 - expect(() => {
110 - interact();
111 - interact();
112 - }).not.toThrow();
113 - });
114 -
115 - describe('disabled', () => {
116 - let onTapStart, onTapChange, onTapUpdate, onTapCancel, onTapEnd, ref;
117 -
118 - const componentInit = () => {
119 - onTapStart = jest.fn();
120 - onTapChange = jest.fn();
121 - onTapUpdate = jest.fn();
122 - onTapCancel = jest.fn();
123 - onTapEnd = jest.fn();
124 - ref = React.createRef();
125 - const Component = () => {
126 - const listener = useTap({
127 - disabled: true,
128 - onTapStart,
129 - onTapChange,
130 - onTapUpdate,
131 - onTapCancel,
132 - onTapEnd,
133 - });
134 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
135 - };
136 - ReactDOM.render(<Component />, container);
137 - };
138 -
139 - // @gate experimental
140 - test('does not call callbacks', () => {
141 - componentInit();
142 - const target = createEventTarget(ref.current);
143 - target.pointerdown();
144 - target.pointerup();
145 - expect(onTapStart).not.toBeCalled();
146 - expect(onTapChange).not.toBeCalled();
147 - expect(onTapUpdate).not.toBeCalled();
148 - expect(onTapCancel).not.toBeCalled();
149 - expect(onTapEnd).not.toBeCalled();
150 - });
151 - });
152 -
153 - describe('maximumDistance', () => {
154 - let onTapCancel, onTapUpdate, ref;
155 -
156 - function render(props) {
157 - const Component = () => {
158 - const listener = useTap(props);
159 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
160 - };
161 - ReactDOM.render(<Component />, container);
162 - document.elementFromPoint = () => ref.current;
163 - }
164 -
165 - const componentInit = () => {
166 - onTapCancel = jest.fn();
167 - onTapUpdate = jest.fn();
168 - ref = React.createRef();
169 - render({
170 - maximumDistance: 20,
171 - onTapCancel,
172 - onTapUpdate,
173 - });
174 - };
175 -
176 - // @gate experimental
177 - test('ignores values less than 10', () => {
178 - componentInit();
179 - render({
180 - maximumDistance: 5,
181 - onTapCancel,
182 - onTapUpdate,
183 - });
184 - const target = createEventTarget(ref.current);
185 - const pointerType = 'mouse';
186 - target.pointerdown({pointerType, x: 0, y: 0});
187 - target.pointermove({pointerType, x: 10, y: 10});
188 - expect(onTapUpdate).toHaveBeenCalledTimes(1);
189 - expect(onTapCancel).toHaveBeenCalledTimes(0);
190 - });
191 -
192 - // TODO: Get rid of this condition somehow. Perhaps with a dynamic version
193 - // of the @gate pragma.
194 - if (__EXPERIMENTAL__) {
195 - testWithPointerType('below threshold', pointerType => {
196 - componentInit();
197 - const target = createEventTarget(ref.current);
198 - target.pointerdown({pointerType, x: 0, y: 0});
199 - target.pointermove({pointerType, x: 10, y: 10});
200 - expect(onTapUpdate).toHaveBeenCalledTimes(1);
201 - expect(onTapCancel).toHaveBeenCalledTimes(0);
202 - });
203 -
204 - testWithPointerType('above threshold', pointerType => {
205 - componentInit();
206 - const target = createEventTarget(ref.current);
207 - target.pointerdown({pointerType, x: 0, y: 0});
208 - target.pointermove({pointerType, x: 15, y: 14});
209 - expect(onTapUpdate).toHaveBeenCalledTimes(0);
210 - expect(onTapCancel).toHaveBeenCalledTimes(1);
211 - });
212 - }
213 - });
214 -
215 - describe('onAuxiliaryTap', () => {
216 - let onAuxiliaryTap, ref;
217 -
218 - const componentInit = () => {
219 - onAuxiliaryTap = jest.fn();
220 - ref = React.createRef();
221 - const Component = () => {
222 - const listener = useTap({onAuxiliaryTap});
223 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
224 - };
225 - ReactDOM.render(<Component />, container);
226 - document.elementFromPoint = () => ref.current;
227 - };
228 -
229 - // @gate experimental
230 - test('auxiliary-button pointer up', () => {
231 - componentInit();
232 - const pointerType = 'mouse';
233 - const button = buttonType.auxiliary;
234 - const buttons = buttonsType.auxiliary;
235 - const target = createEventTarget(ref.current);
236 - target.pointerdown({button, buttons, pointerType});
237 - target.pointerup({button, buttons, pointerType});
238 - expect(onAuxiliaryTap).toHaveBeenCalledTimes(1);
239 - });
240 -
241 - // @gate experimental
242 - test('modifier-button pointer up', () => {
243 - componentInit();
244 - const pointerType = 'mouse';
245 - const button = buttonType.primary;
246 - const buttons = buttonsType.primary;
247 - const target = createEventTarget(ref.current);
248 - target.pointerdown({button, buttons, pointerType});
249 - target.pointerup({button, buttons, metaKey: true, pointerType});
250 - expect(onAuxiliaryTap).toHaveBeenCalledTimes(1);
251 - });
252 - });
253 -
254 - describe('onTapStart', () => {
255 - let onTapStart, ref;
256 -
257 - const componentInit = () => {
258 - onTapStart = jest.fn();
259 - ref = React.createRef();
260 - const Component = () => {
261 - const listener = useTap({onTapStart});
262 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
263 - };
264 - ReactDOM.render(<Component />, container);
265 - document.elementFromPoint = () => ref.current;
266 - };
267 -
268 - // TODO: Get rid of this condition somehow. Perhaps with a dynamic version
269 - // of the @gate pragma.
270 - if (__EXPERIMENTAL__) {
271 - testWithPointerType('pointer down', pointerType => {
272 - componentInit();
273 - const target = createEventTarget(ref.current);
274 - const nativeEvent = {
275 - button: buttonType.primary,
276 - buttons: buttonsType.primary,
277 - pageX: 10,
278 - pageY: 10,
279 - pointerType,
280 - x: 10,
281 - y: 10,
282 - };
283 - target.pointerdown(nativeEvent);
284 - // 'pointerup' is only for the MouseEvent/TouchEvent fallback
285 - // implementation. We also dispatch 'pointerup' so that this test covers
286 - // the case where browsers dispatch an emulated mousedown (and mouseup)
287 - // event *after* a touch ends.
288 - target.pointerup(nativeEvent);
289 - expect(onTapStart).toHaveBeenCalledTimes(1);
290 - expect(onTapStart).toHaveBeenCalledWith(
291 - expect.objectContaining({
292 - altKey: false,
293 - ctrlKey: false,
294 - height: pointerType === 'mouse' ? 1 : 23,
295 - metaKey: false,
296 - pageX: 10,
297 - pageY: 10,
298 - pointerType,
299 - pressure: pointerType === 'touch' ? 1 : 0.5,
300 - screenX: 10,
301 - screenY: 60,
302 - shiftKey: false,
303 - tangentialPressure: 0,
304 - target: target.node,
305 - tiltX: 0,
306 - tiltY: 0,
307 - timeStamp: expect.any(Number),
308 - twist: 0,
309 - type: 'tap:start',
310 - width: pointerType === 'mouse' ? 1 : 23,
311 - x: 10,
312 - y: 10,
313 - }),
314 - );
315 - });
316 - }
317 -
318 - // @gate experimental
319 - test('second pointer on target', () => {
320 - componentInit();
321 - const pointerType = 'touch';
322 - const target = createEventTarget(ref.current);
323 - const button = buttonType.primary;
324 - const buttons = buttonsType.primary;
325 - target.pointerdown({button, buttons, pointerId: 1, pointerType});
326 - expect(onTapStart).toHaveBeenCalledTimes(1);
327 - target.pointerdown({button, buttons, pointerId: 2, pointerType});
328 - expect(onTapStart).toHaveBeenCalledTimes(1);
329 - });
330 -
331 - // TODO: Get rid of this condition somehow. Perhaps with a dynamic version
332 - // of the @gate pragma.
333 - if (__EXPERIMENTAL__) {
334 - testWithPointerType('ignored buttons and modifiers', pointerType => {
335 - componentInit();
336 - const target = createEventTarget(ref.current);
337 - if (pointerType !== 'touch') {
338 - // right-click
339 - target.pointerdown({
340 - button: buttonType.secondary,
341 - buttons: buttonsType.secondary,
342 - pointerType,
343 - });
344 - target.pointerup({pointerType});
345 - // middle-click
346 - target.pointerdown({
347 - button: buttonType.auxiliary,
348 - buttons: buttonsType.auxiliary,
349 - pointerType,
350 - });
351 - target.pointerup({pointerType});
352 - // virtual middle-click with misleading 'buttons' value
353 - target.pointerdown({
354 - button: buttonType.auxiliary,
355 - buttons: 0,
356 - pointerType,
357 - });
358 - target.pointerup({pointerType});
359 - // pen eraser
360 - target.pointerdown({
361 - button: buttonType.eraser,
362 - buttons: buttonsType.eraser,
363 - pointerType,
364 - });
365 - target.pointerup({pointerType});
366 - }
367 - // alt-click
368 - target.pointerdown({
369 - button: buttonType.primary,
370 - buttons: buttonsType.primary,
371 - altKey: true,
372 - pointerType,
373 - });
374 - target.pointerup({pointerType});
375 - // ctrl-click
376 - target.pointerdown({
377 - button: buttonType.primary,
378 - buttons: buttonsType.primary,
379 - ctrlKey: true,
380 - pointerType,
381 - });
382 - target.pointerup({pointerType});
383 - // meta-click
384 - target.pointerdown({
385 - button: buttonType.primary,
386 - buttons: buttonsType.primary,
387 - metaKey: true,
388 - pointerType,
389 - });
390 - target.pointerup({pointerType});
391 - // shift-click
392 - target.pointerdown({
393 - button: buttonType.primary,
394 - buttons: buttonsType.primary,
395 - shiftKey: true,
396 - pointerType,
397 - });
398 - target.pointerup({pointerType});
399 -
400 - expect(onTapStart).toHaveBeenCalledTimes(0);
401 - });
402 - }
403 - });
404 -
405 - describe('onTapEnd', () => {
406 - let onTapEnd, ref;
407 -
408 - const componentInit = () => {
409 - onTapEnd = jest.fn();
410 - ref = React.createRef();
411 - const Component = () => {
412 - const listener = useTap({onTapEnd});
413 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
414 - };
415 - ReactDOM.render(<Component />, container);
416 - document.elementFromPoint = () => ref.current;
417 - };
418 -
419 - // TODO: Get rid of this condition somehow. Perhaps with a dynamic version
420 - // of the @gate pragma.
421 - if (__EXPERIMENTAL__) {
422 - testWithPointerType('pointer up', pointerType => {
423 - componentInit();
424 - const target = createEventTarget(ref.current);
425 - const button = buttonType.primary;
426 - const buttons = buttonsType.primary;
427 - target.pointerdown({button, buttons, pointerType});
428 - target.pointerup({
429 - button,
430 - buttons,
431 - pageX: 10,
432 - pageY: 10,
433 - pointerType,
434 - x: 10,
435 - y: 10,
436 - });
437 - expect(onTapEnd).toHaveBeenCalledTimes(1);
438 - expect(onTapEnd).toHaveBeenCalledWith(
439 - expect.objectContaining({
440 - altKey: false,
441 - ctrlKey: false,
442 - height: pointerType === 'mouse' ? 1 : 23,
443 - metaKey: false,
444 - pageX: 10,
445 - pageY: 10,
446 - pointerType,
447 - pressure: 0,
448 - screenX: 10,
449 - screenY: 60,
450 - shiftKey: false,
451 - tangentialPressure: 0,
452 - target: target.node,
453 - tiltX: 0,
454 - tiltY: 0,
455 - timeStamp: expect.any(Number),
456 - twist: 0,
457 - type: 'tap:end',
458 - width: pointerType === 'mouse' ? 1 : 23,
459 - x: 10,
460 - y: 10,
461 - }),
462 - );
463 - });
464 -
465 - testWithPointerType('zero-dimension hit rect', pointerType => {
466 - componentInit();
467 - const targetRef = React.createRef();
468 - const innerRef = React.createRef();
469 -
470 - const Component = () => {
471 - const listener = useTap({onTapEnd});
472 - return (
473 - <div ref={targetRef} DEPRECATED_flareListeners={listener}>
474 - <button ref={innerRef} />
475 - </div>
476 - );
477 - };
478 - ReactDOM.render(<Component />, container);
479 - document.elementFromPoint = () => innerRef.current;
480 -
481 - const target = createEventTarget(targetRef.current);
482 - target.setBoundingClientRect({x: 0, y: 0, width: 0, height: 0});
483 - const innerTarget = createEventTarget(innerRef.current);
484 - innerTarget.pointerdown({pointerType});
485 - innerTarget.pointerup({pointerType});
486 - expect(onTapEnd).toBeCalled();
487 - });
488 -
489 - testWithPointerType('pointer up outside target', pointerType => {
490 - componentInit();
491 - const downTarget = createEventTarget(ref.current);
492 - const upTarget = createEventTarget(container);
493 - tapAndReleaseOutside({
494 - hasPointerEvents,
495 - downTarget,
496 - upTarget,
497 - pointerType,
498 - });
499 - expect(onTapEnd).not.toBeCalled();
500 - });
501 - }
502 -
503 - if (hasPointerEvents) {
504 - // @gate experimental
505 - test('second pointer up off target', () => {
506 - componentInit();
507 - const pointerType = 'touch';
508 - const target = createEventTarget(ref.current);
509 - const offTarget = createEventTarget(container);
510 - const button = buttonType.primary;
511 - const buttons = buttonsType.primary;
512 -
513 - target.pointerdown({button, buttons, pointerId: 1, pointerType});
514 - offTarget.pointerdown({button, buttons, pointerId: 2, pointerType});
515 - offTarget.pointerup({
516 - button,
517 - buttons,
518 - pageX: 10,
519 - pageY: 10,
520 - pointerId: 2,
521 - pointerType,
522 - x: 10,
523 - y: 10,
524 - });
525 - expect(onTapEnd).toHaveBeenCalledTimes(0);
526 - });
527 - }
528 -
529 - // @gate experimental
530 - test('ignored buttons and modifiers', () => {
531 - componentInit();
532 - const target = createEventTarget(ref.current);
533 - // right-click
534 - target.pointerdown({
535 - button: buttonType.secondary,
536 - buttons: buttonsType.secondary,
537 - });
538 - target.pointerup({
539 - button: buttonType.secondary,
540 - buttons: buttonsType.secondary,
541 - });
542 - // middle-click
543 - target.pointerdown({
544 - button: buttonType.auxiliary,
545 - buttons: buttonsType.auxiliary,
546 - });
547 - target.pointerup({
548 - button: buttonType.auxiliary,
549 - buttons: buttonsType.auxiliary,
550 - });
551 - // pen eraser
552 - target.pointerdown({
553 - button: buttonType.eraser,
554 - buttons: buttonsType.eraser,
555 - });
556 - target.pointerup({
557 - button: buttonType.eraser,
558 - buttons: buttonsType.eraser,
559 - });
560 - // alt-click
561 - target.pointerdown({
562 - button: buttonType.primary,
563 - buttons: buttonsType.primary,
564 - });
565 - target.pointerup({altKey: true, button: buttonType.primary});
566 - // ctrl-click
567 - target.pointerdown({
568 - button: buttonType.primary,
569 - buttons: buttonsType.primary,
570 - });
571 - target.pointerup({ctrlKey: true, button: buttonType.primary});
572 - // meta-click
573 - target.pointerdown({
574 - button: buttonType.primary,
575 - buttons: buttonsType.primary,
576 - });
577 - target.pointerup({metaKey: true, button: buttonType.primary});
578 - // shift-click
579 - target.pointerdown({
580 - button: buttonType.primary,
581 - buttons: buttonsType.primary,
582 - });
583 - target.pointerup({shiftKey: true, button: buttonType.primary});
584 -
585 - expect(onTapEnd).toHaveBeenCalledTimes(0);
586 - });
587 - });
588 -
589 - describe('onTapUpdate', () => {
590 - let onTapUpdate, ref;
591 - const rect = {x: 0, y: 0, width: 100, height: 100};
592 - const coordinates = {x: 10, y: 10};
593 -
594 - const componentInit = () => {
595 - onTapUpdate = jest.fn();
596 - ref = React.createRef();
597 - const Component = () => {
598 - const listener = useTap({onTapUpdate});
599 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
600 - };
601 - ReactDOM.render(<Component />, container);
602 - document.elementFromPoint = () => ref.current;
603 - };
604 -
605 - // TODO: Get rid of this condition somehow. Perhaps with a dynamic version
606 - // of the @gate pragma.
607 - if (__EXPERIMENTAL__) {
608 - testWithPointerType('requires activation', pointerType => {
609 - componentInit();
610 - const target = createEventTarget(ref.current);
611 - target.setBoundingClientRect(rect);
612 - if (pointerType !== 'touch') {
613 - target.pointerhover({pointerType, ...coordinates});
614 - target.pointermove({pointerType, ...coordinates});
615 - }
616 - expect(onTapUpdate).not.toBeCalled();
617 - });
618 -
619 - testWithPointerType('pointer move', pointerType => {
620 - componentInit();
621 - const target = createEventTarget(ref.current);
622 - target.setBoundingClientRect(rect);
623 - target.pointerdown({pointerType});
624 -
625 - target.pointermove({pointerType, x: 10, y: 10});
626 - expect(onTapUpdate).toHaveBeenCalledWith(
627 - expect.objectContaining({
628 - altKey: false,
629 - ctrlKey: false,
630 - height: pointerType === 'mouse' ? 1 : 23,
631 - metaKey: false,
632 - pageX: 10,
633 - pageY: 10,
634 - pointerType,
635 - pressure: pointerType === 'touch' ? 1 : 0.5,
636 - screenX: 10,
637 - screenY: 60,
638 - shiftKey: false,
639 - tangentialPressure: 0,
640 - target: target.node,
641 - tiltX: 0,
642 - tiltY: 0,
643 - timeStamp: expect.any(Number),
644 - twist: 0,
645 - type: 'tap:update',
646 - width: pointerType === 'mouse' ? 1 : 23,
647 - x: 10,
648 - y: 10,
649 - }),
650 - );
651 -
652 - target.pointermove({pointerType, x: 20, y: 20});
653 - expect(onTapUpdate).toHaveBeenCalledWith(
654 - expect.objectContaining({pointerType, x: 20, y: 20}),
655 - );
656 -
657 - expect(onTapUpdate).toHaveBeenCalledTimes(2);
658 - });
659 -
660 - testWithPointerType('pointer moves outside target', pointerType => {
661 - componentInit();
662 - const target = createEventTarget(ref.current);
663 - const containerTarget = createEventTarget(container);
664 - target.setBoundingClientRect(rect);
665 - target.pointerdown({pointerType});
666 - target.pointermove({pointerType, x: 10, y: 10});
667 - expect(onTapUpdate).toHaveBeenCalledTimes(1);
668 -
669 - // NOTE: this assumes the PointerEvent implementation calls
670 - // 'releasePointerCapture' for touch pointers
671 - if (!hasPointerEvents && pointerType === 'touch') {
672 - document.elementFromPoint = () => containerTarget.node;
673 - target.pointermove({pointerType, x: 101, y: 101});
674 - } else {
675 - containerTarget.pointermove({pointerType, x: 101, y: 101});
676 - }
677 -
678 - // No extra 'onTapUpdate' calls when the pointer is outside the target
679 - expect(onTapUpdate).toHaveBeenCalledTimes(1);
680 - });
681 - }
682 -
683 - if (hasPointerEvents) {
684 - // @gate experimental
685 - test('second pointer off target', () => {
686 - componentInit();
687 - const pointerType = 'touch';
688 - const target = createEventTarget(ref.current);
689 - const offTarget = createEventTarget(container);
690 - const button = buttonType.primary;
691 - const buttons = buttonsType.primary;
692 - target.pointerdown({button, buttons, pointerId: 1, pointerType});
693 - offTarget.pointerdown({button, buttons, pointerId: 2, pointerType});
694 - target.pointermove({pointerId: 1, pointerType, x: 10, y: 10});
695 - expect(onTapUpdate).toHaveBeenCalledTimes(1);
696 - offTarget.pointermove({pointerId: 2, pointerType, x: 10, y: 10});
697 - expect(onTapUpdate).toHaveBeenCalledTimes(1);
698 - });
699 - }
700 - });
701 -
702 - describe('onTapChange', () => {
703 - let eventsLog, onTapChange, ref;
704 -
705 - const logger = msg => () => {
706 - eventsLog.push(msg);
707 - };
708 -
709 - const componentInit = () => {
710 - eventsLog = [];
711 - onTapChange = jest.fn();
712 - ref = React.createRef();
713 - const Component = () => {
714 - const listener = useTap({
715 - onTapChange(e) {
716 - logger('change')();
717 - onTapChange(e);
718 - },
719 - onTapStart: logger('start'),
720 - onTapEnd: logger('end'),
721 - onTapCancel: logger('cancel'),
722 - });
723 - return <div ref={ref} DEPRECATED_flareListeners={listener} />;
724 - };
725 - ReactDOM.render(<Component />, container);
726 - document.elementFromPoint = () => ref.current;
727 - };
728 -
729 - // TODO: Get rid of this condition somehow. Perhaps with a dynamic version
730 - // of the @gate pragma.
731 - if (__EXPERIMENTAL__) {
732 - testWithPointerType('pointer down/up', pointerType => {
733 - componentInit();
734 - const target = createEventTarget(ref.current);
735 - target.pointerdown({pointerType});
736 - expect(onTapChange).toHaveBeenCalledTimes(1);
737 - expect(onTapChange).toHaveBeenCalledWith(true);
738 - target.pointerup({pointerType, x: 0, y: 0});
739 - expect(onTapChange).toHaveBeenCalledTimes(2);
740 - expect(onTapChange).toHaveBeenCalledWith(false);
741 - expect(eventsLog).toEqual(['start', 'change', 'change', 'end']);
742 - });
743 -
744 - testWithPointerType('pointer cancel', pointerType => {
745 - componentInit();
746 - const target = createEventTarget(ref.current);
747 - target.pointerdown({pointerType});
748 - expect(onTapChange).toHaveBeenCalledTimes(1);
749 - expect(onTapChange).toHaveBeenCalledWith(true);
750 - target.pointercancel({pointerType});
751 - expect(onTapChange).toHaveBeenCalledTimes(2);
752 - expect(onTapChange).toHaveBeenCalledWith(false);
753 - expect(eventsLog).toEqual(['start', 'change', 'change', 'cancel']);
754 - });
755 -
756 - testWithPointerType('pointer move outside target', pointerType => {
757 - componentInit();
758 - const downTarget = createEventTarget(ref.current);
759 - const upTarget = createEventTarget(container);
760 - tapAndMoveOutside({
761 - hasPointerEvents,
762 - downTarget,
763 - upTarget,
764 - pointerType,
765 - });
766 - expect(onTapChange).toHaveBeenCalledTimes(2);
767 - });
768 - }
769 - });
770 -
771 - describe('onTapCancel', () => {
772 - let onTapCancel, onTapUpdate, parentRef, ref, siblingRef;
773 -
774 - const componentInit = () => {
775 - onTapCancel = jest.fn();
776 - onTapUpdate = jest.fn();
777 - parentRef = React.createRef();
778 - ref = React.createRef();
779 - siblingRef = React.createRef();
780 - const Component = () => {
781 - const listener = useTap({onTapCancel, onTapUpdate});
782 - return (
783 - <div ref={parentRef}>
784 - <div ref={ref} DEPRECATED_flareListeners={listener} />
785 - <span ref={siblingRef} />
786 - </div>
787 - );
788 - };
789 - ReactDOM.render(<Component />, container);
790 - };
791 -
792 - // TODO: Get rid of this condition somehow. Perhaps with a dynamic version
793 - // of the @gate pragma.
794 - if (__EXPERIMENTAL__) {
795 - testWithPointerType('pointer cancel', pointerType => {
796 - componentInit();
797 - const target = createEventTarget(ref.current);
798 - target.pointerdown({pointerType});
799 - target.pointercancel({pointerType});
800 - expect(onTapCancel).toHaveBeenCalledTimes(1);
801 - expect(onTapCancel).toHaveBeenCalledWith(
802 - expect.objectContaining({
803 - altKey: false,
804 - ctrlKey: false,
805 - height: 1,
806 - metaKey: false,
807 - pageX: 0,
808 - pageY: 0,
809 - pointerType,
810 - pressure: 0,
811 - screenX: 0,
812 - screenY: 0,
813 - shiftKey: false,
814 - tangentialPressure: 0,
815 - target: target.node,
816 - tiltX: 0,
817 - tiltY: 0,
818 - timeStamp: expect.any(Number),
819 - twist: 0,
820 - type: 'tap:cancel',
821 - width: 1,
822 - x: 0,
823 - y: 0,
824 - }),
825 - );
826 - target.pointermove({pointerType, x: 5, y: 5});
827 - expect(onTapUpdate).not.toBeCalled();
828 - });
829 - }
830 -
831 - // @gate experimental
832 - test('second pointer on target', () => {
833 - componentInit();
834 - const pointerType = 'touch';
835 - const target = createEventTarget(ref.current);
836 - const button = buttonType.primary;
837 - const buttons = buttonsType.primary;
838 - target.pointerdown({button, buttons, pointerId: 1, pointerType});
839 - target.pointerdown({button, buttons, pointerId: 2, pointerType});
840 - expect(onTapCancel).toHaveBeenCalledTimes(1);
841 - });
842 -
843 - if (hasPointerEvents) {
844 - // @gate experimental
845 - test('second pointer off target', () => {
846 - componentInit();
847 - const pointerType = 'touch';
848 - const target = createEventTarget(ref.current);
849 - const offTarget = createEventTarget(container);
850 - const button = buttonType.primary;
851 - const buttons = buttonsType.primary;
852 - target.pointerdown({button, buttons, pointerId: 1, pointerType});
853 - offTarget.pointerdown({button, buttons, pointerId: 2, pointerType});
854 - expect(onTapCancel).toHaveBeenCalledTimes(0);
855 - });
856 - }
857 -
858 - // TODO: Get rid of this condition somehow. Perhaps with a dynamic version
859 - // of the @gate pragma.
860 - if (__EXPERIMENTAL__) {
861 - testWithPointerType('pointer move outside target', pointerType => {
862 - componentInit();
863 - const downTarget = createEventTarget(ref.current);
864 - const upTarget = createEventTarget(container);
865 - tapAndMoveOutside({
866 - hasPointerEvents,
867 - downTarget,
868 - upTarget,
869 - pointerType,
870 - });
871 - expect(onTapCancel).toBeCalled();
872 - });
873 - }
874 -
875 - // @gate experimental
876 - test('ignored modifiers', () => {
877 - componentInit();
878 - const target = createEventTarget(ref.current);
879 - const button = buttonType.primary;
880 - const buttons = buttonsType.primary;
881 - // alt-click
882 - target.pointerdown({button, buttons});
883 - target.pointerup({altKey: true, button});
884 - // ctrl-click
885 - target.pointerdown({button, buttons});
886 - target.pointerup({ctrlKey: true, button});
887 - // meta-click
888 - target.pointerdown({button, buttons});
889 - target.pointerup({metaKey: true, button});
890 - // shift-click
891 - target.pointerdown({buttons});
892 - target.pointerup({shiftKey: true, button});
893 -
894 - expect(onTapCancel).toHaveBeenCalledTimes(4);
895 - });
896 -
897 - // @gate experimental
898 - test('long press context menu', () => {
899 - componentInit();
900 - const target = createEventTarget(ref.current);
901 - target.contextmenu({}, {pointerType: 'touch'});
902 - expect(onTapCancel).toHaveBeenCalledTimes(1);
903 - });
904 -
905 - // @gate experimental
906 - test('parent scroll (non-mouse)', () => {
907 - componentInit();
908 - const target = createEventTarget(ref.current);
909 - const parentTarget = createEventTarget(parentRef.current);
910 - target.pointerdown({pointerType: 'touch'});
911 - parentTarget.scroll();
912 - expect(onTapCancel).toHaveBeenCalledTimes(1);
913 - });
914 -
915 - // @gate experimental
916 - test('sibling scroll', () => {
917 - componentInit();
918 - const target = createEventTarget(ref.current);
919 - const siblingTarget = createEventTarget(siblingRef.current);
920 - target.pointerdown();
921 - siblingTarget.scroll();
922 - expect(onTapCancel).not.toBeCalled();
923 - });
924 -
925 - // @gate experimental
926 - test('document scroll (non-mouse)', () => {
927 - componentInit();
928 - const target = createEventTarget(ref.current);
929 - const documentTarget = createEventTarget(document);
930 - target.pointerdown({pointerType: 'touch'});
931 - documentTarget.scroll();
932 - expect(onTapCancel).toHaveBeenCalledTimes(1);
933 - });
934 -
935 - // Scroll on an element not managed by React
936 - // @gate experimental
937 - test('root container scroll (non-mouse)', () => {
938 - componentInit();
939 - const target = createEventTarget(ref.current);
940 - const containerTarget = createEventTarget(container);
941 - target.pointerdown({pointerType: 'touch'});
942 - containerTarget.scroll();
943 - expect(onTapCancel).toHaveBeenCalledTimes(1);
944 - });
945 - });
946 -
947 - describe('preventDefault', () => {
948 - let onTapEnd, ref, innerRef, preventDefault, remount;
949 -
950 - const componentInit = () => {
951 - remount = function(shouldPreventDefault) {
952 - onTapEnd = jest.fn();
953 - preventDefault = jest.fn();
954 - ref = React.createRef();
955 - innerRef = React.createRef();
956 - const Component = () => {
957 - const listener = useTap({
958 - onTapEnd,
959 - preventDefault: shouldPreventDefault,
960 - });
961 - return (
962 - <a href="#" ref={ref} DEPRECATED_flareListeners={listener}>
963 - <div ref={innerRef} />
964 - </a>
965 - );
966 - };
967 - ReactDOM.render(<Component />, container);
968 - };
969 - remount();
970 - };
971 -
972 - // @gate experimental
973 - test('prevents native behavior by default', () => {
974 - componentInit();
975 - const target = createEventTarget(ref.current);
976 - target.pointerdown();
977 - target.pointerup({preventDefault});
978 - expect(preventDefault).toBeCalled();
979 - expect(onTapEnd).toHaveBeenCalledWith(
980 - expect.objectContaining({defaultPrevented: true}),
981 - );
982 - });
983 -
984 - // @gate experimental
985 - test('prevents native behaviour by default (inner target)', () => {
986 - componentInit();
987 - const innerTarget = createEventTarget(innerRef.current);
988 - innerTarget.pointerdown();
989 - innerTarget.pointerup({preventDefault});
990 - expect(preventDefault).toBeCalled();
991 - expect(onTapEnd).toHaveBeenCalledWith(
992 - expect.objectContaining({defaultPrevented: true}),
993 - );
994 - });
995 -
996 - // @gate experimental
997 - test('allows native behaviour if false', () => {
998 - componentInit();
999 - remount(false);
1000 -
1001 - const target = createEventTarget(ref.current);
1002 - target.pointerdown();
1003 - target.pointerup({preventDefault});
1004 - expect(preventDefault).not.toBeCalled();
1005 - expect(onTapEnd).toHaveBeenCalledWith(
1006 - expect.objectContaining({defaultPrevented: false}),
1007 - );
1008 - });
1009 - });
1010 -});
packages/react-interactions/events/src/dom/shared/index.js deleted
-87
@@ -1,87 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @emails react-core
8 - */
9 -
10 -'use strict';
11 -
12 -import {DiscreteEvent, UserBlockingEvent} from 'shared/ReactTypes';
13 -import type {
14 - ReactDOMResponderContext,
15 - ReactDOMResponderEvent,
16 -} from 'react-dom/src/shared/ReactDOMTypes';
17 -
18 -export const hasPointerEvents =
19 - typeof window !== 'undefined' && window.PointerEvent !== undefined;
20 -
21 -export const isMac =
22 - typeof window !== 'undefined' && window.navigator != null
23 - ? /^Mac/.test(window.navigator.platform)
24 - : false;
25 -
26 -export const buttonsEnum = {
27 - none: 0,
28 - primary: 1,
29 - secondary: 2,
30 - auxiliary: 4,
31 -};
32 -
33 -export function dispatchDiscreteEvent(
34 - context: ReactDOMResponderContext,
35 - payload: ReactDOMResponderEvent,
36 - callback: any => void,
37 -) {
38 - context.dispatchEvent(payload, callback, DiscreteEvent);
39 -}
40 -
41 -export function dispatchUserBlockingEvent(
42 - context: ReactDOMResponderContext,
43 - payload: ReactDOMResponderEvent,
44 - callback: any => void,
45 -) {
46 - context.dispatchEvent(payload, callback, UserBlockingEvent);
47 -}
48 -
49 -export function getTouchById(
50 - nativeEvent: TouchEvent,
51 - pointerId: null | number,
52 -): null | Touch {
53 - if (pointerId != null) {
54 - const changedTouches = nativeEvent.changedTouches;
55 - for (let i = 0; i < changedTouches.length; i++) {
56 - const touch = changedTouches[i];
57 - if (touch.identifier === pointerId) {
58 - return touch;
59 - }
60 - }
61 - return null;
62 - }
63 - return null;
64 -}
65 -
66 -export function hasModifierKey(event: ReactDOMResponderEvent): boolean {
67 - const nativeEvent: any = event.nativeEvent;
68 - const {altKey, ctrlKey, metaKey, shiftKey} = nativeEvent;
69 - return (
70 - altKey === true || ctrlKey === true || metaKey === true || shiftKey === true
71 - );
72 -}
73 -
74 -// Keyboards, Assitive Technologies, and element.click() all produce a "virtual"
75 -// click event. This is a method of inferring such clicks. Every browser except
76 -// IE 11 only sets a zero value of "detail" for click events that are "virtual".
77 -// However, IE 11 uses a zero value for all click events. For IE 11 we rely on
78 -// the quirk that it produces click events that are of type PointerEvent, and
79 -// where only the "virtual" click lacks a pointerType field.
80 -export function isVirtualClick(event: ReactDOMResponderEvent): boolean {
81 - const nativeEvent: any = event.nativeEvent;
82 - // JAWS/NVDA with Firefox.
83 - if (nativeEvent.mozInputSource === 0 && nativeEvent.isTrusted) {
84 - return true;
85 - }
86 - return nativeEvent.detail === 0 && !nativeEvent.pointerType;
87 -}
packages/react-interactions/events/tap.js deleted
-10
@@ -1,10 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -export * from './src/dom/Tap';
packages/react-native-renderer/src/ReactFabricHostConfig.js
-16
@@ -435,22 +435,6 @@ export function replaceContainerChildren(
435 newChildren: ChildSet,
436 ): void {}
437
438 -export function DEPRECATED_mountResponderInstance(
439 - responder: any,
440 - responderInstance: any,
441 - props: Object,
442 - state: Object,
443 - instance: Instance,
444 -) {
445 - throw new Error('Not yet implemented.');
446 -}
447 -
448 -export function DEPRECATED_unmountResponderInstance(
449 - responderInstance: any,
450 -): void {
451 - throw new Error('Not yet implemented.');
452 -}
453 -
438 export function getFundamentalComponentInstance(fundamentalInstance: any) {
439 throw new Error('Not yet implemented.');
440 }
packages/react-native-renderer/src/ReactNativeHostConfig.js
-16
@@ -492,22 +492,6 @@ export function unhideTextInstance(
492 throw new Error('Not yet implemented.');
493 }
494
495 -export function DEPRECATED_mountResponderInstance(
496 - responder: any,
497 - responderInstance: any,
498 - props: Object,
499 - state: Object,
500 - instance: Instance,
501 -) {
502 - throw new Error('Not yet implemented.');
503 -}
504 -
505 -export function DEPRECATED_unmountResponderInstance(
506 - responderInstance: any,
507 -): void {
508 - throw new Error('Not yet implemented.');
509 -}
510 -
495 export function getFundamentalComponentInstance(fundamentalInstance: any) {
496 throw new Error('Not yet implemented.');
497 }
packages/react-native-renderer/src/__tests__/ResponderEventPlugin-test.internal.js
+1 -2
@@ -13,7 +13,6 @@
13 // though the responder plugin is only used in React Native. Sadness ensues.
14 // The coverage is valuable though, so we will keep it for now.
15 const {HostComponent} = require('react-reconciler/src/ReactWorkTags');
16 -const {PLUGIN_EVENT_SYSTEM} = require('react-dom/src/events/EventSystemFlags');
16
17 let EventBatching;
18 let EventPluginUtils;
@@ -320,7 +319,7 @@ const run = function(config, hierarchyConfig, nativeEventConfig) {
319 nativeEventConfig.targetInst,
320 nativeEventConfig.nativeEvent,
321 nativeEventConfig.target,
323 - PLUGIN_EVENT_SYSTEM,
322 + 0,
323 );
324
325 // At this point the negotiation events have been dispatched as part of the
packages/react-native-renderer/src/legacy-events/ReactGenericBatching.js
+1 -1
@@ -64,7 +64,7 @@ export function discreteUpdates(fn, a, b, c, d) {
64 }
65 }
66
67 -export function flushDiscreteUpdatesIfNeeded(timeStamp: number) {
67 +export function flushDiscreteUpdatesIfNeeded() {
68 if (!isInsideEventHandler) {
69 flushDiscreteUpdatesImpl();
70 }
packages/react-noop-renderer/src/createReactNoop.js
-8
@@ -375,14 +375,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
375 warnsIfNotActing: true,
376 supportsHydration: false,
377
378 - DEPRECATED_mountResponderInstance(): void {
379 - // NO-OP
380 - },
381 -
382 - DEPRECATED_unmountResponderInstance(): void {
383 - // NO-OP
384 - },
385 -
378 getFundamentalComponentInstance(fundamentalInstance): Instance {
379 const {impl, props, state} = fundamentalInstance;
380 return impl.getInstance(null, props, state);
packages/react-reconciler/src/ReactFiber.new.js
-2
@@ -326,7 +326,6 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
326 : {
327 lanes: currentDependencies.lanes,
328 firstContext: currentDependencies.firstContext,
329 - responders: currentDependencies.responders,
329 };
330
331 // These will be overridden during the parent's reconciliation
@@ -422,7 +421,6 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
421 : {
422 lanes: currentDependencies.lanes,
423 firstContext: currentDependencies.firstContext,
425 - responders: currentDependencies.responders,
424 };
425
426 if (enableProfilerTimer) {
packages/react-reconciler/src/ReactFiber.old.js
-2
@@ -320,7 +320,6 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
320 : {
321 lanes: currentDependencies.lanes,
322 firstContext: currentDependencies.firstContext,
323 - responders: currentDependencies.responders,
323 };
324
325 // These will be overridden during the parent's reconciliation
@@ -416,7 +415,6 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
415 : {
416 lanes: currentDependencies.lanes,
417 firstContext: currentDependencies.firstContext,
419 - responders: currentDependencies.responders,
418 };
419
420 if (enableProfilerTimer) {
packages/react-reconciler/src/ReactFiberCommitWork.new.js
-27
@@ -31,7 +31,6 @@ import {
31 enableProfilerTimer,
32 enableProfilerCommitHooks,
33 enableSuspenseServerRenderer,
34 - enableDeprecatedFlareAPI,
34 enableFundamentalAPI,
35 enableSuspenseCallback,
36 enableScopeAPI,
@@ -124,10 +123,6 @@ import {
123 Layout as HookLayout,
124 } from './ReactHookEffectTags';
125 import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.new';
127 -import {
128 - updateDeprecatedEventListeners,
129 - unmountDeprecatedResponderListeners,
130 -} from './ReactFiberDeprecatedEvents.new';
126 import {
127 NoEffect as NoSubtreeTag,
128 Passive as PassiveSubtreeTag,
@@ -904,9 +899,6 @@ function commitUnmount(
899 return;
900 }
901 case HostComponent: {
907 - if (enableDeprecatedFlareAPI) {
908 - unmountDeprecatedResponderListeners(current);
909 - }
902 safelyDetachRef(current);
903 return;
904 }
@@ -945,9 +937,6 @@ function commitUnmount(
937 }
938 case ScopeComponent: {
939 if (enableScopeAPI) {
948 - if (enableDeprecatedFlareAPI) {
949 - unmountDeprecatedResponderListeners(current);
950 - }
940 safelyDetachRef(current);
941 }
942 return;
@@ -1533,13 +1522,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1522 finishedWork,
1523 );
1524 }
1536 - if (enableDeprecatedFlareAPI) {
1537 - const prevListeners = oldProps.DEPRECATED_flareListeners;
1538 - const nextListeners = newProps.DEPRECATED_flareListeners;
1539 - if (prevListeners !== nextListeners) {
1540 - updateDeprecatedEventListeners(nextListeners, finishedWork, null);
1541 - }
1542 - }
1525 }
1526 return;
1527 }
@@ -1596,15 +1578,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1578 case ScopeComponent: {
1579 if (enableScopeAPI) {
1580 const scopeInstance = finishedWork.stateNode;
1599 - if (enableDeprecatedFlareAPI) {
1600 - const newProps = finishedWork.memoizedProps;
1601 - const oldProps = current !== null ? current.memoizedProps : newProps;
1602 - const prevListeners = oldProps.DEPRECATED_flareListeners;
1603 - const nextListeners = newProps.DEPRECATED_flareListeners;
1604 - if (prevListeners !== nextListeners || current === null) {
1605 - updateDeprecatedEventListeners(nextListeners, finishedWork, null);
1606 - }
1607 - }
1581 prepareScopeUpdate(scopeInstance, finishedWork);
1582 return;
1583 }
packages/react-reconciler/src/ReactFiberCommitWork.old.js
-27
@@ -31,7 +31,6 @@ import {
31 enableProfilerTimer,
32 enableProfilerCommitHooks,
33 enableSuspenseServerRenderer,
34 - enableDeprecatedFlareAPI,
34 enableFundamentalAPI,
35 enableSuspenseCallback,
36 enableScopeAPI,
@@ -126,10 +125,6 @@ import {
125 Passive as HookPassive,
126 } from './ReactHookEffectTags';
127 import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.old';
129 -import {
130 - updateDeprecatedEventListeners,
131 - unmountDeprecatedResponderListeners,
132 -} from './ReactFiberDeprecatedEvents.old';
128
129 let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;
130 if (__DEV__) {
@@ -922,9 +917,6 @@ function commitUnmount(
917 return;
918 }
919 case HostComponent: {
925 - if (enableDeprecatedFlareAPI) {
926 - unmountDeprecatedResponderListeners(current);
927 - }
920 safelyDetachRef(current);
921 return;
922 }
@@ -963,9 +955,6 @@ function commitUnmount(
955 }
956 case ScopeComponent: {
957 if (enableScopeAPI) {
966 - if (enableDeprecatedFlareAPI) {
967 - unmountDeprecatedResponderListeners(current);
968 - }
958 safelyDetachRef(current);
959 }
960 return;
@@ -1556,13 +1545,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1545 finishedWork,
1546 );
1547 }
1559 - if (enableDeprecatedFlareAPI) {
1560 - const prevListeners = oldProps.DEPRECATED_flareListeners;
1561 - const nextListeners = newProps.DEPRECATED_flareListeners;
1562 - if (prevListeners !== nextListeners) {
1563 - updateDeprecatedEventListeners(nextListeners, finishedWork, null);
1564 - }
1565 - }
1548 }
1549 return;
1550 }
@@ -1619,15 +1601,6 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1601 case ScopeComponent: {
1602 if (enableScopeAPI) {
1603 const scopeInstance = finishedWork.stateNode;
1622 - if (enableDeprecatedFlareAPI) {
1623 - const newProps = finishedWork.memoizedProps;
1624 - const oldProps = current !== null ? current.memoizedProps : newProps;
1625 - const prevListeners = oldProps.DEPRECATED_flareListeners;
1626 - const nextListeners = newProps.DEPRECATED_flareListeners;
1627 - if (prevListeners !== nextListeners || current === null) {
1628 - updateDeprecatedEventListeners(nextListeners, finishedWork, null);
1629 - }
1630 - }
1604 prepareScopeUpdate(scopeInstance, finishedWork);
1605 return;
1606 }
packages/react-reconciler/src/ReactFiberCompleteWork.new.js
+2 -57
@@ -126,7 +126,6 @@ import {
126 enableSchedulerTracing,
127 enableSuspenseCallback,
128 enableSuspenseServerRenderer,
129 - enableDeprecatedFlareAPI,
129 enableFundamentalAPI,
130 enableScopeAPI,
131 enableBlocksAPI,
@@ -142,7 +141,6 @@ import {
141 import {createFundamentalStateInstance} from './ReactFiberFundamental.new';
142 import {OffscreenLane} from './ReactFiberLane';
143 import {resetChildFibers} from './ReactChildFiber.new';
145 -import {updateDeprecatedEventListeners} from './ReactFiberDeprecatedEvents.new';
144 import {createScopeInstance} from './ReactFiberScope.new';
145 import {transferActualDuration} from './ReactProfilerTimer.new';
146
@@ -737,14 +735,6 @@ function completeWork(
735 rootContainerInstance,
736 );
737
740 - if (enableDeprecatedFlareAPI) {
741 - const prevListeners = current.memoizedProps.DEPRECATED_flareListeners;
742 - const nextListeners = newProps.DEPRECATED_flareListeners;
743 - if (prevListeners !== nextListeners) {
744 - markUpdate(workInProgress);
745 - }
746 - }
747 -
738 if (current.ref !== workInProgress.ref) {
739 markRef(workInProgress);
740 }
@@ -779,16 +769,6 @@ function completeWork(
769 // commit-phase we mark this as such.
770 markUpdate(workInProgress);
771 }
782 - if (enableDeprecatedFlareAPI) {
783 - const listeners = newProps.DEPRECATED_flareListeners;
784 - if (listeners != null) {
785 - updateDeprecatedEventListeners(
786 - listeners,
787 - workInProgress,
788 - rootContainerInstance,
789 - );
790 - }
791 - }
772 } else {
773 const instance = createInstance(
774 type,
@@ -800,20 +780,8 @@ function completeWork(
780
781 appendAllChildren(instance, workInProgress, false, false);
782
803 - // This needs to be set before we mount Flare event listeners
783 workInProgress.stateNode = instance;
784
806 - if (enableDeprecatedFlareAPI) {
807 - const listeners = newProps.DEPRECATED_flareListeners;
808 - if (listeners != null) {
809 - updateDeprecatedEventListeners(
810 - listeners,
811 - workInProgress,
812 - rootContainerInstance,
813 - );
814 - }
815 - }
816 -
785 // Certain renderers require commit-time effects for initial mount.
786 // (eg DOM renderer supports auto-focus for certain elements).
787 // Make sure such renderers get scheduled for later work.
@@ -1289,37 +1257,14 @@ function completeWork(
1257 if (current === null) {
1258 const scopeInstance: ReactScopeInstance = createScopeInstance();
1259 workInProgress.stateNode = scopeInstance;
1292 - if (enableDeprecatedFlareAPI) {
1293 - const listeners = newProps.DEPRECATED_flareListeners;
1294 - if (listeners != null) {
1295 - const rootContainerInstance = getRootHostContainer();
1296 - updateDeprecatedEventListeners(
1297 - listeners,
1298 - workInProgress,
1299 - rootContainerInstance,
1300 - );
1301 - }
1302 - }
1260 prepareScopeUpdate(scopeInstance, workInProgress);
1261 if (workInProgress.ref !== null) {
1262 markRef(workInProgress);
1263 markUpdate(workInProgress);
1264 }
1265 } else {
1309 - if (enableDeprecatedFlareAPI) {
1310 - const prevListeners =
1311 - current.memoizedProps.DEPRECATED_flareListeners;
1312 - const nextListeners = newProps.DEPRECATED_flareListeners;
1313 - if (
1314 - prevListeners !== nextListeners ||
1315 - workInProgress.ref !== null
1316 - ) {
1317 - markUpdate(workInProgress);
1318 - }
1319 - } else {
1320 - if (workInProgress.ref !== null) {
1321 - markUpdate(workInProgress);
1322 - }
1266 + if (workInProgress.ref !== null) {
1267 + markUpdate(workInProgress);
1268 }
1269 if (current.ref !== workInProgress.ref) {
1270 markRef(workInProgress);
packages/react-reconciler/src/ReactFiberCompleteWork.old.js
+2 -57
@@ -124,7 +124,6 @@ import {
124 enableSchedulerTracing,
125 enableSuspenseCallback,
126 enableSuspenseServerRenderer,
127 - enableDeprecatedFlareAPI,
127 enableFundamentalAPI,
128 enableScopeAPI,
129 enableBlocksAPI,
@@ -140,7 +139,6 @@ import {
139 import {createFundamentalStateInstance} from './ReactFiberFundamental.old';
140 import {OffscreenLane} from './ReactFiberLane';
141 import {resetChildFibers} from './ReactChildFiber.old';
143 -import {updateDeprecatedEventListeners} from './ReactFiberDeprecatedEvents.old';
142 import {createScopeInstance} from './ReactFiberScope.old';
143 import {transferActualDuration} from './ReactProfilerTimer.old';
144
@@ -716,14 +714,6 @@ function completeWork(
714 rootContainerInstance,
715 );
716
719 - if (enableDeprecatedFlareAPI) {
720 - const prevListeners = current.memoizedProps.DEPRECATED_flareListeners;
721 - const nextListeners = newProps.DEPRECATED_flareListeners;
722 - if (prevListeners !== nextListeners) {
723 - markUpdate(workInProgress);
724 - }
725 - }
726 -
717 if (current.ref !== workInProgress.ref) {
718 markRef(workInProgress);
719 }
@@ -758,16 +748,6 @@ function completeWork(
748 // commit-phase we mark this as such.
749 markUpdate(workInProgress);
750 }
761 - if (enableDeprecatedFlareAPI) {
762 - const listeners = newProps.DEPRECATED_flareListeners;
763 - if (listeners != null) {
764 - updateDeprecatedEventListeners(
765 - listeners,
766 - workInProgress,
767 - rootContainerInstance,
768 - );
769 - }
770 - }
751 } else {
752 const instance = createInstance(
753 type,
@@ -779,20 +759,8 @@ function completeWork(
759
760 appendAllChildren(instance, workInProgress, false, false);
761
782 - // This needs to be set before we mount Flare event listeners
762 workInProgress.stateNode = instance;
763
785 - if (enableDeprecatedFlareAPI) {
786 - const listeners = newProps.DEPRECATED_flareListeners;
787 - if (listeners != null) {
788 - updateDeprecatedEventListeners(
789 - listeners,
790 - workInProgress,
791 - rootContainerInstance,
792 - );
793 - }
794 - }
795 -
764 // Certain renderers require commit-time effects for initial mount.
765 // (eg DOM renderer supports auto-focus for certain elements).
766 // Make sure such renderers get scheduled for later work.
@@ -1262,37 +1230,14 @@ function completeWork(
1230 if (current === null) {
1231 const scopeInstance: ReactScopeInstance = createScopeInstance();
1232 workInProgress.stateNode = scopeInstance;
1265 - if (enableDeprecatedFlareAPI) {
1266 - const listeners = newProps.DEPRECATED_flareListeners;
1267 - if (listeners != null) {
1268 - const rootContainerInstance = getRootHostContainer();
1269 - updateDeprecatedEventListeners(
1270 - listeners,
1271 - workInProgress,
1272 - rootContainerInstance,
1273 - );
1274 - }
1275 - }
1233 prepareScopeUpdate(scopeInstance, workInProgress);
1234 if (workInProgress.ref !== null) {
1235 markRef(workInProgress);
1236 markUpdate(workInProgress);
1237 }
1238 } else {
1282 - if (enableDeprecatedFlareAPI) {
1283 - const prevListeners =
1284 - current.memoizedProps.DEPRECATED_flareListeners;
1285 - const nextListeners = newProps.DEPRECATED_flareListeners;
1286 - if (
1287 - prevListeners !== nextListeners ||
1288 - workInProgress.ref !== null
1289 - ) {
1290 - markUpdate(workInProgress);
1291 - }
1292 - } else {
1293 - if (workInProgress.ref !== null) {
1294 - markUpdate(workInProgress);
1295 - }
1239 + if (workInProgress.ref !== null) {
1240 + markUpdate(workInProgress);
1241 }
1242 if (current.ref !== workInProgress.ref) {
1243 markRef(workInProgress);
packages/react-reconciler/src/ReactFiberDeprecatedEvents.new.js deleted
-234
@@ -1,234 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import type {Fiber} from './ReactInternalTypes';
11 -import type {Container, Instance} from './ReactFiberHostConfig';
12 -import type {
13 - ReactEventResponder,
14 - ReactEventResponderInstance,
15 - ReactEventResponderListener,
16 -} from 'shared/ReactTypes';
17 -
18 -import {
19 - DEPRECATED_mountResponderInstance,
20 - DEPRECATED_unmountResponderInstance,
21 -} from './ReactFiberHostConfig';
22 -import {NoLanes} from './ReactFiberLane';
23 -
24 -import {REACT_RESPONDER_TYPE} from 'shared/ReactSymbols';
25 -
26 -import invariant from 'shared/invariant';
27 -import {HostComponent, HostRoot} from './ReactWorkTags';
28 -
29 -const emptyObject = {};
30 -const isArray = Array.isArray;
31 -
32 -export function createResponderInstance(
33 - responder: ReactEventResponder<any, any>,
34 - responderProps: Object,
35 - responderState: Object,
36 - fiber: Fiber,
37 -): ReactEventResponderInstance<any, any> {
38 - return {
39 - fiber,
40 - props: responderProps,
41 - responder,
42 - rootEventTypes: null,
43 - state: responderState,
44 - };
45 -}
46 -
47 -function mountEventResponder(
48 - responder: ReactEventResponder<any, any>,
49 - responderProps: Object,
50 - fiber: Fiber,
51 - respondersMap: Map<
52 - ReactEventResponder<any, any>,
53 - ReactEventResponderInstance<any, any>,
54 - >,
55 - rootContainerInstance: null | Container,
56 -) {
57 - let responderState = emptyObject;
58 - const getInitialState = responder.getInitialState;
59 - if (getInitialState !== null) {
60 - responderState = getInitialState(responderProps);
61 - }
62 - const responderInstance = createResponderInstance(
63 - responder,
64 - responderProps,
65 - responderState,
66 - fiber,
67 - );
68 -
69 - if (!rootContainerInstance) {
70 - let node = fiber;
71 - while (node !== null) {
72 - const tag = node.tag;
73 - if (tag === HostComponent) {
74 - rootContainerInstance = node.stateNode;
75 - break;
76 - } else if (tag === HostRoot) {
77 - rootContainerInstance = node.stateNode.containerInfo;
78 - break;
79 - }
80 - node = node.return;
81 - }
82 - }
83 -
84 - DEPRECATED_mountResponderInstance(
85 - responder,
86 - responderInstance,
87 - responderProps,
88 - responderState,
89 - ((rootContainerInstance: any): Instance),
90 - );
91 - respondersMap.set(responder, responderInstance);
92 -}
93 -
94 -function updateEventListener(
95 - listener: ReactEventResponderListener<any, any>,
96 - fiber: Fiber,
97 - visitedResponders: Set<ReactEventResponder<any, any>>,
98 - respondersMap: Map<
99 - ReactEventResponder<any, any>,
100 - ReactEventResponderInstance<any, any>,
101 - >,
102 - rootContainerInstance: null | Container,
103 -): void {
104 - let responder;
105 - let props;
106 -
107 - if (listener) {
108 - responder = listener.responder;
109 - props = listener.props;
110 - }
111 - invariant(
112 - responder && responder.$$typeof === REACT_RESPONDER_TYPE,
113 - 'An invalid value was used as an event listener. Expect one or many event ' +
114 - 'listeners created via React.unstable_useResponder().',
115 - );
116 - const listenerProps = ((props: any): Object);
117 - if (visitedResponders.has(responder)) {
118 - // show warning
119 - if (__DEV__) {
120 - console.error(
121 - 'Duplicate event responder "%s" found in event listeners. ' +
122 - 'Event listeners passed to elements cannot use the same event responder more than once.',
123 - responder.displayName,
124 - );
125 - }
126 - return;
127 - }
128 - visitedResponders.add(responder);
129 - const responderInstance = respondersMap.get(responder);
130 -
131 - if (responderInstance === undefined) {
132 - // Mount (happens in either complete or commit phase)
133 - mountEventResponder(
134 - responder,
135 - listenerProps,
136 - fiber,
137 - respondersMap,
138 - rootContainerInstance,
139 - );
140 - } else {
141 - // Update (happens during commit phase only)
142 - responderInstance.props = listenerProps;
143 - responderInstance.fiber = fiber;
144 - }
145 -}
146 -
147 -export function updateDeprecatedEventListeners(
148 - listeners: any,
149 - fiber: Fiber,
150 - rootContainerInstance: null | Container,
151 -): void {
152 - const visitedResponders = new Set();
153 - let dependencies = fiber.dependencies;
154 - if (listeners != null) {
155 - if (dependencies === null) {
156 - dependencies = fiber.dependencies = {
157 - lanes: NoLanes,
158 - firstContext: null,
159 - responders: new Map(),
160 - };
161 - }
162 - let respondersMap = dependencies.responders;
163 - if (respondersMap === null) {
164 - dependencies.responders = respondersMap = new Map();
165 - }
166 - if (isArray(listeners)) {
167 - for (let i = 0, length = listeners.length; i < length; i++) {
168 - const listener = listeners[i];
169 - updateEventListener(
170 - listener,
171 - fiber,
172 - visitedResponders,
173 - respondersMap,
174 - rootContainerInstance,
175 - );
176 - }
177 - } else {
178 - updateEventListener(
179 - listeners,
180 - fiber,
181 - visitedResponders,
182 - respondersMap,
183 - rootContainerInstance,
184 - );
185 - }
186 - }
187 - if (dependencies !== null) {
188 - const respondersMap = dependencies.responders;
189 - if (respondersMap !== null) {
190 - // Unmount
191 - const mountedResponders = Array.from(respondersMap.keys());
192 - for (let i = 0, length = mountedResponders.length; i < length; i++) {
193 - const mountedResponder = mountedResponders[i];
194 - if (!visitedResponders.has(mountedResponder)) {
195 - const responderInstance = ((respondersMap.get(
196 - mountedResponder,
197 - ): any): ReactEventResponderInstance<any, any>);
198 - DEPRECATED_unmountResponderInstance(responderInstance);
199 - respondersMap.delete(mountedResponder);
200 - }
201 - }
202 - }
203 - }
204 -}
205 -
206 -export function createDeprecatedResponderListener(
207 - responder: ReactEventResponder<any, any>,
208 - props: Object,
209 -): ReactEventResponderListener<any, any> {
210 - const eventResponderListener = {
211 - responder,
212 - props,
213 - };
214 - if (__DEV__) {
215 - Object.freeze(eventResponderListener);
216 - }
217 - return eventResponderListener;
218 -}
219 -
220 -export function unmountDeprecatedResponderListeners(fiber: Fiber) {
221 - const dependencies = fiber.dependencies;
222 -
223 - if (dependencies !== null) {
224 - const respondersMap = dependencies.responders;
225 - if (respondersMap !== null) {
226 - const responderInstances = Array.from(respondersMap.values());
227 - for (let i = 0, length = responderInstances.length; i < length; i++) {
228 - const responderInstance = responderInstances[i];
229 - DEPRECATED_unmountResponderInstance(responderInstance);
230 - }
231 - dependencies.responders = null;
232 - }
233 - }
234 -}
packages/react-reconciler/src/ReactFiberDeprecatedEvents.old.js deleted
-234
@@ -1,234 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - *
7 - * @flow
8 - */
9 -
10 -import type {Fiber} from './ReactInternalTypes';
11 -import type {Container, Instance} from './ReactFiberHostConfig';
12 -import type {
13 - ReactEventResponder,
14 - ReactEventResponderInstance,
15 - ReactEventResponderListener,
16 -} from 'shared/ReactTypes';
17 -
18 -import {
19 - DEPRECATED_mountResponderInstance,
20 - DEPRECATED_unmountResponderInstance,
21 -} from './ReactFiberHostConfig';
22 -import {NoLanes} from './ReactFiberLane';
23 -
24 -import {REACT_RESPONDER_TYPE} from 'shared/ReactSymbols';
25 -
26 -import invariant from 'shared/invariant';
27 -import {HostComponent, HostRoot} from './ReactWorkTags';
28 -
29 -const emptyObject = {};
30 -const isArray = Array.isArray;
31 -
32 -export function createResponderInstance(
33 - responder: ReactEventResponder<any, any>,
34 - responderProps: Object,
35 - responderState: Object,
36 - fiber: Fiber,
37 -): ReactEventResponderInstance<any, any> {
38 - return {
39 - fiber,
40 - props: responderProps,
41 - responder,
42 - rootEventTypes: null,
43 - state: responderState,
44 - };
45 -}
46 -
47 -function mountEventResponder(
48 - responder: ReactEventResponder<any, any>,
49 - responderProps: Object,
50 - fiber: Fiber,
51 - respondersMap: Map<
52 - ReactEventResponder<any, any>,
53 - ReactEventResponderInstance<any, any>,
54 - >,
55 - rootContainerInstance: null | Container,
56 -) {
57 - let responderState = emptyObject;
58 - const getInitialState = responder.getInitialState;
59 - if (getInitialState !== null) {
60 - responderState = getInitialState(responderProps);
61 - }
62 - const responderInstance = createResponderInstance(
63 - responder,
64 - responderProps,
65 - responderState,
66 - fiber,
67 - );
68 -
69 - if (!rootContainerInstance) {
70 - let node = fiber;
71 - while (node !== null) {
72 - const tag = node.tag;
73 - if (tag === HostComponent) {
74 - rootContainerInstance = node.stateNode;
75 - break;
76 - } else if (tag === HostRoot) {
77 - rootContainerInstance = node.stateNode.containerInfo;
78 - break;
79 - }
80 - node = node.return;
81 - }
82 - }
83 -
84 - DEPRECATED_mountResponderInstance(
85 - responder,
86 - responderInstance,
87 - responderProps,
88 - responderState,
89 - ((rootContainerInstance: any): Instance),
90 - );
91 - respondersMap.set(responder, responderInstance);
92 -}
93 -
94 -function updateEventListener(
95 - listener: ReactEventResponderListener<any, any>,
96 - fiber: Fiber,
97 - visitedResponders: Set<ReactEventResponder<any, any>>,
98 - respondersMap: Map<
99 - ReactEventResponder<any, any>,
100 - ReactEventResponderInstance<any, any>,
101 - >,
102 - rootContainerInstance: null | Container,
103 -): void {
104 - let responder;
105 - let props;
106 -
107 - if (listener) {
108 - responder = listener.responder;
109 - props = listener.props;
110 - }
111 - invariant(
112 - responder && responder.$$typeof === REACT_RESPONDER_TYPE,
113 - 'An invalid value was used as an event listener. Expect one or many event ' +
114 - 'listeners created via React.unstable_useResponder().',
115 - );
116 - const listenerProps = ((props: any): Object);
117 - if (visitedResponders.has(responder)) {
118 - // show warning
119 - if (__DEV__) {
120 - console.error(
121 - 'Duplicate event responder "%s" found in event listeners. ' +
122 - 'Event listeners passed to elements cannot use the same event responder more than once.',
123 - responder.displayName,
124 - );
125 - }
126 - return;
127 - }
128 - visitedResponders.add(responder);
129 - const responderInstance = respondersMap.get(responder);
130 -
131 - if (responderInstance === undefined) {
132 - // Mount (happens in either complete or commit phase)
133 - mountEventResponder(
134 - responder,
135 - listenerProps,
136 - fiber,
137 - respondersMap,
138 - rootContainerInstance,
139 - );
140 - } else {
141 - // Update (happens during commit phase only)
142 - responderInstance.props = listenerProps;
143 - responderInstance.fiber = fiber;
144 - }
145 -}
146 -
147 -export function updateDeprecatedEventListeners(
148 - listeners: any,
149 - fiber: Fiber,
150 - rootContainerInstance: null | Container,
151 -): void {
152 - const visitedResponders = new Set();
153 - let dependencies = fiber.dependencies;
154 - if (listeners != null) {
155 - if (dependencies === null) {
156 - dependencies = fiber.dependencies = {
157 - lanes: NoLanes,
158 - firstContext: null,
159 - responders: new Map(),
160 - };
161 - }
162 - let respondersMap = dependencies.responders;
163 - if (respondersMap === null) {
164 - dependencies.responders = respondersMap = new Map();
165 - }
166 - if (isArray(listeners)) {
167 - for (let i = 0, length = listeners.length; i < length; i++) {
168 - const listener = listeners[i];
169 - updateEventListener(
170 - listener,
171 - fiber,
172 - visitedResponders,
173 - respondersMap,
174 - rootContainerInstance,
175 - );
176 - }
177 - } else {
178 - updateEventListener(
179 - listeners,
180 - fiber,
181 - visitedResponders,
182 - respondersMap,
183 - rootContainerInstance,
184 - );
185 - }
186 - }
187 - if (dependencies !== null) {
188 - const respondersMap = dependencies.responders;
189 - if (respondersMap !== null) {
190 - // Unmount
191 - const mountedResponders = Array.from(respondersMap.keys());
192 - for (let i = 0, length = mountedResponders.length; i < length; i++) {
193 - const mountedResponder = mountedResponders[i];
194 - if (!visitedResponders.has(mountedResponder)) {
195 - const responderInstance = ((respondersMap.get(
196 - mountedResponder,
197 - ): any): ReactEventResponderInstance<any, any>);
198 - DEPRECATED_unmountResponderInstance(responderInstance);
199 - respondersMap.delete(mountedResponder);
200 - }
201 - }
202 - }
203 - }
204 -}
205 -
206 -export function createDeprecatedResponderListener(
207 - responder: ReactEventResponder<any, any>,
208 - props: Object,
209 -): ReactEventResponderListener<any, any> {
210 - const eventResponderListener = {
211 - responder,
212 - props,
213 - };
214 - if (__DEV__) {
215 - Object.freeze(eventResponderListener);
216 - }
217 - return eventResponderListener;
218 -}
219 -
220 -export function unmountDeprecatedResponderListeners(fiber: Fiber) {
221 - const dependencies = fiber.dependencies;
222 -
223 - if (dependencies !== null) {
224 - const respondersMap = dependencies.responders;
225 - if (respondersMap !== null) {
226 - const responderInstances = Array.from(respondersMap.values());
227 - for (let i = 0, length = responderInstances.length; i < length; i++) {
228 - const responderInstance = responderInstances[i];
229 - DEPRECATED_unmountResponderInstance(responderInstance);
230 - }
231 - dependencies.responders = null;
232 - }
233 - }
234 -}
packages/react-reconciler/src/ReactFiberHooks.new.js
-67
@@ -11,9 +11,7 @@ import type {
11 MutableSource,
12 MutableSourceGetSnapshotFn,
13 MutableSourceSubscribeFn,
14 - ReactEventResponder,
14 ReactContext,
16 - ReactEventResponderListener,
15 } from 'shared/ReactTypes';
16 import type {Fiber, Dispatcher} from './ReactInternalTypes';
17 import type {Lanes, Lane} from './ReactFiberLane';
@@ -46,7 +44,6 @@ import {
44 DefaultLanePriority,
45 } from './ReactFiberLane';
46 import {readContext} from './ReactFiberNewContext.new';
49 -import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.new';
47 import {
48 Update as UpdateEffect,
49 Passive as PassiveEffect,
@@ -129,7 +126,6 @@ export type HookType =
126 | 'useMemo'
127 | 'useImperativeHandle'
128 | 'useDebugValue'
132 - | 'useResponder'
129 | 'useDeferredValue'
130 | 'useTransition'
131 | 'useMutableSource'
@@ -1787,7 +1783,6 @@ export const ContextOnlyDispatcher: Dispatcher = {
1783 useRef: throwInvalidHookError,
1784 useState: throwInvalidHookError,
1785 useDebugValue: throwInvalidHookError,
1790 - useResponder: throwInvalidHookError,
1786 useDeferredValue: throwInvalidHookError,
1787 useTransition: throwInvalidHookError,
1788 useMutableSource: throwInvalidHookError,
@@ -1809,7 +1804,6 @@ const HooksDispatcherOnMount: Dispatcher = {
1804 useRef: mountRef,
1805 useState: mountState,
1806 useDebugValue: mountDebugValue,
1812 - useResponder: createDeprecatedResponderListener,
1807 useDeferredValue: mountDeferredValue,
1808 useTransition: mountTransition,
1809 useMutableSource: mountMutableSource,
@@ -1831,7 +1825,6 @@ const HooksDispatcherOnUpdate: Dispatcher = {
1825 useRef: updateRef,
1826 useState: updateState,
1827 useDebugValue: updateDebugValue,
1834 - useResponder: createDeprecatedResponderListener,
1828 useDeferredValue: updateDeferredValue,
1829 useTransition: updateTransition,
1830 useMutableSource: updateMutableSource,
@@ -1853,7 +1846,6 @@ const HooksDispatcherOnRerender: Dispatcher = {
1846 useRef: updateRef,
1847 useState: rerenderState,
1848 useDebugValue: updateDebugValue,
1856 - useResponder: createDeprecatedResponderListener,
1849 useDeferredValue: rerenderDeferredValue,
1850 useTransition: rerenderTransition,
1851 useMutableSource: updateMutableSource,
@@ -1988,14 +1980,6 @@ if (__DEV__) {
1980 mountHookTypesDev();
1981 return mountDebugValue(value, formatterFn);
1982 },
1991 - useResponder<E, C>(
1992 - responder: ReactEventResponder<E, C>,
1993 - props,
1994 - ): ReactEventResponderListener<E, C> {
1995 - currentHookNameInDev = 'useResponder';
1996 - mountHookTypesDev();
1997 - return createDeprecatedResponderListener(responder, props);
1998 - },
1983 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
1984 currentHookNameInDev = 'useDeferredValue';
1985 mountHookTypesDev();
@@ -2120,14 +2104,6 @@ if (__DEV__) {
2104 updateHookTypesDev();
2105 return mountDebugValue(value, formatterFn);
2106 },
2123 - useResponder<E, C>(
2124 - responder: ReactEventResponder<E, C>,
2125 - props,
2126 - ): ReactEventResponderListener<E, C> {
2127 - currentHookNameInDev = 'useResponder';
2128 - updateHookTypesDev();
2129 - return createDeprecatedResponderListener(responder, props);
2130 - },
2107 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2108 currentHookNameInDev = 'useDeferredValue';
2109 updateHookTypesDev();
@@ -2252,14 +2228,6 @@ if (__DEV__) {
2228 updateHookTypesDev();
2229 return updateDebugValue(value, formatterFn);
2230 },
2255 - useResponder<E, C>(
2256 - responder: ReactEventResponder<E, C>,
2257 - props,
2258 - ): ReactEventResponderListener<E, C> {
2259 - currentHookNameInDev = 'useResponder';
2260 - updateHookTypesDev();
2261 - return createDeprecatedResponderListener(responder, props);
2262 - },
2231 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2232 currentHookNameInDev = 'useDeferredValue';
2233 updateHookTypesDev();
@@ -2385,14 +2353,6 @@ if (__DEV__) {
2353 updateHookTypesDev();
2354 return updateDebugValue(value, formatterFn);
2355 },
2388 - useResponder<E, C>(
2389 - responder: ReactEventResponder<E, C>,
2390 - props,
2391 - ): ReactEventResponderListener<E, C> {
2392 - currentHookNameInDev = 'useResponder';
2393 - updateHookTypesDev();
2394 - return createDeprecatedResponderListener(responder, props);
2395 - },
2356 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2357 currentHookNameInDev = 'useDeferredValue';
2358 updateHookTypesDev();
@@ -2528,15 +2488,6 @@ if (__DEV__) {
2488 mountHookTypesDev();
2489 return mountDebugValue(value, formatterFn);
2490 },
2531 - useResponder<E, C>(
2532 - responder: ReactEventResponder<E, C>,
2533 - props,
2534 - ): ReactEventResponderListener<E, C> {
2535 - currentHookNameInDev = 'useResponder';
2536 - warnInvalidHookAccess();
2537 - mountHookTypesDev();
2538 - return createDeprecatedResponderListener(responder, props);
2539 - },
2491 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2492 currentHookNameInDev = 'useDeferredValue';
2493 warnInvalidHookAccess();
@@ -2676,15 +2627,6 @@ if (__DEV__) {
2627 updateHookTypesDev();
2628 return updateDebugValue(value, formatterFn);
2629 },
2679 - useResponder<E, C>(
2680 - responder: ReactEventResponder<E, C>,
2681 - props,
2682 - ): ReactEventResponderListener<E, C> {
2683 - currentHookNameInDev = 'useResponder';
2684 - warnInvalidHookAccess();
2685 - updateHookTypesDev();
2686 - return createDeprecatedResponderListener(responder, props);
2687 - },
2630 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2631 currentHookNameInDev = 'useDeferredValue';
2632 warnInvalidHookAccess();
@@ -2825,15 +2767,6 @@ if (__DEV__) {
2767 updateHookTypesDev();
2768 return updateDebugValue(value, formatterFn);
2769 },
2828 - useResponder<E, C>(
2829 - responder: ReactEventResponder<E, C>,
2830 - props,
2831 - ): ReactEventResponderListener<E, C> {
2832 - currentHookNameInDev = 'useResponder';
2833 - warnInvalidHookAccess();
2834 - updateHookTypesDev();
2835 - return createDeprecatedResponderListener(responder, props);
2836 - },
2770 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2771 currentHookNameInDev = 'useDeferredValue';
2772 warnInvalidHookAccess();
packages/react-reconciler/src/ReactFiberHooks.old.js
-67
@@ -11,9 +11,7 @@ import type {
11 MutableSource,
12 MutableSourceGetSnapshotFn,
13 MutableSourceSubscribeFn,
14 - ReactEventResponder,
14 ReactContext,
16 - ReactEventResponderListener,
15 } from 'shared/ReactTypes';
16 import type {Fiber, Dispatcher} from './ReactInternalTypes';
17 import type {Lanes, Lane} from './ReactFiberLane';
@@ -46,7 +44,6 @@ import {
44 DefaultLanePriority,
45 } from './ReactFiberLane';
46 import {readContext} from './ReactFiberNewContext.old';
49 -import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.old';
47 import {
48 Update as UpdateEffect,
49 Passive as PassiveEffect,
@@ -128,7 +125,6 @@ export type HookType =
125 | 'useMemo'
126 | 'useImperativeHandle'
127 | 'useDebugValue'
131 - | 'useResponder'
128 | 'useDeferredValue'
129 | 'useTransition'
130 | 'useMutableSource'
@@ -1785,7 +1781,6 @@ export const ContextOnlyDispatcher: Dispatcher = {
1781 useRef: throwInvalidHookError,
1782 useState: throwInvalidHookError,
1783 useDebugValue: throwInvalidHookError,
1788 - useResponder: throwInvalidHookError,
1784 useDeferredValue: throwInvalidHookError,
1785 useTransition: throwInvalidHookError,
1786 useMutableSource: throwInvalidHookError,
@@ -1807,7 +1802,6 @@ const HooksDispatcherOnMount: Dispatcher = {
1802 useRef: mountRef,
1803 useState: mountState,
1804 useDebugValue: mountDebugValue,
1810 - useResponder: createDeprecatedResponderListener,
1805 useDeferredValue: mountDeferredValue,
1806 useTransition: mountTransition,
1807 useMutableSource: mountMutableSource,
@@ -1829,7 +1823,6 @@ const HooksDispatcherOnUpdate: Dispatcher = {
1823 useRef: updateRef,
1824 useState: updateState,
1825 useDebugValue: updateDebugValue,
1832 - useResponder: createDeprecatedResponderListener,
1826 useDeferredValue: updateDeferredValue,
1827 useTransition: updateTransition,
1828 useMutableSource: updateMutableSource,
@@ -1851,7 +1844,6 @@ const HooksDispatcherOnRerender: Dispatcher = {
1844 useRef: updateRef,
1845 useState: rerenderState,
1846 useDebugValue: updateDebugValue,
1854 - useResponder: createDeprecatedResponderListener,
1847 useDeferredValue: rerenderDeferredValue,
1848 useTransition: rerenderTransition,
1849 useMutableSource: updateMutableSource,
@@ -1986,14 +1978,6 @@ if (__DEV__) {
1978 mountHookTypesDev();
1979 return mountDebugValue(value, formatterFn);
1980 },
1989 - useResponder<E, C>(
1990 - responder: ReactEventResponder<E, C>,
1991 - props,
1992 - ): ReactEventResponderListener<E, C> {
1993 - currentHookNameInDev = 'useResponder';
1994 - mountHookTypesDev();
1995 - return createDeprecatedResponderListener(responder, props);
1996 - },
1981 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
1982 currentHookNameInDev = 'useDeferredValue';
1983 mountHookTypesDev();
@@ -2118,14 +2102,6 @@ if (__DEV__) {
2102 updateHookTypesDev();
2103 return mountDebugValue(value, formatterFn);
2104 },
2121 - useResponder<E, C>(
2122 - responder: ReactEventResponder<E, C>,
2123 - props,
2124 - ): ReactEventResponderListener<E, C> {
2125 - currentHookNameInDev = 'useResponder';
2126 - updateHookTypesDev();
2127 - return createDeprecatedResponderListener(responder, props);
2128 - },
2105 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2106 currentHookNameInDev = 'useDeferredValue';
2107 updateHookTypesDev();
@@ -2250,14 +2226,6 @@ if (__DEV__) {
2226 updateHookTypesDev();
2227 return updateDebugValue(value, formatterFn);
2228 },
2253 - useResponder<E, C>(
2254 - responder: ReactEventResponder<E, C>,
2255 - props,
2256 - ): ReactEventResponderListener<E, C> {
2257 - currentHookNameInDev = 'useResponder';
2258 - updateHookTypesDev();
2259 - return createDeprecatedResponderListener(responder, props);
2260 - },
2229 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2230 currentHookNameInDev = 'useDeferredValue';
2231 updateHookTypesDev();
@@ -2383,14 +2351,6 @@ if (__DEV__) {
2351 updateHookTypesDev();
2352 return updateDebugValue(value, formatterFn);
2353 },
2386 - useResponder<E, C>(
2387 - responder: ReactEventResponder<E, C>,
2388 - props,
2389 - ): ReactEventResponderListener<E, C> {
2390 - currentHookNameInDev = 'useResponder';
2391 - updateHookTypesDev();
2392 - return createDeprecatedResponderListener(responder, props);
2393 - },
2354 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2355 currentHookNameInDev = 'useDeferredValue';
2356 updateHookTypesDev();
@@ -2526,15 +2486,6 @@ if (__DEV__) {
2486 mountHookTypesDev();
2487 return mountDebugValue(value, formatterFn);
2488 },
2529 - useResponder<E, C>(
2530 - responder: ReactEventResponder<E, C>,
2531 - props,
2532 - ): ReactEventResponderListener<E, C> {
2533 - currentHookNameInDev = 'useResponder';
2534 - warnInvalidHookAccess();
2535 - mountHookTypesDev();
2536 - return createDeprecatedResponderListener(responder, props);
2537 - },
2489 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2490 currentHookNameInDev = 'useDeferredValue';
2491 warnInvalidHookAccess();
@@ -2674,15 +2625,6 @@ if (__DEV__) {
2625 updateHookTypesDev();
2626 return updateDebugValue(value, formatterFn);
2627 },
2677 - useResponder<E, C>(
2678 - responder: ReactEventResponder<E, C>,
2679 - props,
2680 - ): ReactEventResponderListener<E, C> {
2681 - currentHookNameInDev = 'useResponder';
2682 - warnInvalidHookAccess();
2683 - updateHookTypesDev();
2684 - return createDeprecatedResponderListener(responder, props);
2685 - },
2628 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2629 currentHookNameInDev = 'useDeferredValue';
2630 warnInvalidHookAccess();
@@ -2823,15 +2765,6 @@ if (__DEV__) {
2765 updateHookTypesDev();
2766 return updateDebugValue(value, formatterFn);
2767 },
2826 - useResponder<E, C>(
2827 - responder: ReactEventResponder<E, C>,
2828 - props,
2829 - ): ReactEventResponderListener<E, C> {
2830 - currentHookNameInDev = 'useResponder';
2831 - warnInvalidHookAccess();
2832 - updateHookTypesDev();
2833 - return createDeprecatedResponderListener(responder, props);
2834 - },
2768 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T {
2769 currentHookNameInDev = 'useDeferredValue';
2770 warnInvalidHookAccess();
packages/react-reconciler/src/ReactFiberWorkLoop.new.js
+2 -2
@@ -2483,7 +2483,7 @@ function commitMutationEffectsImpl(
2483 commitDetachRef(current);
2484 }
2485 if (enableScopeAPI) {
2486 - // TODO: This is a temporary solution that allows us to transition away
2486 + // TODO: This is a temporary solution that allowed us to transition away
2487 // from React Flare on www.
2488 if (fiber.tag === ScopeComponent) {
2489 commitAttachRef(fiber);
@@ -2633,7 +2633,7 @@ function commitLayoutEffectsImpl(
2633 }
2634
2635 if (enableScopeAPI) {
2636 - // TODO: This is a temporary solution that allows us to transition away
2636 + // TODO: This is a temporary solution that allowed us to transition away
2637 // from React Flare on www.
2638 if (effectTag & Ref && fiber.tag !== ScopeComponent) {
2639 commitAttachRef(fiber);
packages/react-reconciler/src/ReactFiberWorkLoop.old.js
+2 -2
@@ -2342,7 +2342,7 @@ function commitMutationEffects(root: FiberRoot, renderPriorityLevel) {
2342 commitDetachRef(current);
2343 }
2344 if (enableScopeAPI) {
2345 - // TODO: This is a temporary solution that allows us to transition away
2345 + // TODO: This is a temporary solution that allowed us to transition away
2346 // from React Flare on www.
2347 if (nextEffect.tag === ScopeComponent) {
2348 commitAttachRef(nextEffect);
@@ -2429,7 +2429,7 @@ function commitLayoutEffects(root: FiberRoot, committedLanes: Lanes) {
2429 }
2430
2431 if (enableScopeAPI) {
2432 - // TODO: This is a temporary solution that allows us to transition away
2432 + // TODO: This is a temporary solution that allowed us to transition away
2433 // from React Flare on www.
2434 if (effectTag & Ref && nextEffect.tag !== ScopeComponent) {
2435 commitAttachRef(nextEffect);
packages/react-reconciler/src/ReactInternalTypes.js
-11
@@ -10,9 +10,6 @@
10 import type {Source} from 'shared/ReactElementType';
11 import type {
12 RefObject,
13 - ReactEventResponder,
14 - ReactEventResponderListener,
15 - ReactEventResponderInstance,
13 ReactContext,
14 MutableSourceSubscribeFn,
15 MutableSourceGetSnapshotFn,
@@ -44,10 +41,6 @@ export type ContextDependency<T> = {
41 export type Dependencies = {
42 lanes: Lanes,
43 firstContext: ContextDependency<mixed> | null,
47 - responders: Map<
48 - ReactEventResponder<any, any>,
49 - ReactEventResponderInstance<any, any>,
50 - > | null,
44 ...
45 };
46
@@ -298,10 +291,6 @@ export type Dispatcher = {|
291 deps: Array<mixed> | void | null,
292 ): void,
293 useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void,
301 - useResponder<E, C>(
302 - responder: ReactEventResponder<E, C>,
303 - props: Object,
304 - ): ReactEventResponderListener<E, C>,
294 useDeferredValue<T>(value: T, config: TimeoutConfig | void | null): T,
295 useTransition(
296 config: SuspenseConfig | void | null,
packages/react-reconciler/src/__tests__/ReactScope-test.internal.js
-1
@@ -19,7 +19,6 @@ describe('ReactScope', () => {
19 jest.resetModules();
20 ReactFeatureFlags = require('shared/ReactFeatureFlags');
21 ReactFeatureFlags.enableScopeAPI = true;
22 - ReactFeatureFlags.enableDeprecatedFlareAPI = true;
22 React = require('react');
23 Scheduler = require('scheduler');
24 });
packages/react-reconciler/src/forks/ReactFiberHostConfig.custom.js
-4
@@ -61,10 +61,6 @@ export const warnsIfNotActing = $$$hostConfig.warnsIfNotActing;
61 export const supportsMutation = $$$hostConfig.supportsMutation;
62 export const supportsPersistence = $$$hostConfig.supportsPersistence;
63 export const supportsHydration = $$$hostConfig.supportsHydration;
64 -export const DEPRECATED_mountResponderInstance =
65 - $$$hostConfig.DEPRECATED_mountResponderInstance;
66 -export const DEPRECATED_unmountResponderInstance =
67 - $$$hostConfig.DEPRECATED_unmountResponderInstance;
64 export const getFundamentalComponentInstance =
65 $$$hostConfig.getFundamentalComponentInstance;
66 export const mountFundamentalComponent =
packages/react-test-renderer/src/ReactTestHostConfig.js
+2 -45
@@ -7,13 +7,8 @@
7 * @flow
8 */
9
10 -import type {
11 - ReactEventResponder,
12 - ReactEventResponderInstance,
13 - ReactFundamentalComponentInstance,
14 -} from 'shared/ReactTypes';
10 +import type {ReactFundamentalComponentInstance} from 'shared/ReactTypes';
11
16 -import {enableDeprecatedFlareAPI} from 'shared/ReactFeatureFlags';
12 import {REACT_OPAQUE_ID_TYPE} from 'shared/ReactSymbols';
13
14 export type Type = string;
@@ -58,7 +53,6 @@ export * from 'react-reconciler/src/ReactFiberHostConfigWithNoPersistence';
53 export * from 'react-reconciler/src/ReactFiberHostConfigWithNoHydration';
54 export * from 'react-reconciler/src/ReactFiberHostConfigWithNoTestSelectors';
55
61 -const EVENT_COMPONENT_CONTEXT = {};
56 const NO_CONTEXT = {};
57 const UPDATE_SIGNAL = {};
58 const nodeToInstanceMap = new WeakMap();
@@ -161,19 +155,9 @@ export function createInstance(
155 hostContext: Object,
156 internalInstanceHandle: Object,
157 ): Instance {
164 - let propsToUse = props;
165 - if (enableDeprecatedFlareAPI) {
166 - if (props.DEPRECATED_flareListeners != null) {
167 - // We want to remove the "DEPRECATED_flareListeners" prop
168 - // as we don't want it in the test renderer's
169 - // instance props.
170 - const {DEPRECATED_flareListeners, ...otherProps} = props; // eslint-disable-line
171 - propsToUse = otherProps;
172 - }
173 - }
158 return {
159 type,
176 - props: propsToUse,
160 + props,
161 isHidden: false,
162 children: [],
163 internalInstanceHandle,
@@ -224,17 +208,6 @@ export function createTextInstance(
208 hostContext: Object,
209 internalInstanceHandle: Object,
210 ): TextInstance {
227 - if (__DEV__) {
228 - if (enableDeprecatedFlareAPI) {
229 - if (hostContext === EVENT_COMPONENT_CONTEXT) {
230 - console.error(
231 - 'validateDOMNesting: React event components cannot have text DOM nodes as children. ' +
232 - 'Wrap the child text "%s" in an element.',
233 - text,
234 - );
235 - }
236 - }
237 - }
211 return {
212 text,
213 isHidden: false,
@@ -311,22 +284,6 @@ export function unhideTextInstance(
284 textInstance.isHidden = false;
285 }
286
314 -export function DEPRECATED_mountResponderInstance(
315 - responder: ReactEventResponder<any, any>,
316 - responderInstance: ReactEventResponderInstance<any, any>,
317 - props: Object,
318 - state: Object,
319 - instance: Instance,
320 -) {
321 - // noop
322 -}
323 -
324 -export function DEPRECATED_unmountResponderInstance(
325 - responderInstance: ReactEventResponderInstance<any, any>,
326 -): void {
327 - // noop
328 -}
329 -
287 export function getFundamentalComponentInstance(
288 fundamentalInstance: ReactFundamentalComponentInstance<any, any>,
289 ): Instance {
packages/react/index.classic.fb.js
-3
@@ -52,9 +52,6 @@ export {
52 // enableBlocksAPI
53 block,
54 block as unstable_block,
55 - // enableDeprecatedFlareAPI
56 - DEPRECATED_useResponder,
57 - DEPRECATED_createResponder,
55 // enableScopeAPI
56 unstable_Scope,
57 unstable_useOpaqueIdentifier,
packages/react/index.js
-2
@@ -80,8 +80,6 @@ export {
80 block,
81 block as unstable_block,
82 unstable_LegacyHidden,
83 - DEPRECATED_useResponder,
84 - DEPRECATED_createResponder,
83 unstable_createFundamental,
84 unstable_Scope,
85 unstable_useOpaqueIdentifier,
packages/react/index.modern.fb.js
-3
@@ -51,9 +51,6 @@ export {
51 // enableBlocksAPI
52 block,
53 block as unstable_block,
54 - // enableDeprecatedFlareAPI
55 - DEPRECATED_useResponder,
56 - DEPRECATED_createResponder,
54 // enableScopeAPI
55 unstable_Scope,
56 unstable_useOpaqueIdentifier,
packages/react/src/React.js
-5
@@ -45,7 +45,6 @@ import {
45 useReducer,
46 useRef,
47 useState,
48 - useResponder,
48 useTransition,
49 useDeferredValue,
50 useOpaqueIdentifier,
@@ -59,7 +58,6 @@ import {
58 import {createMutableSource} from './ReactMutableSource';
59 import ReactSharedInternals from './ReactSharedInternals';
60 import {createFundamental} from './ReactFundamental';
62 -import {createEventResponder} from './ReactEventResponder';
61
62 // TODO: Move this branching into the other module instead and just re-export.
63 const createElement = __DEV__ ? createElementWithValidation : createElementProd;
@@ -115,9 +113,6 @@ export {
113 withSuspenseConfig as unstable_withSuspenseConfig,
114 // enableBlocksAPI
115 block,
118 - // enableDeprecatedFlareAPI
119 - useResponder as DEPRECATED_useResponder,
120 - createEventResponder as DEPRECATED_createResponder,
116 // enableFundamentalAPI
117 createFundamental as unstable_createFundamental,
118 // enableScopeAPI
packages/react/src/ReactEventResponder.js deleted
-46
@@ -1,46 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its affiliates.
3 - *
4 - * This source code is licensed under the MIT license found in the
5 - * LICENSE file in the root directory of this source tree.
6 - * @flow
7 - */
8 -
9 -import type {ReactEventResponder} from 'shared/ReactTypes';
10 -import {REACT_RESPONDER_TYPE} from 'shared/ReactSymbols';
11 -import {hasBadMapPolyfill} from './BadMapPolyfill';
12 -
13 -export function createEventResponder<E, C>(
14 - displayName: string,
15 - responderConfig: Object,
16 -): ReactEventResponder<E, C> {
17 - const {
18 - getInitialState,
19 - onEvent,
20 - onMount,
21 - onUnmount,
22 - onRootEvent,
23 - rootEventTypes,
24 - targetEventTypes,
25 - targetPortalPropagation,
26 - } = responderConfig;
27 - const eventResponder = {
28 - $$typeof: REACT_RESPONDER_TYPE,
29 - displayName,
30 - getInitialState: getInitialState || null,
31 - onEvent: onEvent || null,
32 - onMount: onMount || null,
33 - onRootEvent: onRootEvent || null,
34 - onUnmount: onUnmount || null,
35 - rootEventTypes: rootEventTypes || null,
36 - targetEventTypes: targetEventTypes || null,
37 - targetPortalPropagation: targetPortalPropagation || false,
38 - };
39 - // We use responder as a Map key later on. When we have a bad
40 - // polyfill, then we can't use it as a key as the polyfill tries
41 - // to add a property to the object.
42 - if (__DEV__ && !hasBadMapPolyfill) {
43 - Object.freeze(eventResponder);
44 - }
45 - return eventResponder;
46 -}
packages/react/src/ReactHooks.js
-20
@@ -12,13 +12,10 @@ import type {
12 MutableSourceGetSnapshotFn,
13 MutableSourceSubscribeFn,
14 ReactContext,
15 - ReactEventResponder,
16 - ReactEventResponderListener,
15 } from 'shared/ReactTypes';
16 import type {OpaqueIDType} from 'react-reconciler/src/ReactFiberHostConfig';
17
18 import invariant from 'shared/invariant';
21 -import {REACT_RESPONDER_TYPE} from 'shared/ReactSymbols';
19
20 import ReactCurrentDispatcher from './ReactCurrentDispatcher';
21
@@ -154,23 +151,6 @@ export function useDebugValue<T>(
151
152 export const emptyObject = {};
153
157 -export function useResponder(
158 - responder: ReactEventResponder<any, any>,
159 - listenerProps: ?Object,
160 -): ?ReactEventResponderListener<any, any> {
161 - const dispatcher = resolveDispatcher();
162 - if (__DEV__) {
163 - if (responder == null || responder.$$typeof !== REACT_RESPONDER_TYPE) {
164 - console.error(
165 - 'useResponder: invalid first argument. Expected an event responder, but instead got %s',
166 - responder,
167 - );
168 - return;
169 - }
170 - }
171 - return dispatcher.useResponder(responder, listenerProps || emptyObject);
172 -}
173 -
154 export function useTransition(
155 config: ?Object,
156 ): [(() => void) => void, boolean] {
packages/shared/ReactFeatureFlags.js
-3
@@ -54,9 +54,6 @@ export const enableSchedulerDebugging = false;
54 // Disable javascript: URL strings in href for XSS protection.
55 export const disableJavaScriptURLs = false;
56
57 -// Experimental React Flare event system and event components support.
58 -export const enableDeprecatedFlareAPI = false;
59 -
57 // Experimental Host Component support.
58 export const enableFundamentalAPI = false;
59
packages/shared/ReactSymbols.js
-2
@@ -28,7 +28,6 @@ export let REACT_LAZY_TYPE = 0xead4;
28 export let REACT_BLOCK_TYPE = 0xead9;
29 export let REACT_SERVER_BLOCK_TYPE = 0xeada;
30 export let REACT_FUNDAMENTAL_TYPE = 0xead5;
31 -export let REACT_RESPONDER_TYPE = 0xead6;
31 export let REACT_SCOPE_TYPE = 0xead7;
32 export let REACT_OPAQUE_ID_TYPE = 0xeae0;
33 export let REACT_DEBUG_TRACING_MODE_TYPE = 0xeae1;
@@ -52,7 +51,6 @@ if (typeof Symbol === 'function' && Symbol.for) {
51 REACT_BLOCK_TYPE = symbolFor('react.block');
52 REACT_SERVER_BLOCK_TYPE = symbolFor('react.server.block');
53 REACT_FUNDAMENTAL_TYPE = symbolFor('react.fundamental');
55 - REACT_RESPONDER_TYPE = symbolFor('react.responder');
54 REACT_SCOPE_TYPE = symbolFor('react.scope');
55 REACT_OPAQUE_ID_TYPE = symbolFor('react.opaque.id');
56 REACT_DEBUG_TRACING_MODE_TYPE = symbolFor('react.debug_trace_mode');
packages/shared/ReactTypes.js
-31
@@ -86,37 +86,6 @@ export type RefObject = {|
86 current: any,
87 |};
88
89 -export type ReactEventResponderInstance<E, C> = {|
90 - fiber: Object,
91 - props: Object,
92 - responder: ReactEventResponder<E, C>,
93 - rootEventTypes: null | Set<string>,
94 - state: Object,
95 -|};
96 -
97 -export type ReactEventResponderListener<E, C> = {|
98 - props: Object,
99 - responder: ReactEventResponder<E, C>,
100 -|};
101 -
102 -export type ReactEventResponder<E, C> = {
103 - $$typeof: Symbol | number,
104 - displayName: string,
105 - targetEventTypes: null | Array<string>,
106 - targetPortalPropagation: boolean,
107 - rootEventTypes: null | Array<string>,
108 - getInitialState: null | ((props: Object) => Object),
109 - onEvent:
110 - | null
111 - | ((event: E, context: C, props: Object, state: Object) => void),
112 - onRootEvent:
113 - | null
114 - | ((event: E, context: C, props: Object, state: Object) => void),
115 - onMount: null | ((context: C, props: Object, state: Object) => void),
116 - onUnmount: null | ((context: C, props: Object, state: Object) => void),
117 - ...
118 -};
119 -
89 export type EventPriority = 0 | 1 | 2;
90
91 export const DiscreteEvent: EventPriority = 0;
packages/shared/forks/ReactFeatureFlags.native-fb.js
-1
@@ -27,7 +27,6 @@ export const disableJavaScriptURLs = false;
27 export const disableInputAttributeSyncing = false;
28 export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
29 export const warnAboutDeprecatedLifecycles = true;
30 -export const enableDeprecatedFlareAPI = false;
30 export const enableFundamentalAPI = false;
31 export const enableScopeAPI = false;
32 export const enableCreateEventHandleAPI = false;
packages/shared/forks/ReactFeatureFlags.native-oss.js
-1
@@ -26,7 +26,6 @@ export const enableLazyElements = false;
26 export const disableJavaScriptURLs = false;
27 export const disableInputAttributeSyncing = false;
28 export const enableSchedulerDebugging = false;
29 -export const enableDeprecatedFlareAPI = false;
29 export const enableFundamentalAPI = false;
30 export const enableScopeAPI = false;
31 export const enableCreateEventHandleAPI = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.js
-1
@@ -26,7 +26,6 @@ export const enableLazyElements = false;
26 export const disableJavaScriptURLs = false;
27 export const disableInputAttributeSyncing = false;
28 export const enableSchedulerDebugging = false;
29 -export const enableDeprecatedFlareAPI = false;
29 export const enableFundamentalAPI = false;
30 export const enableScopeAPI = false;
31 export const enableCreateEventHandleAPI = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.native.js
-1
@@ -26,7 +26,6 @@ export const enableLazyElements = false;
26 export const disableJavaScriptURLs = false;
27 export const disableInputAttributeSyncing = false;
28 export const enableSchedulerDebugging = false;
29 -export const enableDeprecatedFlareAPI = false;
29 export const enableFundamentalAPI = false;
30 export const enableScopeAPI = false;
31 export const enableCreateEventHandleAPI = false;
packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
-1
@@ -26,7 +26,6 @@ export const enableLazyElements = false;
26 export const enableSchedulerDebugging = false;
27 export const disableJavaScriptURLs = false;
28 export const disableInputAttributeSyncing = false;
29 -export const enableDeprecatedFlareAPI = true;
29 export const enableFundamentalAPI = false;
30 export const enableScopeAPI = true;
31 export const enableCreateEventHandleAPI = false;
packages/shared/forks/ReactFeatureFlags.testing.js
-1
@@ -26,7 +26,6 @@ export const enableLazyElements = false;
26 export const disableJavaScriptURLs = false;
27 export const disableInputAttributeSyncing = false;
28 export const enableSchedulerDebugging = false;
29 -export const enableDeprecatedFlareAPI = false;
29 export const enableFundamentalAPI = false;
30 export const enableScopeAPI = false;
31 export const enableCreateEventHandleAPI = false;
packages/shared/forks/ReactFeatureFlags.testing.www.js
-1
@@ -26,7 +26,6 @@ export const enableLazyElements = false;
26 export const disableJavaScriptURLs = true;
27 export const disableInputAttributeSyncing = false;
28 export const enableSchedulerDebugging = false;
29 -export const enableDeprecatedFlareAPI = true;
29 export const enableFundamentalAPI = false;
30 export const enableScopeAPI = true;
31 export const enableCreateEventHandleAPI = true;
packages/shared/forks/ReactFeatureFlags.www.js
-2
@@ -60,8 +60,6 @@ export const disableJavaScriptURLs = true;
60
61 export const disableModulePatternComponents = true;
62
63 -export const enableDeprecatedFlareAPI = true;
64 -
63 export const enableCreateEventHandleAPI = true;
64
65 export const enableFundamentalAPI = false;
packages/shared/isValidElementType.js
-2
@@ -20,7 +20,6 @@ import {
20 REACT_MEMO_TYPE,
21 REACT_LAZY_TYPE,
22 REACT_FUNDAMENTAL_TYPE,
23 - REACT_RESPONDER_TYPE,
23 REACT_SCOPE_TYPE,
24 REACT_BLOCK_TYPE,
25 REACT_SERVER_BLOCK_TYPE,
@@ -55,7 +54,6 @@ export default function isValidElementType(type: mixed) {
54 type.$$typeof === REACT_CONTEXT_TYPE ||
55 type.$$typeof === REACT_FORWARD_REF_TYPE ||
56 type.$$typeof === REACT_FUNDAMENTAL_TYPE ||
58 - type.$$typeof === REACT_RESPONDER_TYPE ||
57 type.$$typeof === REACT_BLOCK_TYPE ||
58 type[(0: any)] === REACT_SERVER_BLOCK_TYPE
59 ) {
scripts/error-codes/codes.json
-6
@@ -322,8 +322,6 @@
322 "321": "Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.",
323 "322": "forwardRef requires a render function but was given %s.",
324 "323": "React has blocked a javascript: URL as a security precaution.",
325 - "324": "An event responder context was used outside of an event cycle. Use context.setTimeout() to use asynchronous responder context outside of event cycle .",
326 - "325": "addRootEventTypes() found a duplicate root event type of \"%s\". This might be because the event type exists in the event responder \"rootEventTypes\" array or because of a previous addRootEventTypes() using this root event type.",
325 "326": "Expected a valid priority level",
326 "327": "Should not already be working.",
327 "328": "Should have a work-in-progress.",
@@ -334,17 +332,13 @@
332 "333": "This should have a parent host component initialized. This error is likely caused by a bug in React. Please file an issue.",
333 "334": "accumulate(...): Accumulated items must not be null or undefined.",
334 "335": "ReactDOMServer does not yet support the event API.",
337 - "336": "The \"%s\" event responder cannot be used via the \"useEvent\" hook.",
338 - "337": "An invalid event responder was provided to host component",
335 "338": "ReactDOMServer does not yet support the fundamental API.",
340 - "339": "An invalid value was used as an event listener. Expect one or many event listeners created via React.unstable_useResponder().",
336 "340": "Threw in newly mounted dehydrated component. This is likely a bug in React. Please file an issue.",
337 "341": "We just came from a parent so we must have had a parent. This is a bug in React.",
338 "342": "A React component suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.",
339 "343": "ReactDOMServer does not yet support scope components.",
340 "344": "Expected prepareToHydrateHostSuspenseInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.",
341 "345": "Root did not complete. This is a bug in React.",
347 - "346": "An event responder context was used outside of an event cycle.",
342 "348": "ensureListeningTo(): received a container that was not an element node. This is likely a bug in React.",
343 "349": "Expected a work-in-progress root. This is a bug in React. Please file an issue.",
344 "350": "Cannot read from mutable source during the current render without tearing. This is a bug in React. Please file an issue.",
scripts/jest/setupTests.www.js
-1
@@ -16,7 +16,6 @@ jest.mock('shared/ReactFeatureFlags', () => {
16 wwwFlags.disableLegacyContext = defaultFlags.disableLegacyContext;
17 wwwFlags.warnAboutUnmockedScheduler = defaultFlags.warnAboutUnmockedScheduler;
18 wwwFlags.disableJavaScriptURLs = defaultFlags.disableJavaScriptURLs;
19 - wwwFlags.enableDeprecatedFlareAPI = defaultFlags.enableDeprecatedFlareAPI;
19
20 return wwwFlags;
21 });
scripts/rollup/build.js
-6
@@ -370,8 +370,6 @@ function getPlugins(
370 useForks(forks),
371 // Ensure we don't try to bundle any fbjs modules.
372 forbidFBJSImports(),
373 - // Replace any externals with their valid internal FB mappings
374 - isFBWWWBundle && replace(Bundles.fbBundleExternalsMap),
373 // Use Node resolution mechanism.
374 resolve({
375 skip: externals,
@@ -564,10 +562,6 @@ async function createBundle(bundle, bundleType) {
562 const deps = Modules.getDependencies(bundleType, bundle.entry);
563 externals = externals.concat(deps);
564 }
567 - if (isFBWWWBundle) {
568 - // Add any mapped fb bundle externals
569 - externals = externals.concat(Object.values(Bundles.fbBundleExternalsMap));
570 - }
565
566 const importSideEffects = Modules.getImportSideEffects();
567 const pureExternalModules = Object.keys(importSideEffects).filter(
scripts/rollup/bundles.js
-68
@@ -704,75 +704,8 @@ const bundles = [
704 global: 'SchedulerTracing',
705 externals: [],
706 },
707 -
708 - /******* React Events (experimental) *******/
709 -
710 - {
711 - bundleTypes: [
712 - UMD_DEV,
713 - UMD_PROD,
714 - NODE_DEV,
715 - NODE_PROD,
716 - FB_WWW_DEV,
717 - FB_WWW_PROD,
718 - ],
719 - moduleType: NON_FIBER_RENDERER,
720 - entry: 'react-interactions/events/context-menu',
721 - global: 'ReactEventsContextMenu',
722 - externals: ['react'],
723 - },
724 -
725 - {
726 - bundleTypes: [
727 - UMD_DEV,
728 - UMD_PROD,
729 - NODE_DEV,
730 - NODE_PROD,
731 - FB_WWW_DEV,
732 - FB_WWW_PROD,
733 - ],
734 - moduleType: NON_FIBER_RENDERER,
735 - entry: 'react-interactions/events/deprecated-focus',
736 - global: 'ReactEventsFocus',
737 - externals: ['react'],
738 - },
739 -
740 - {
741 - bundleTypes: [
742 - UMD_DEV,
743 - UMD_PROD,
744 - NODE_DEV,
745 - NODE_PROD,
746 - FB_WWW_DEV,
747 - FB_WWW_PROD,
748 - ],
749 - moduleType: NON_FIBER_RENDERER,
750 - entry: 'react-interactions/events/hover',
751 - global: 'ReactEventsHover',
752 - externals: ['react'],
753 - },
754 -
755 - {
756 - bundleTypes: [
757 - UMD_DEV,
758 - UMD_PROD,
759 - NODE_DEV,
760 - NODE_PROD,
761 - FB_WWW_DEV,
762 - FB_WWW_PROD,
763 - ],
764 - moduleType: NON_FIBER_RENDERER,
765 - entry: 'react-interactions/events/press-legacy',
766 - global: 'ReactEventsPressLegacy',
767 - externals: ['react'],
768 - },
707 ];
708
771 -const fbBundleExternalsMap = {
772 - 'react-interactions/events/focus': 'ReactEventsFocus',
773 - 'react-interactions/events/tap': 'ReactEventsTap',
774 -};
775 -
709 // Based on deep-freeze by substack (public domain)
710 function deepFreeze(o) {
711 Object.freeze(o);
@@ -829,7 +762,6 @@ function getFilename(bundle, bundleType) {
762 }
763
764 module.exports = {
832 - fbBundleExternalsMap,
765 bundleTypes,
766 moduleTypes,
767 bundles,