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,