[Flare] Tweaks to Flare system design and API (#16264)
Dominic Gannaway committed
Aug 1, 2019 at 19:08 UTC
42794557ca44a8c05c71aab698d44d1294236538
39 files changed
+1143
-1193
packages/react-debug-tools/src/ReactDebugHooks.js
+10
-8
@@ -11,6 +11,7 @@ import type {
11
ReactContext,
12
ReactProviderType,
13
ReactEventResponder,
14
+ ReactEventResponderListener,
15
} from 'shared/ReactTypes';
16
import type {Fiber} from 'react-reconciler/src/ReactFiber';
17
import type {Hook} from 'react-reconciler/src/ReactFiberHooks';
@@ -25,8 +26,6 @@ import {
26
ForwardRef,
27
} from 'shared/ReactWorkTags';
28
28
-const emptyObject = {};
29
-
29
type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher;
30
31
// Used to track hooks called during a render
@@ -221,17 +220,20 @@ function useMemo<T>(
220
return value;
221
}
222
224
-function useListener(
223
+function useResponder(
224
responder: ReactEventResponder<any, any>,
226
- hookProps: ?Object,
227
-): void {
228
- const listenerProps = hookProps || emptyObject;
225
+ listenerProps: Object,
226
+): ReactEventResponderListener<any, any> {
227
// Don't put the actual event responder object in, just its displayName
228
const value = {
229
responder: responder.displayName || 'EventResponder',
230
props: listenerProps,
231
};
234
- hookLog.push({primitive: 'Listener', stackError: new Error(), value});
232
+ hookLog.push({primitive: 'Responder', stackError: new Error(), value});
233
+ return {
234
+ responder,
235
+ props: listenerProps,
236
+ };
237
}
238
239
const Dispatcher: DispatcherType = {
@@ -246,7 +248,7 @@ const Dispatcher: DispatcherType = {
248
useReducer,
249
useRef,
250
useState,
249
- useListener,
251
+ useResponder,
252
};
253
254
// Inspect
packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.internal.js
+6
-4
@@ -22,19 +22,21 @@ describe('ReactHooksInspection', () => {
22
ReactDebugTools = require('react-debug-tools');
23
});
24
25
- it('should inspect a simple useListener hook', () => {
25
+ it('should inspect a simple useResponder hook', () => {
26
const TestResponder = React.unstable_createResponder('TestResponder', {});
27
28
function Foo(props) {
29
- React.unstable_useListener(TestResponder, {preventDefault: false});
30
- return <div responders={<TestResponder />}>Hello world</div>;
29
+ const listener = React.unstable_useResponder(TestResponder, {
30
+ preventDefault: false,
31
+ });
32
+ return <div listeners={listener}>Hello world</div>;
33
}
34
let tree = ReactDebugTools.inspectHooks(Foo, {});
35
expect(tree).toEqual([
36
{
37
isStateEditable: false,
38
id: 0,
37
- name: 'Listener',
39
+ name: 'Responder',
40
value: {props: {preventDefault: false}, responder: 'TestResponder'},
41
subHooks: [],
42
},
packages/react-dom/src/client/ReactDOMComponent.js
+5
-5
@@ -98,7 +98,7 @@ const AUTOFOCUS = 'autoFocus';
98
const CHILDREN = 'children';
99
const STYLE = 'style';
100
const HTML = '__html';
101
-const RESPONDERS = 'responders';
101
+const LISTENERS = 'listeners';
102
103
const {html: HTML_NAMESPACE} = Namespaces;
104
@@ -341,7 +341,7 @@ function setInitialDOMProperties(
341
setTextContent(domElement, '' + nextProp);
342
}
343
} else if (
344
- (enableFlareAPI && propKey === RESPONDERS) ||
344
+ (enableFlareAPI && propKey === LISTENERS) ||
345
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
346
propKey === SUPPRESS_HYDRATION_WARNING
347
) {
@@ -698,7 +698,7 @@ export function diffProperties(
698
} else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) {
699
// Noop. This is handled by the clear text mechanism.
700
} else if (
701
- (enableFlareAPI && propKey === RESPONDERS) ||
701
+ (enableFlareAPI && propKey === LISTENERS) ||
702
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
703
propKey === SUPPRESS_HYDRATION_WARNING
704
) {
@@ -790,7 +790,7 @@ export function diffProperties(
790
(updatePayload = updatePayload || []).push(propKey, '' + nextProp);
791
}
792
} else if (
793
- (enableFlareAPI && propKey === RESPONDERS) ||
793
+ (enableFlareAPI && propKey === LISTENERS) ||
794
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
795
propKey === SUPPRESS_HYDRATION_WARNING
796
) {
@@ -1045,7 +1045,7 @@ export function diffHydratedProperties(
1045
if (suppressHydrationWarning) {
1046
// Don't bother comparing. We're ignoring all these warnings.
1047
} else if (
1048
- (enableFlareAPI && propKey === RESPONDERS) ||
1048
+ (enableFlareAPI && propKey === LISTENERS) ||
1049
propKey === SUPPRESS_CONTENT_EDITABLE_WARNING ||
1050
propKey === SUPPRESS_HYDRATION_WARNING ||
1051
// Controlled attributes are not validated
packages/react-dom/src/events/DOMEventResponderSystem.js
+13
-83
@@ -12,12 +12,7 @@ import {
12
PASSIVE_NOT_SUPPORTED,
13
} from 'events/EventSystemFlags';
14
import type {AnyNativeEvent} from 'events/PluginModuleType';
15
-import {
16
- HostComponent,
17
- FunctionComponent,
18
- MemoComponent,
19
- ForwardRef,
20
-} from 'shared/ReactWorkTags';
15
+import {HostComponent} from 'shared/ReactWorkTags';
16
import type {EventPriority} from 'shared/ReactTypes';
17
import type {
18
ReactDOMEventResponder,
@@ -67,7 +62,7 @@ export function setListenToResponderEventTypes(
62
}
63
64
type EventQueueItem = {|
70
- listeners: Array<(val: any) => void>,
65
+ listener: (val: any) => void,
66
value: any,
67
|};
68
type EventQueue = Array<EventQueueItem>;
@@ -103,8 +98,8 @@ let currentDocument: null | Document = null;
98
99
const eventResponderContext: ReactDOMResponderContext = {
100
dispatchEvent(
106
- eventProp: string,
101
eventValue: any,
102
+ eventListener: any => void,
103
eventPriority: EventPriority,
104
): void {
105
validateResponderContext();
@@ -112,15 +107,9 @@ const eventResponderContext: ReactDOMResponderContext = {
107
if (eventPriority < currentEventQueuePriority) {
108
currentEventQueuePriority = eventPriority;
109
}
115
- const responderInstance = ((currentInstance: any): ReactDOMEventResponderInstance);
116
- const target = responderInstance.fiber;
117
- const responder = responderInstance.responder;
118
- const listeners = collectListeners(eventProp, responder, target);
119
- if (listeners.length !== 0) {
120
- ((currentEventQueue: any): EventQueue).push(
121
- createEventQueueItem(eventValue, listeners),
122
- );
123
- }
110
+ ((currentEventQueue: any): EventQueue).push(
111
+ createEventQueueItem(eventValue, eventListener),
112
+ );
113
},
114
isTargetWithinResponder(target: Element | Document): boolean {
115
validateResponderContext();
@@ -392,11 +381,11 @@ function collectFocusableElements(
381
382
function createEventQueueItem(
383
value: any,
395
- listeners: Array<(val: any) => void>,
384
+ listener: (val: any) => void,
385
): EventQueueItem {
386
return {
387
value,
399
- listeners,
388
+ listener,
389
};
390
}
391
@@ -519,70 +508,11 @@ function createDOMResponderEvent(
508
};
509
}
510
522
-function collectListeners(
523
- eventProp: string,
524
- eventResponder: ReactDOMEventResponder,
525
- target: Fiber,
526
-): Array<(any) => void> {
527
- const eventListeners = [];
528
- let node = target.return;
529
- nodeTraversal: while (node !== null) {
530
- switch (node.tag) {
531
- case HostComponent: {
532
- const dependencies = node.dependencies;
533
-
534
- if (dependencies !== null) {
535
- const respondersMap = dependencies.responders;
536
-
537
- if (respondersMap !== null && respondersMap.has(eventResponder)) {
538
- break nodeTraversal;
539
- }
540
- }
541
- break;
542
- }
543
- case FunctionComponent:
544
- case MemoComponent:
545
- case ForwardRef: {
546
- const dependencies = node.dependencies;
547
-
548
- if (dependencies !== null) {
549
- const listeners = dependencies.listeners;
550
-
551
- if (listeners !== null) {
552
- for (
553
- let s = 0, listenersLength = listeners.length;
554
- s < listenersLength;
555
- s++
556
- ) {
557
- const listener = listeners[s];
558
- const {responder, props} = listener;
559
- const listenerFunc = props[eventProp];
560
-
561
- if (
562
- responder === eventResponder &&
563
- typeof listenerFunc === 'function'
564
- ) {
565
- eventListeners.push(listenerFunc);
566
- }
567
- }
568
- }
569
- }
570
- }
571
- }
572
- node = node.return;
573
- }
574
- return eventListeners;
575
-}
576
-
511
function processEvents(eventQueue: EventQueue): void {
512
for (let i = 0, length = eventQueue.length; i < length; i++) {
579
- const {value, listeners} = eventQueue[i];
580
- for (let s = 0, length2 = listeners.length; s < length2; s++) {
581
- const listener = listeners[s];
582
- const type =
583
- typeof value === 'object' && value !== null ? value.type : '';
584
- invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, value);
585
- }
513
+ const {value, listener} = eventQueue[i];
514
+ const type = typeof value === 'object' && value !== null ? value.type : '';
515
+ invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, value);
516
}
517
}
518
@@ -663,6 +593,7 @@ function traverseAndHandleEventResponderInstances(
593
// - Bubble target responder phase
594
// - Root responder phase
595
596
+ const visitedResponders = new Set();
597
const responderEvent = createDOMResponderEvent(
598
topLevelType,
599
nativeEvent,
@@ -670,7 +601,6 @@ function traverseAndHandleEventResponderInstances(
601
isPassiveEvent,
602
isPassiveSupported,
603
);
673
- const visitedResponders = new Set();
604
let node = targetFiber;
605
while (node !== null) {
606
const {dependencies, tag} = node;
@@ -687,8 +617,8 @@ function traverseAndHandleEventResponderInstances(
617
!visitedResponders.has(responder) &&
618
validateResponderTargetEventTypes(eventType, responder)
619
) {
690
- const onEvent = responder.onEvent;
620
visitedResponders.add(responder);
621
+ const onEvent = responder.onEvent;
622
if (onEvent !== null) {
623
currentInstance = responderInstance;
624
responderEvent.responderTarget = ((target: any):
packages/react-dom/src/events/__tests__/DOMEventResponderSystem-test.internal.js
+186
-108
@@ -87,19 +87,28 @@ describe('DOMEventResponderSystem', () => {
87
jest.resetModules();
88
ReactFeatureFlags = require('shared/ReactFeatureFlags');
89
ReactFeatureFlags.enableFlareAPI = true;
90
+ React = require('react');
91
ReactTestRenderer = require('react-test-renderer');
92
const TestResponder = createEventResponder({});
92
- const renderer = ReactTestRenderer.create(
93
- <div responders={<TestResponder />}>Hello world</div>,
94
- );
93
+
94
+ function Test() {
95
+ const listener = React.unstable_useResponder(TestResponder, {});
96
+
97
+ return <div listeners={listener}>Hello world</div>;
98
+ }
99
+ const renderer = ReactTestRenderer.create(<Test />);
100
expect(renderer).toMatchRenderedOutput(<div>Hello world</div>);
101
});
102
103
it('can render correctly with the ReactDOMServer', () => {
104
const TestResponder = createEventResponder({});
100
- const output = ReactDOMServer.renderToString(
101
- <div responders={<TestResponder />}>Hello world</div>,
102
- );
105
+
106
+ function Test() {
107
+ const listener = React.unstable_useResponder(TestResponder, {});
108
+
109
+ return <div listeners={listener}>Hello world</div>;
110
+ }
111
+ const output = ReactDOMServer.renderToString(<Test />);
112
expect(output).toBe(`<div data-reactroot="">Hello world</div>`);
113
});
114
@@ -121,11 +130,15 @@ describe('DOMEventResponderSystem', () => {
130
},
131
});
132
124
- const Test = () => (
125
- <button ref={buttonRef} responders={<TestResponder />}>
126
- Click me!
127
- </button>
128
- );
133
+ function Test() {
134
+ const listener = React.unstable_useResponder(TestResponder, {});
135
+
136
+ return (
137
+ <button ref={buttonRef} listeners={listener}>
138
+ Click me!
139
+ </button>
140
+ );
141
+ }
142
143
ReactDOM.render(<Test />, container);
144
expect(container.innerHTML).toBe('<button>Click me!</button>');
@@ -177,11 +190,15 @@ describe('DOMEventResponderSystem', () => {
190
},
191
});
192
180
- const Test = () => (
181
- <button ref={buttonRef} responders={<TestResponder />}>
182
- Click me!
183
- </button>
184
- );
193
+ function Test() {
194
+ const listener = React.unstable_useResponder(TestResponder, {});
195
+
196
+ return (
197
+ <button ref={buttonRef} listeners={listener}>
198
+ Click me!
199
+ </button>
200
+ );
201
+ }
202
203
ReactDOM.render(<Test />, container);
204
@@ -217,15 +234,23 @@ describe('DOMEventResponderSystem', () => {
234
},
235
});
236
220
- let Test = () => (
221
- <button
222
- ref={buttonRef}
223
- responders={[<TestResponder />, <TestResponder />]}>
224
- Click me!
225
- </button>
226
- );
237
+ function Test() {
238
+ const listener = React.unstable_useResponder(TestResponder, {});
239
+ const listener2 = React.unstable_useResponder(TestResponder, {});
240
228
- ReactDOM.render(<Test />, container);
241
+ return (
242
+ <button ref={buttonRef} listeners={[listener, listener2]}>
243
+ Click me!
244
+ </button>
245
+ );
246
+ }
247
+
248
+ expect(() => {
249
+ ReactDOM.render(<Test />, container);
250
+ }).toWarnDev(
251
+ 'Duplicate event responder "TestEventResponder" found in event listeners. ' +
252
+ 'Event listeners passed to elements cannot use the same event responder more than once.',
253
+ );
254
255
// Clicking the button should trigger the event responder onEvent()
256
let buttonElement = buttonRef.current;
@@ -244,15 +269,19 @@ describe('DOMEventResponderSystem', () => {
269
270
eventLog = [];
271
247
- Test = () => (
248
- <div responders={<TestResponder />}>
249
- <button ref={buttonRef} responders={<TestResponder />}>
250
- Click me!
251
- </button>
252
- </div>
253
- );
272
+ function Test2() {
273
+ const listener = React.unstable_useResponder(TestResponder, {});
274
255
- ReactDOM.render(<Test />, container);
275
+ return (
276
+ <div listeners={listener}>
277
+ <button ref={buttonRef} listeners={listener}>
278
+ Click me!
279
+ </button>
280
+ </div>
281
+ );
282
+ }
283
+
284
+ ReactDOM.render(<Test2 />, container);
285
286
// Clicking the button should trigger the event responder onEvent()
287
buttonElement = buttonRef.current;
@@ -288,13 +317,16 @@ describe('DOMEventResponderSystem', () => {
317
},
318
});
319
291
- let Test = () => (
292
- <button
293
- ref={buttonRef}
294
- responders={[<TestResponderA />, <TestResponderB />]}>
295
- Click me!
296
- </button>
297
- );
320
+ function Test() {
321
+ const listener = React.unstable_useResponder(TestResponderA, {});
322
+ const listener2 = React.unstable_useResponder(TestResponderB, {});
323
+
324
+ return (
325
+ <button ref={buttonRef} listeners={[listener, listener2]}>
326
+ Click me!
327
+ </button>
328
+ );
329
+ }
330
331
ReactDOM.render(<Test />, container);
332
@@ -306,15 +338,20 @@ describe('DOMEventResponderSystem', () => {
338
339
eventLog = [];
340
309
- Test = () => (
310
- <div responders={<TestResponderA />}>
311
- <button ref={buttonRef} responders={<TestResponderB />}>
312
- Click me!
313
- </button>
314
- </div>
315
- );
341
+ function Test2() {
342
+ const listener = React.unstable_useResponder(TestResponderA, {});
343
+ const listener2 = React.unstable_useResponder(TestResponderB, {});
344
317
- ReactDOM.render(<Test />, container);
345
+ return (
346
+ <div listeners={listener}>
347
+ <button ref={buttonRef} listeners={listener2}>
348
+ Click me!
349
+ </button>
350
+ </div>
351
+ );
352
+ }
353
+
354
+ ReactDOM.render(<Test2 />, container);
355
356
// Clicking the button should trigger the event responder onEvent()
357
buttonElement = buttonRef.current;
@@ -323,7 +360,7 @@ describe('DOMEventResponderSystem', () => {
360
expect(eventLog).toEqual(['B [bubble]', 'A [bubble]']);
361
});
362
326
- it('nested event responders should fire in the correct order', () => {
363
+ it('nested event responders should fire in the correct order #2', () => {
364
let eventLog = [];
365
const buttonRef = React.createRef();
366
@@ -334,13 +371,17 @@ describe('DOMEventResponderSystem', () => {
371
},
372
});
373
337
- const Test = () => (
338
- <div responders={<TestResponder name="A" />}>
339
- <button ref={buttonRef} responders={<TestResponder name="B" />}>
340
- Click me!
341
- </button>
342
- </div>
343
- );
374
+ const Test = () => {
375
+ const listener = React.unstable_useResponder(TestResponder, {name: 'A'});
376
+ const listener2 = React.unstable_useResponder(TestResponder, {name: 'B'});
377
+ return (
378
+ <div listeners={listener}>
379
+ <button ref={buttonRef} listeners={listener2}>
380
+ Click me!
381
+ </button>
382
+ </div>
383
+ );
384
+ };
385
386
ReactDOM.render(<Test />, container);
387
@@ -364,7 +405,11 @@ describe('DOMEventResponderSystem', () => {
405
phase: 'bubble',
406
timeStamp: context.getTimeStamp(),
407
};
367
- context.dispatchEvent('onMagicClick', syntheticEvent, DiscreteEvent);
408
+ context.dispatchEvent(
409
+ syntheticEvent,
410
+ props.onMagicClick,
411
+ DiscreteEvent,
412
+ );
413
},
414
});
415
@@ -373,12 +418,12 @@ describe('DOMEventResponderSystem', () => {
418
}
419
420
const Test = () => {
376
- React.unstable_useListener(TestResponder, {
421
+ const listener = React.unstable_useResponder(TestResponder, {
422
onMagicClick: handleMagicEvent,
423
});
424
425
return (
381
- <button ref={buttonRef} responders={<TestResponder />}>
426
+ <button ref={buttonRef} listeners={listener}>
427
Click me!
428
</button>
429
);
@@ -404,7 +449,7 @@ describe('DOMEventResponderSystem', () => {
449
phase,
450
timeStamp: context.getTimeStamp(),
451
};
407
- context.dispatchEvent('onPress', pressEvent, DiscreteEvent);
452
+ context.dispatchEvent(pressEvent, props.onPress, DiscreteEvent);
453
454
context.setTimeout(() => {
455
const longPressEvent = {
@@ -413,7 +458,7 @@ describe('DOMEventResponderSystem', () => {
458
phase,
459
timeStamp: context.getTimeStamp(),
460
};
416
- context.dispatchEvent('onLongPress', longPressEvent, DiscreteEvent);
461
+ context.dispatchEvent(longPressEvent, props.onLongPress, DiscreteEvent);
462
463
const longPressChangeEvent = {
464
target: event.target,
@@ -422,8 +467,8 @@ describe('DOMEventResponderSystem', () => {
467
timeStamp: context.getTimeStamp(),
468
};
469
context.dispatchEvent(
425
- 'onLongPressChange',
470
longPressChangeEvent,
471
+ props.onLongPressChange,
472
DiscreteEvent,
473
);
474
}, 500);
@@ -441,14 +486,14 @@ describe('DOMEventResponderSystem', () => {
486
}
487
488
const Test = () => {
444
- React.unstable_useListener(TestResponder, {
489
+ const listener = React.unstable_useResponder(TestResponder, {
490
onPress: e => log('press ' + e.phase),
491
onLongPress: e => log('longpress ' + e.phase),
492
onLongPressChange: e => log('longpresschange ' + e.phase),
493
});
494
495
return (
451
- <button ref={buttonRef} responders={<TestResponder />}>
496
+ <button ref={buttonRef} listeners={listener}>
497
Click me!
498
</button>
499
);
@@ -485,16 +530,19 @@ describe('DOMEventResponderSystem', () => {
530
},
531
});
532
488
- ReactDOM.render(
489
- <button responders={[<TestResponder />, <TestResponder2 />]} />,
490
- container,
491
- );
533
+ function Test({toggle}) {
534
+ const listener = React.unstable_useResponder(TestResponder, {});
535
+ const listener2 = React.unstable_useResponder(TestResponder2, {});
536
+ if (toggle) {
537
+ return <button listeners={[listener2, listener]} />;
538
+ }
539
+ return <button listeners={[listener, listener2]} />;
540
+ }
541
+
542
+ ReactDOM.render(<Test />, container);
543
expect(onMountFired).toEqual(2);
544
494
- ReactDOM.render(
495
- <button responders={[<TestResponder2 />, <TestResponder />]} />,
496
- container,
497
- );
545
+ ReactDOM.render(<Test toggle={true} />, container);
546
expect(onMountFired).toEqual(2);
547
});
548
@@ -508,24 +556,39 @@ describe('DOMEventResponderSystem', () => {
556
},
557
});
558
511
- ReactDOM.render(<button responders={[<TestResponder />]} />, container);
559
+ function Test({test}) {
560
+ const listener = React.unstable_useResponder(TestResponder, {});
561
+ if (test === 0) {
562
+ return <button listeners={[listener]} />;
563
+ } else if (test === 1) {
564
+ return <button listeners={null} />;
565
+ } else if (test === 2) {
566
+ return <button listeners={[]} />;
567
+ } else if (test === 3) {
568
+ return <button />;
569
+ } else if (test === 4) {
570
+ return <button listeners={listener} />;
571
+ }
572
+ }
573
+
574
+ ReactDOM.render(<Test test={0} />, container);
575
ReactDOM.render(null, container);
576
expect(onUnmountFired).toEqual(1);
577
515
- ReactDOM.render(<button responders={[<TestResponder />]} />, container);
516
- ReactDOM.render(<button responders={null} />, container);
578
+ ReactDOM.render(<Test test={0} />, container);
579
+ ReactDOM.render(<Test test={1} />, container);
580
expect(onUnmountFired).toEqual(2);
581
519
- ReactDOM.render(<button responders={[<TestResponder />]} />, container);
520
- ReactDOM.render(<button responders={[]} />, container);
582
+ ReactDOM.render(<Test test={0} />, container);
583
+ ReactDOM.render(<Test test={2} />, container);
584
expect(onUnmountFired).toEqual(3);
585
523
- ReactDOM.render(<button responders={[<TestResponder />]} />, container);
524
- ReactDOM.render(<button />, container);
586
+ ReactDOM.render(<Test test={0} />, container);
587
+ ReactDOM.render(<Test test={3} />, container);
588
expect(onUnmountFired).toEqual(4);
589
527
- ReactDOM.render(<button responders={[<TestResponder />]} />, container);
528
- ReactDOM.render(<button responders={<TestResponder />} />, container);
590
+ ReactDOM.render(<Test test={0} />, container);
591
+ ReactDOM.render(<Test test={4} />, container);
592
expect(onUnmountFired).toEqual(4);
593
});
594
@@ -542,7 +605,10 @@ describe('DOMEventResponderSystem', () => {
605
},
606
});
607
545
- const Test = () => <button responders={<TestResponder />} />;
608
+ const Test = () => {
609
+ const listener = React.unstable_useResponder(TestResponder, {});
610
+ return <button listeners={listener} />;
611
+ };
612
613
ReactDOM.render(<Test />, container);
614
ReactDOM.render(null, container);
@@ -564,9 +630,10 @@ describe('DOMEventResponderSystem', () => {
630
},
631
});
632
567
- const Test = () => (
568
- <button ref={buttonRef} responders={<TestResponder />} />
569
- );
633
+ const Test = () => {
634
+ const listener = React.unstable_useResponder(TestResponder, {});
635
+ return <button ref={buttonRef} listeners={listener} />;
636
+ };
637
638
ReactDOM.render(<Test />, container);
639
@@ -596,9 +663,10 @@ describe('DOMEventResponderSystem', () => {
663
},
664
});
665
599
- const Test = () => (
600
- <button responders={<TestResponder />}>Click me!</button>
601
- );
666
+ const Test = () => {
667
+ const listener = React.unstable_useResponder(TestResponder, {});
668
+ return <button listeners={listener}>Click me!</button>;
669
+ };
670
671
ReactDOM.render(<Test />, container);
672
expect(container.innerHTML).toBe('<button>Click me!</button>');
@@ -647,13 +715,18 @@ describe('DOMEventResponderSystem', () => {
715
},
716
});
717
650
- const Test = () => (
651
- <div responders={<TestResponderA />}>
652
- <button ref={buttonRef} responders={<TestResponderB />}>
653
- Click me!
654
- </button>
655
- </div>
656
- );
718
+ const Test = () => {
719
+ const listener = React.unstable_useResponder(TestResponderA, {});
720
+ const listener2 = React.unstable_useResponder(TestResponderB, {});
721
+
722
+ return (
723
+ <div listeners={listener}>
724
+ <button ref={buttonRef} listeners={listener2}>
725
+ Click me!
726
+ </button>
727
+ </div>
728
+ );
729
+ };
730
731
ReactDOM.render(<Test />, container);
732
@@ -706,11 +779,16 @@ describe('DOMEventResponderSystem', () => {
779
},
780
});
781
709
- const Test = () => (
710
- <div responders={<TestResponderA />}>
711
- <button responders={<TestResponderB />}>Click me!</button>
712
- </div>
713
- );
782
+ const Test = () => {
783
+ const listener = React.unstable_useResponder(TestResponderA, {});
784
+ const listener2 = React.unstable_useResponder(TestResponderB, {});
785
+
786
+ return (
787
+ <div listeners={listener}>
788
+ <button listeners={listener2}>Click me!</button>
789
+ </div>
790
+ );
791
+ };
792
793
ReactDOM.render(<Test />, container);
794
@@ -744,17 +822,17 @@ describe('DOMEventResponderSystem', () => {
822
type: 'click',
823
timeStamp: context.getTimeStamp(),
824
};
747
- context.dispatchEvent('onClick', syntheticEvent, DiscreteEvent);
825
+ context.dispatchEvent(syntheticEvent, props.onClick, DiscreteEvent);
826
},
827
});
828
829
let handler;
830
const Test = () => {
753
- React.unstable_useListener(TestResponder, {
831
+ const listener = React.unstable_useResponder(TestResponder, {
832
onClick: handler,
833
});
834
757
- return <button responders={<TestResponder />}>Click me!</button>;
835
+ return <button listeners={listener}>Click me!</button>;
836
};
837
expect(() => {
838
handler = event => {
@@ -819,7 +897,7 @@ describe('DOMEventResponderSystem', () => {
897
expect(container.innerHTML).toBe('<button>Click me!</button>');
898
});
899
822
- it('should work with event listener hooks', () => {
900
+ it('should work with event responder hooks', () => {
901
const buttonRef = React.createRef();
902
const eventLogs = [];
903
const TestResponder = createEventResponder({
@@ -830,16 +908,16 @@ describe('DOMEventResponderSystem', () => {
908
type: 'foo',
909
timeStamp: context.getTimeStamp(),
910
};
833
- context.dispatchEvent('onFoo', fooEvent, DiscreteEvent);
911
+ context.dispatchEvent(fooEvent, props.onFoo, DiscreteEvent);
912
},
913
});
914
915
const Test = () => {
838
- React.unstable_useListener(TestResponder, {
916
+ const listener = React.unstable_useResponder(TestResponder, {
917
onFoo: e => eventLogs.push('hook'),
918
});
919
842
- return <button ref={buttonRef} responders={<TestResponder />} />;
920
+ return <button ref={buttonRef} listeners={listener} />;
921
};
922
923
ReactDOM.render(<Test />, container);
@@ -850,11 +928,11 @@ describe('DOMEventResponderSystem', () => {
928
eventLogs.length = 0;
929
930
const Test2 = () => {
853
- React.unstable_useListener(TestResponder, {
931
+ const listener = React.unstable_useResponder(TestResponder, {
932
onFoo: e => eventLogs.push('hook'),
933
});
934
857
- return <button ref={buttonRef} responders={<TestResponder />} />;
935
+ return <button ref={buttonRef} listeners={listener} />;
936
};
937
938
ReactDOM.render(<Test2 />, container);
packages/react-dom/src/server/ReactPartialRenderer.js
+1
-1
@@ -360,7 +360,7 @@ function createOpenTagMarkup(
360
if (!hasOwnProperty.call(props, propKey)) {
361
continue;
362
}
363
- if (enableFlareAPI && propKey === 'responders') {
363
+ if (enableFlareAPI && propKey === 'listeners') {
364
continue;
365
}
366
let propValue = props[propKey];
packages/react-dom/src/server/ReactPartialRendererHooks.js
+12
-2
@@ -9,7 +9,10 @@
9
10
import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberHooks';
11
import type {ThreadID} from './ReactThreadIDAllocator';
12
-import type {ReactContext} from 'shared/ReactTypes';
12
+import type {
13
+ ReactContext,
14
+ ReactEventResponderListener,
15
+} from 'shared/ReactTypes';
16
17
import {validateContextBounds} from './ReactPartialRendererContext';
18
@@ -447,6 +450,13 @@ export function useCallback<T>(
450
return callback;
451
}
452
453
+function useResponder(responder, props): ReactEventResponderListener<any, any> {
454
+ return {
455
+ props,
456
+ responder,
457
+ };
458
+}
459
+
460
function noop(): void {}
461
462
export let currentThreadID: ThreadID = 0;
@@ -470,5 +480,5 @@ export const Dispatcher: DispatcherType = {
480
useEffect: noop,
481
// Debugging effect
482
useDebugValue: noop,
473
- useListener: noop,
483
+ useResponder,
484
};
packages/react-dom/src/shared/ReactControlledValuePropTypes.js
+2
-2
@@ -36,7 +36,7 @@ if (__DEV__) {
36
props.readOnly ||
37
props.disabled ||
38
props[propName] == null ||
39
- (enableFlareAPI && props.responders)
39
+ (enableFlareAPI && props.listeners)
40
) {
41
return null;
42
}
@@ -53,7 +53,7 @@ if (__DEV__) {
53
props.readOnly ||
54
props.disabled ||
55
props[propName] == null ||
56
- (enableFlareAPI && props.responders)
56
+ (enableFlareAPI && props.listeners)
57
) {
58
return null;
59
}
packages/react-events/src/dom/Drag.js
+65
-39
@@ -11,7 +11,10 @@ import type {
11
ReactDOMResponderEvent,
12
ReactDOMResponderContext,
13
} from 'shared/ReactDOMTypes';
14
-import type {EventPriority} from 'shared/ReactTypes';
14
+import type {
15
+ EventPriority,
16
+ ReactEventResponderListener,
17
+} from 'shared/ReactTypes';
18
19
import React from 'react';
20
import {DiscreteEvent, UserBlockingEvent} from 'shared/ReactTypes';
@@ -19,14 +22,16 @@ import {DiscreteEvent, UserBlockingEvent} from 'shared/ReactTypes';
22
const targetEventTypes = ['pointerdown'];
23
const rootEventTypes = ['pointerup', 'pointercancel', 'pointermove_active'];
24
22
-type DragListenerProps = {|
25
+type DragProps = {
26
+ disabled: boolean,
27
+ shouldClaimOwnership: () => boolean,
28
onDragStart: (e: DragEvent) => void,
29
onDragMove: (e: DragEvent) => void,
30
onDragEnd: (e: DragEvent) => void,
31
onDragChange: boolean => void,
27
-|};
32
+};
33
29
-type DragState = {
34
+type DragState = {|
35
dragTarget: null | Element | Document,
36
isPointerDown: boolean,
37
isDragging: boolean,
@@ -35,7 +40,7 @@ type DragState = {
40
x: number,
41
y: number,
42
ownershipClaimed: boolean,
38
-};
43
+|};
44
45
// In the case we don't have PointerEvents (Safari), we listen to touch events
46
// too
@@ -78,9 +83,13 @@ function createDragEvent(
83
};
84
}
85
86
+function isFunction(obj): boolean {
87
+ return typeof obj === 'function';
88
+}
89
+
90
function dispatchDragEvent(
82
- eventPropName: string,
91
context: ReactDOMResponderContext,
92
+ listener: DragEvent => void,
93
name: DragEventType,
94
state: DragState,
95
eventPriority: EventPriority,
@@ -88,7 +97,7 @@ function dispatchDragEvent(
97
): void {
98
const target = ((state.dragTarget: any): Element | Document);
99
const syntheticEvent = createDragEvent(context, name, target, eventData);
91
- context.dispatchEvent(eventPropName, syntheticEvent, eventPriority);
100
+ context.dispatchEvent(syntheticEvent, listener, eventPriority);
101
}
102
103
const dragResponderImpl = {
@@ -108,7 +117,7 @@ const dragResponderImpl = {
117
onEvent(
118
event: ReactDOMResponderEvent,
119
context: ReactDOMResponderContext,
111
- props: Object,
120
+ props: DragProps,
121
state: DragState,
122
): void {
123
const {target, type, nativeEvent} = event;
@@ -128,14 +137,17 @@ const dragResponderImpl = {
137
state.y = y;
138
state.dragTarget = target;
139
state.isPointerDown = true;
140
+ const onDragStart = props.onDragStart;
141
132
- dispatchDragEvent(
133
- 'onDragStart',
134
- context,
135
- 'dragstart',
136
- state,
137
- DiscreteEvent,
138
- );
142
+ if (isFunction(onDragStart)) {
143
+ dispatchDragEvent(
144
+ context,
145
+ onDragStart,
146
+ 'dragstart',
147
+ state,
148
+ DiscreteEvent,
149
+ );
150
+ }
151
context.addRootEventTypes(rootEventTypes);
152
}
153
break;
@@ -145,7 +157,7 @@ const dragResponderImpl = {
157
onRootEvent(
158
event: ReactDOMResponderEvent,
159
context: ReactDOMResponderContext,
148
- props: Object,
160
+ props: DragProps,
161
state: DragState,
162
): void {
163
const {type, nativeEvent} = event;
@@ -180,25 +192,31 @@ const dragResponderImpl = {
192
}
193
if (shouldEnableDragging) {
194
state.isDragging = true;
183
- context.dispatchEvent('onDragChange', true, UserBlockingEvent);
195
+ const onDragChange = props.onDragChange;
196
+ if (isFunction(onDragChange)) {
197
+ context.dispatchEvent(true, onDragChange, UserBlockingEvent);
198
+ }
199
} else {
200
state.dragTarget = null;
201
state.isPointerDown = false;
202
context.removeRootEventTypes(rootEventTypes);
203
}
204
} else {
190
- const eventData = {
191
- diffX: x - state.startX,
192
- diffY: y - state.startY,
193
- };
194
- dispatchDragEvent(
195
- 'onDragMove',
196
- context,
197
- 'dragmove',
198
- state,
199
- UserBlockingEvent,
200
- eventData,
201
- );
205
+ const onDragMove = props.onDragMove;
206
+ if (isFunction(onDragMove)) {
207
+ const eventData = {
208
+ diffX: x - state.startX,
209
+ diffY: y - state.startY,
210
+ };
211
+ dispatchDragEvent(
212
+ context,
213
+ onDragMove,
214
+ 'dragmove',
215
+ state,
216
+ UserBlockingEvent,
217
+ eventData,
218
+ );
219
+ }
220
(nativeEvent: any).preventDefault();
221
}
222
}
@@ -213,14 +231,20 @@ const dragResponderImpl = {
231
if (state.ownershipClaimed) {
232
context.releaseOwnership();
233
}
216
- dispatchDragEvent(
217
- 'onDragEnd',
218
- context,
219
- 'dragend',
220
- state,
221
- DiscreteEvent,
222
- );
223
- context.dispatchEvent('onDragChange', false, UserBlockingEvent);
234
+ const onDragEnd = props.onDragEnd;
235
+ if (isFunction(onDragEnd)) {
236
+ dispatchDragEvent(
237
+ context,
238
+ onDragEnd,
239
+ 'dragend',
240
+ state,
241
+ DiscreteEvent,
242
+ );
243
+ }
244
+ const onDragChange = props.onDragChange;
245
+ if (isFunction(onDragChange)) {
246
+ context.dispatchEvent(false, onDragChange, UserBlockingEvent);
247
+ }
248
state.isDragging = false;
249
}
250
if (state.isPointerDown) {
@@ -239,6 +263,8 @@ export const DragResponder = React.unstable_createResponder(
263
dragResponderImpl,
264
);
265
242
-export function useDragListener(props: DragListenerProps): void {
243
- React.unstable_useListener(DragResponder, props);
266
+export function useDragResponder(
267
+ props: DragProps,
268
+): ReactEventResponderListener<any, any> {
269
+ return React.unstable_useResponder(DragResponder, props);
270
}
packages/react-events/src/dom/Focus.js
+66
-31
@@ -12,6 +12,7 @@ import type {
12
ReactDOMResponderContext,
13
PointerType,
14
} from 'shared/ReactDOMTypes';
15
+import type {ReactEventResponderListener} from 'shared/ReactTypes';
16
17
import React from 'react';
18
import {DiscreteEvent} from 'shared/ReactTypes';
@@ -34,26 +35,20 @@ type FocusState = {
35
pointerType: PointerType,
36
};
37
37
-type FocusListenerProps = {|
38
+type FocusProps = {
39
+ disabled: boolean,
40
onBlur: (e: FocusEvent) => void,
41
onFocus: (e: FocusEvent) => void,
42
onFocusChange: boolean => void,
43
onFocusVisibleChange: boolean => void,
42
-|};
43
-
44
-type FocusProps = {
45
- disabled: boolean,
44
};
45
46
type FocusEventType = 'focus' | 'blur' | 'focuschange' | 'focusvisiblechange';
47
50
-type FocusWithinListenerProps = {|
51
- onFocusWithinChange: boolean => void,
52
- onFocusWithinVisibleChange: boolean => void,
53
-|};
54
-
48
type FocusWithinProps = {
49
disabled: boolean,
50
+ onFocusWithinChange: boolean => void,
51
+ onFocusWithinVisibleChange: boolean => void,
52
};
53
54
type FocusWithinEventType = 'focuswithinvisiblechange' | 'focuswithinchange';
@@ -91,6 +86,10 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
86
);
87
}
88
89
+function isFunction(obj): boolean {
90
+ return typeof obj === 'function';
91
+}
92
+
93
function createFocusEvent(
94
context: ReactDOMResponderContext,
95
type: FocusEventType | FocusWithinEventType,
@@ -195,16 +194,19 @@ function dispatchFocusEvents(
194
) {
195
const pointerType = state.pointerType;
196
const target = ((state.focusTarget: any): Element | Document);
198
- const syntheticEvent = createFocusEvent(
199
- context,
200
- 'focus',
201
- target,
202
- pointerType,
203
- );
204
- context.dispatchEvent('onFocus', syntheticEvent, DiscreteEvent);
205
- context.dispatchEvent('onFocusChange', true, DiscreteEvent);
197
+ const onFocus = props.onFocus;
198
+ if (isFunction(onFocus)) {
199
+ const syntheticEvent = createFocusEvent(
200
+ context,
201
+ 'focus',
202
+ target,
203
+ pointerType,
204
+ );
205
+ context.dispatchEvent(syntheticEvent, onFocus, DiscreteEvent);
206
+ }
207
+ dispatchFocusChange(context, props, true);
208
if (state.isFocusVisible) {
207
- dispatchFocusVisibleChangeEvent(context, true);
209
+ dispatchFocusVisibleChangeEvent(context, props, true);
210
}
211
}
212
@@ -215,19 +217,42 @@ function dispatchBlurEvents(
217
) {
218
const pointerType = state.pointerType;
219
const target = ((state.focusTarget: any): Element | Document);
218
- const syntheticEvent = createFocusEvent(context, 'blur', target, pointerType);
219
- context.dispatchEvent('onBlur', syntheticEvent, DiscreteEvent);
220
- context.dispatchEvent('onFocusChange', false, DiscreteEvent);
220
+ const onBlur = props.onBlur;
221
+ if (isFunction(onBlur)) {
222
+ const syntheticEvent = createFocusEvent(
223
+ context,
224
+ 'blur',
225
+ target,
226
+ pointerType,
227
+ );
228
+ context.dispatchEvent(syntheticEvent, onBlur, DiscreteEvent);
229
+ }
230
+ dispatchFocusChange(context, props, false);
231
if (state.isFocusVisible) {
222
- dispatchFocusVisibleChangeEvent(context, false);
232
+ dispatchFocusVisibleChangeEvent(context, props, false);
233
+ }
234
+}
235
+
236
+function dispatchFocusChange(
237
+ context: ReactDOMResponderContext,
238
+ props: FocusProps,
239
+ value: boolean,
240
+): void {
241
+ const onFocusChange = props.onFocusChange;
242
+ if (isFunction(onFocusChange)) {
243
+ context.dispatchEvent(value, onFocusChange, DiscreteEvent);
244
}
245
}
246
247
function dispatchFocusVisibleChangeEvent(
248
context: ReactDOMResponderContext,
249
+ props: FocusProps,
250
value: boolean,
251
) {
230
- context.dispatchEvent('onFocusVisibleChange', value, DiscreteEvent);
252
+ const onFocusVisibleChange = props.onFocusVisibleChange;
253
+ if (isFunction(onFocusVisibleChange)) {
254
+ context.dispatchEvent(value, onFocusVisibleChange, DiscreteEvent);
255
+ }
256
}
257
258
function unmountFocusResponder(
@@ -299,7 +324,7 @@ const focusResponderImpl = {
324
handleRootEvent(event, context, state, isFocusVisible => {
325
if (state.isFocusVisible !== isFocusVisible) {
326
state.isFocusVisible = isFocusVisible;
302
- dispatchFocusVisibleChangeEvent(context, isFocusVisible);
327
+ dispatchFocusVisibleChangeEvent(context, props, isFocusVisible);
328
}
329
});
330
},
@@ -324,8 +349,10 @@ export const FocusResponder = React.unstable_createResponder(
349
focusResponderImpl,
350
);
351
327
-export function useFocusListener(props: FocusListenerProps): void {
328
- React.unstable_useListener(FocusResponder, props);
352
+export function useFocusResponder(
353
+ props: FocusProps,
354
+): ReactEventResponderListener<any, any> {
355
+ return React.unstable_useResponder(FocusResponder, props);
356
}
357
358
/**
@@ -338,7 +365,10 @@ function dispatchFocusWithinChangeEvent(
365
state: FocusState,
366
value: boolean,
367
) {
341
- context.dispatchEvent('onFocusWithinChange', value, DiscreteEvent);
368
+ const onFocusWithinChange = props.onFocusWithinChange;
369
+ if (isFunction(onFocusWithinChange)) {
370
+ context.dispatchEvent(value, onFocusWithinChange, DiscreteEvent);
371
+ }
372
if (state.isFocusVisible) {
373
dispatchFocusWithinVisibleChangeEvent(context, props, state, value);
374
}
@@ -350,7 +380,10 @@ function dispatchFocusWithinVisibleChangeEvent(
380
state: FocusState,
381
value: boolean,
382
) {
353
- context.dispatchEvent('onFocusWithinVisibleChange', value, DiscreteEvent);
383
+ const onFocusWithinVisibleChange = props.onFocusWithinVisibleChange;
384
+ if (isFunction(onFocusWithinVisibleChange)) {
385
+ context.dispatchEvent(value, onFocusWithinVisibleChange, DiscreteEvent);
386
+ }
387
}
388
389
function unmountFocusWithinResponder(
@@ -459,6 +492,8 @@ export const FocusWithinResponder = React.unstable_createResponder(
492
focusWithinResponderImpl,
493
);
494
462
-export function useFocusWithinListener(props: FocusWithinListenerProps): void {
463
- React.unstable_useListener(FocusWithinResponder, props);
495
+export function useFocusWithinResponder(
496
+ props: FocusWithinProps,
497
+): ReactEventResponderListener<any, any> {
498
+ return React.unstable_useResponder(FocusWithinResponder, props);
499
}
packages/react-events/src/dom/Hover.js
+40
-27
@@ -11,20 +11,18 @@ import type {
11
ReactDOMResponderEvent,
12
ReactDOMResponderContext,
13
} from 'shared/ReactDOMTypes';
14
+import type {ReactEventResponderListener} from 'shared/ReactTypes';
15
16
import React from 'react';
17
import {UserBlockingEvent} from 'shared/ReactTypes';
18
18
-type HoverListenerProps = {|
19
+type HoverProps = {
20
+ disabled: boolean,
21
+ preventDefault: boolean,
22
onHoverChange: boolean => void,
23
onHoverEnd: (e: HoverEvent) => void,
24
onHoverMove: (e: HoverEvent) => void,
25
onHoverStart: (e: HoverEvent) => void,
23
-|};
24
-
25
-type HoverProps = {
26
- disabled: boolean,
27
- preventDefault: boolean,
26
};
27
28
type HoverState = {
@@ -65,6 +63,10 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
63
targetEventTypes.push('touchstart', 'mouseover', 'mousemove', 'mouseout');
64
}
65
66
+function isFunction(obj): boolean {
67
+ return typeof obj === 'function';
68
+}
69
+
70
function createHoverEvent(
71
event: ?ReactDOMResponderEvent,
72
context: ReactDOMResponderContext,
@@ -104,8 +106,11 @@ function dispatchHoverChangeEvent(
106
props: HoverProps,
107
state: HoverState,
108
): void {
107
- const bool = state.isActiveHovered;
108
- context.dispatchEvent('onHoverChange', bool, UserBlockingEvent);
109
+ const onHoverChange = props.onHoverChange;
110
+ if (isFunction(onHoverChange)) {
111
+ const bool = state.isActiveHovered;
112
+ context.dispatchEvent(bool, onHoverChange, UserBlockingEvent);
113
+ }
114
}
115
116
function dispatchHoverStartEvents(
@@ -133,13 +138,16 @@ function dispatchHoverStartEvents(
138
139
if (!state.isActiveHovered) {
140
state.isActiveHovered = true;
136
- const syntheticEvent = createHoverEvent(
137
- event,
138
- context,
139
- 'hoverstart',
140
- ((target: any): Element | Document),
141
- );
142
- context.dispatchEvent('onHoverStart', syntheticEvent, UserBlockingEvent);
141
+ const onHoverStart = props.onHoverStart;
142
+ if (isFunction(onHoverStart)) {
143
+ const syntheticEvent = createHoverEvent(
144
+ event,
145
+ context,
146
+ 'hoverstart',
147
+ ((target: any): Element | Document),
148
+ );
149
+ context.dispatchEvent(syntheticEvent, onHoverStart, UserBlockingEvent);
150
+ }
151
dispatchHoverChangeEvent(event, context, props, state);
152
}
153
}
@@ -169,14 +177,16 @@ function dispatchHoverEndEvents(
177
178
if (state.isActiveHovered) {
179
state.isActiveHovered = false;
172
-
173
- const syntheticEvent = createHoverEvent(
174
- event,
175
- context,
176
- 'hoverend',
177
- ((target: any): Element | Document),
178
- );
179
- context.dispatchEvent('onHoverEnd', syntheticEvent, UserBlockingEvent);
180
+ const onHoverEnd = props.onHoverEnd;
181
+ if (isFunction(onHoverEnd)) {
182
+ const syntheticEvent = createHoverEvent(
183
+ event,
184
+ context,
185
+ 'hoverend',
186
+ ((target: any): Element | Document),
187
+ );
188
+ context.dispatchEvent(syntheticEvent, onHoverEnd, UserBlockingEvent);
189
+ }
190
dispatchHoverChangeEvent(event, context, props, state);
191
state.hoverTarget = null;
192
state.ignoreEmulatedMouseEvents = false;
@@ -262,7 +272,8 @@ const hoverResponderImpl = {
272
case 'pointermove':
273
case 'mousemove': {
274
if (state.isHovered && !isEmulatedMouseEvent(event, state)) {
265
- if (state.hoverTarget !== null) {
275
+ const onHoverMove = props.onHoverMove;
276
+ if (state.hoverTarget !== null && isFunction(onHoverMove)) {
277
const syntheticEvent = createHoverEvent(
278
event,
279
context,
@@ -270,8 +281,8 @@ const hoverResponderImpl = {
281
state.hoverTarget,
282
);
283
context.dispatchEvent(
273
- 'onHoverMove',
284
syntheticEvent,
285
+ onHoverMove,
286
UserBlockingEvent,
287
);
288
}
@@ -317,6 +328,8 @@ export const HoverResponder = React.unstable_createResponder(
328
hoverResponderImpl,
329
);
330
320
-export function useHoverListener(props: HoverListenerProps): void {
321
- React.unstable_useListener(HoverResponder, props);
331
+export function useHoverResponder(
332
+ props: HoverProps,
333
+): ReactEventResponderListener<any, any> {
334
+ return React.unstable_useResponder(HoverResponder, props);
335
}
packages/react-events/src/dom/Input.js
+24
-13
@@ -14,17 +14,15 @@ import type {
14
15
import React from 'react';
16
import {DiscreteEvent} from 'shared/ReactTypes';
17
+import type {ReactEventResponderListener} from 'shared/ReactTypes';
18
19
type InputEventType = 'change' | 'beforechange' | 'valuechange';
20
20
-type InputListenerProps = {|
21
+type InputResponderProps = {
22
+ disabled: boolean,
23
onBeforeChange: (e: InputEvent) => void,
24
onChange: (e: InputEvent) => void,
25
onValueChange: (value: string | boolean) => void,
24
-|};
25
-
26
-type InputResponderProps = {
27
- disabled: boolean,
26
};
27
28
type InputEvent = {|
@@ -57,6 +55,10 @@ const supportedInputTypes = new Set([
55
'week',
56
]);
57
58
+function isFunction(obj): boolean {
59
+ return typeof obj === 'function';
60
+}
61
+
62
function createInputEvent(
63
event: ReactDOMResponderEvent,
64
context: ReactDOMResponderContext,
@@ -76,14 +78,14 @@ function createInputEvent(
78
}
79
80
function dispatchInputEvent(
79
- eventPropName: string,
81
event: ReactDOMResponderEvent,
82
+ listener: InputEvent => void,
83
context: ReactDOMResponderContext,
84
type: InputEventType,
85
target: Element | Document,
86
): void {
87
const syntheticEvent = createInputEvent(event, context, type, target);
86
- context.dispatchEvent(eventPropName, syntheticEvent, DiscreteEvent);
88
+ context.dispatchEvent(syntheticEvent, listener, DiscreteEvent);
89
}
90
91
function getNodeName(elem: Element | Document): string {
@@ -115,10 +117,14 @@ function shouldUseChangeEvent(elem: Element | Document): boolean {
117
118
function dispatchChangeEvent(
119
context: ReactDOMResponderContext,
120
+ props: InputResponderProps,
121
target: Element | Document,
122
): void {
120
- const value = getValueFromNode(target);
121
- context.dispatchEvent('onValueChange', value, DiscreteEvent);
123
+ const onValueChange = props.onValueChange;
124
+ if (isFunction(onValueChange)) {
125
+ const value = getValueFromNode(target);
126
+ context.dispatchEvent(value, onValueChange, DiscreteEvent);
127
+ }
128
}
129
130
function dispatchBothChangeEvents(
@@ -128,8 +134,11 @@ function dispatchBothChangeEvents(
134
target: Document | Element,
135
): void {
136
context.enqueueStateRestore(target);
131
- dispatchInputEvent('onChange', event, context, 'change', target);
132
- dispatchChangeEvent(context, target);
137
+ const onChange = props.onChange;
138
+ if (isFunction(onChange)) {
139
+ dispatchInputEvent(event, onChange, context, 'change', target);
140
+ }
141
+ dispatchChangeEvent(context, props, target);
142
}
143
144
function updateValueIfChanged(elem: Element | Document): boolean {
@@ -206,6 +215,8 @@ export const InputResponder = React.unstable_createResponder(
215
inputResponderImpl,
216
);
217
209
-export function useInputListener(props: InputListenerProps): void {
210
- React.unstable_useListener(InputResponder, props);
218
+export function useInputResponder(
219
+ props: InputResponderProps,
220
+): ReactEventResponderListener<any, any> {
221
+ return React.unstable_useResponder(InputResponder, props);
222
}
packages/react-events/src/dom/Keyboard.js
+34
-24
@@ -14,16 +14,14 @@ import type {
14
15
import React from 'react';
16
import {DiscreteEvent} from 'shared/ReactTypes';
17
+import type {ReactEventResponderListener} from 'shared/ReactTypes';
18
19
type KeyboardEventType = 'keydown' | 'keyup';
20
20
-type KeyboardListenerProps = {|
21
+type KeyboardProps = {
22
+ disabled: boolean,
23
onKeyDown: (e: KeyboardEvent) => void,
24
onKeyUp: (e: KeyboardEvent) => void,
23
-|};
24
-
25
-type KeyboardResponderProps = {
26
- disabled: boolean,
25
};
26
27
type KeyboardEvent = {|
@@ -105,6 +103,10 @@ const translateToKey = {
103
'224': 'Meta',
104
};
105
106
+function isFunction(obj): boolean {
107
+ return typeof obj === 'function';
108
+}
109
+
110
function getEventKey(nativeEvent): string {
111
const nativeKey = nativeEvent.key;
112
if (nativeKey) {
@@ -154,14 +156,14 @@ function createKeyboardEvent(
156
}
157
158
function dispatchKeyboardEvent(
157
- eventPropName: string,
159
event: ReactDOMResponderEvent,
160
+ listener: KeyboardEvent => void,
161
context: ReactDOMResponderContext,
162
type: KeyboardEventType,
163
target: Element | Document,
164
): void {
165
const syntheticEvent = createKeyboardEvent(event, context, type, target);
164
- context.dispatchEvent(eventPropName, syntheticEvent, DiscreteEvent);
166
+ context.dispatchEvent(syntheticEvent, listener, DiscreteEvent);
167
}
168
169
const keyboardResponderImpl = {
@@ -169,7 +171,7 @@ const keyboardResponderImpl = {
171
onEvent(
172
event: ReactDOMResponderEvent,
173
context: ReactDOMResponderContext,
172
- props: KeyboardResponderProps,
174
+ props: KeyboardProps,
175
): void {
176
const {responderTarget, type} = event;
177
@@ -177,21 +179,27 @@ const keyboardResponderImpl = {
179
return;
180
}
181
if (type === 'keydown') {
180
- dispatchKeyboardEvent(
181
- 'onKeyDown',
182
- event,
183
- context,
184
- 'keydown',
185
- ((responderTarget: any): Element | Document),
186
- );
182
+ const onKeyDown = props.onKeyDown;
183
+ if (isFunction(onKeyDown)) {
184
+ dispatchKeyboardEvent(
185
+ event,
186
+ onKeyDown,
187
+ context,
188
+ 'keydown',
189
+ ((responderTarget: any): Element | Document),
190
+ );
191
+ }
192
} else if (type === 'keyup') {
188
- dispatchKeyboardEvent(
189
- 'onKeyUp',
190
- event,
191
- context,
192
- 'keyup',
193
- ((responderTarget: any): Element | Document),
194
- );
193
+ const onKeyUp = props.onKeyUp;
194
+ if (isFunction(onKeyUp)) {
195
+ dispatchKeyboardEvent(
196
+ event,
197
+ onKeyUp,
198
+ context,
199
+ 'keyup',
200
+ ((responderTarget: any): Element | Document),
201
+ );
202
+ }
203
}
204
},
205
};
@@ -201,6 +209,8 @@ export const KeyboardResponder = React.unstable_createResponder(
209
keyboardResponderImpl,
210
);
211
204
-export function useKeyboardListener(props: KeyboardListenerProps): void {
205
- React.unstable_useListener(KeyboardResponder, props);
212
+export function useKeyboardResponder(
213
+ props: KeyboardProps,
214
+): ReactEventResponderListener<any, any> {
215
+ return React.unstable_useResponder(KeyboardResponder, props);
216
}
packages/react-events/src/dom/Press.js
+77
-59
@@ -12,20 +12,14 @@ import type {
12
ReactDOMResponderContext,
13
PointerType,
14
} from 'shared/ReactDOMTypes';
15
-import type {EventPriority} from 'shared/ReactTypes';
15
+import type {
16
+ EventPriority,
17
+ ReactEventResponderListener,
18
+} from 'shared/ReactTypes';
19
20
import React from 'react';
21
import {DiscreteEvent, UserBlockingEvent} from 'shared/ReactTypes';
22
20
-type PressListenerProps = {|
21
- onContextMenu: (e: PressEvent) => void,
22
- onPress: (e: PressEvent) => void,
23
- onPressChange: boolean => void,
24
- onPressEnd: (e: PressEvent) => void,
25
- onPressMove: (e: PressEvent) => void,
26
- onPressStart: (e: PressEvent) => void,
27
-|};
28
-
23
type PressProps = {|
24
disabled: boolean,
25
pressRetentionOffset: {
@@ -37,6 +31,12 @@ type PressProps = {|
31
preventContextMenu: boolean,
32
preventDefault: boolean,
33
stopPropagation: boolean,
34
+ onContextMenu: (e: PressEvent) => void,
35
+ onPress: (e: PressEvent) => void,
36
+ onPressChange: boolean => void,
37
+ onPressEnd: (e: PressEvent) => void,
38
+ onPressMove: (e: PressEvent) => void,
39
+ onPressStart: (e: PressEvent) => void,
40
|};
41
42
type PressState = {
@@ -51,7 +51,6 @@ type PressState = {
51
isPressWithinResponderRegion: boolean,
52
pointerType: PointerType,
53
pressTarget: null | Element | Document,
54
- pressStartTimeout: null | number,
54
responderRegionOnActivation: null | $ReadOnly<{|
55
bottom: number,
56
left: number,
@@ -143,6 +142,10 @@ if (typeof window !== 'undefined' && window.PointerEvent === undefined) {
142
);
143
}
144
145
+function isFunction(obj): boolean {
146
+ return typeof obj === 'function';
147
+}
148
+
149
function createPressEvent(
150
context: ReactDOMResponderContext,
151
type: PressEventType,
@@ -202,8 +205,8 @@ function createPressEvent(
205
}
206
207
function dispatchEvent(
205
- eventPropName: string,
208
event: ?ReactDOMResponderEvent,
209
+ listener: any => void,
210
context: ReactDOMResponderContext,
211
state: PressState,
212
name: PressEventType,
@@ -224,15 +227,19 @@ function dispatchEvent(
227
touchEvent,
228
defaultPrevented,
229
);
227
- context.dispatchEvent(eventPropName, syntheticEvent, eventPriority);
230
+ context.dispatchEvent(syntheticEvent, listener, eventPriority);
231
}
232
233
function dispatchPressChangeEvent(
234
context: ReactDOMResponderContext,
235
+ props: PressProps,
236
state: PressState,
237
): void {
234
- const bool = state.isActivePressed;
235
- context.dispatchEvent('onPressChange', bool, DiscreteEvent);
238
+ const onPressChange = props.onPressChange;
239
+ if (isFunction(onPressChange)) {
240
+ const bool = state.isActivePressed;
241
+ context.dispatchEvent(bool, onPressChange, DiscreteEvent);
242
+ }
243
}
244
245
function dispatchPressStartEvents(
@@ -252,17 +259,20 @@ function dispatchPressStartEvents(
259
if (x !== undefined && y !== undefined) {
260
state.activationPosition = {x, y};
261
}
255
-
256
- dispatchEvent(
257
- 'onPressStart',
258
- event,
259
- context,
260
- state,
261
- 'pressstart',
262
- DiscreteEvent,
263
- );
262
+ const onPressStart = props.onPressStart;
263
+
264
+ if (isFunction(onPressStart)) {
265
+ dispatchEvent(
266
+ event,
267
+ onPressStart,
268
+ context,
269
+ state,
270
+ 'pressstart',
271
+ DiscreteEvent,
272
+ );
273
+ }
274
if (!wasActivePressed) {
265
- dispatchPressChangeEvent(context, state);
275
+ dispatchPressChangeEvent(context, props, state);
276
}
277
}
278
}
@@ -278,15 +288,19 @@ function dispatchPressEndEvents(
288
289
if (state.isActivePressed) {
290
state.isActivePressed = false;
281
- dispatchEvent(
282
- 'onPressEnd',
283
- event,
284
- context,
285
- state,
286
- 'pressend',
287
- DiscreteEvent,
288
- );
289
- dispatchPressChangeEvent(context, state);
291
+ const onPressEnd = props.onPressEnd;
292
+
293
+ if (isFunction(onPressEnd)) {
294
+ dispatchEvent(
295
+ event,
296
+ onPressEnd,
297
+ context,
298
+ state,
299
+ 'pressend',
300
+ DiscreteEvent,
301
+ );
302
+ }
303
+ dispatchPressChangeEvent(context, props, state);
304
}
305
306
state.responderRegionOnDeactivation = null;
@@ -299,10 +313,6 @@ function dispatchCancel(
313
state: PressState,
314
): void {
315
state.touchEvent = null;
302
- if (state.pressStartTimeout !== null) {
303
- context.clearTimeout(state.pressStartTimeout);
304
- state.pressStartTimeout = null;
305
- }
316
if (state.isPressed) {
317
state.ignoreEmulatedMouseEvents = false;
318
dispatchPressEndEvents(event, context, props, state);
@@ -488,7 +498,6 @@ const pressResponderImpl = {
498
isPressed: false,
499
isPressWithinResponderRegion: true,
500
pointerType: '',
491
- pressStartTimeout: null,
501
pressTarget: null,
502
responderRegionOnActivation: null,
503
responderRegionOnDeactivation: null,
@@ -624,14 +633,17 @@ const pressResponderImpl = {
633
}
634
dispatchCancel(event, context, props, state);
635
}
627
- dispatchEvent(
628
- 'onContextMenu',
629
- event,
630
- context,
631
- state,
632
- 'contextmenu',
633
- DiscreteEvent,
634
- );
636
+ const onContextMenu = props.onContextMenu;
637
+ if (isFunction(onContextMenu)) {
638
+ dispatchEvent(
639
+ event,
640
+ onContextMenu,
641
+ context,
642
+ state,
643
+ 'contextmenu',
644
+ DiscreteEvent,
645
+ );
646
+ }
647
// Click won't occur, so we need to remove root events
648
removeRootEventTypes(context, state);
649
break;
@@ -701,14 +713,17 @@ const pressResponderImpl = {
713
714
if (state.isPressWithinResponderRegion) {
715
if (isPressed) {
704
- dispatchEvent(
705
- 'onPressMove',
706
- event,
707
- context,
708
- state,
709
- 'pressmove',
710
- UserBlockingEvent,
711
- );
716
+ const onPressMove = props.onPressMove;
717
+ if (isFunction(onPressMove)) {
718
+ dispatchEvent(
719
+ event,
720
+ onPressMove,
721
+ context,
722
+ state,
723
+ 'pressmove',
724
+ UserBlockingEvent,
725
+ );
726
+ }
727
} else {
728
dispatchPressStartEvents(event, context, props, state);
729
}
@@ -775,8 +790,9 @@ const pressResponderImpl = {
790
791
const pressTarget = state.pressTarget;
792
dispatchPressEndEvents(event, context, props, state);
793
+ const onPress = props.onPress;
794
779
- if (pressTarget !== null) {
795
+ if (pressTarget !== null && isFunction(onPress)) {
796
if (
797
!isKeyboardEvent &&
798
pressTarget !== null &&
@@ -801,8 +817,8 @@ const pressResponderImpl = {
817
}
818
if (state.isPressWithinResponderRegion && button !== 1) {
819
dispatchEvent(
804
- 'onPress',
820
event,
821
+ onPress,
822
context,
823
state,
824
'press',
@@ -874,6 +890,8 @@ export const PressResponder = React.unstable_createResponder(
890
pressResponderImpl,
891
);
892
877
-export function usePressListener(props: PressListenerProps): void {
878
- React.unstable_useListener(PressResponder, props);
893
+export function usePressResponder(
894
+ props: PressProps,
895
+): ReactEventResponderListener<any, any> {
896
+ return React.unstable_useResponder(PressResponder, props);
897
}
packages/react-events/src/dom/Scroll.js
+38
-22
@@ -13,20 +13,20 @@ import type {
13
PointerType,
14
} from 'shared/ReactDOMTypes';
15
import {UserBlockingEvent} from 'shared/ReactTypes';
16
-import type {EventPriority} from 'shared/ReactTypes';
16
+import type {
17
+ EventPriority,
18
+ ReactEventResponderListener,
19
+} from 'shared/ReactTypes';
20
21
import React from 'react';
22
20
-type ScrollListenerProps = {
23
+type ScrollProps = {
24
+ disabled: boolean,
25
onScroll: ScrollEvent => void,
26
onScrollDragStart: ScrollEvent => void,
27
onScrollDragEnd: ScrollEvent => void,
28
};
29
26
-type ScrollProps = {
27
- disabled: boolean,
28
-};
29
-
30
type ScrollState = {
31
direction: ScrollDirection,
32
pointerType: PointerType,
@@ -71,6 +71,10 @@ const targetEventTypes = [
71
];
72
const rootEventTypes = ['touchcancel', 'touchend'];
73
74
+function isFunction(obj): boolean {
75
+ return typeof obj === 'function';
76
+}
77
+
78
function createScrollEvent(
79
event: ?ReactDOMResponderEvent,
80
context: ReactDOMResponderContext,
@@ -109,8 +113,8 @@ function createScrollEvent(
113
}
114
115
function dispatchEvent(
112
- eventPropName: string,
116
event: ?ReactDOMResponderEvent,
117
+ listener: ScrollEvent => void,
118
context: ReactDOMResponderContext,
119
state: ScrollState,
120
name: ScrollEventType,
@@ -127,7 +131,7 @@ function dispatchEvent(
131
pointerType,
132
direction,
133
);
130
- context.dispatchEvent(eventPropName, syntheticEvent, eventPriority);
134
+ context.dispatchEvent(syntheticEvent, listener, eventPriority);
135
}
136
137
const scrollResponderImpl = {
@@ -202,23 +206,31 @@ const scrollResponderImpl = {
206
207
if (state.isTouching && !state.isDragging) {
208
state.isDragging = true;
209
+ const onScrollDragStart = props.onScrollDragStart;
210
+
211
+ if (isFunction(onScrollDragStart)) {
212
+ dispatchEvent(
213
+ event,
214
+ onScrollDragStart,
215
+ context,
216
+ state,
217
+ 'scrolldragstart',
218
+ UserBlockingEvent,
219
+ );
220
+ }
221
+ }
222
+ const onScroll = props.onScroll;
223
+
224
+ if (isFunction(onScroll)) {
225
dispatchEvent(
206
- 'onScrollDragStart',
226
event,
227
+ onScroll,
228
context,
229
state,
210
- 'scrolldragstart',
230
+ 'scroll',
231
UserBlockingEvent,
232
);
233
}
214
- dispatchEvent(
215
- 'onScroll',
216
- event,
217
- context,
218
- state,
219
- 'scroll',
220
- UserBlockingEvent,
221
- );
234
break;
235
}
236
case 'keyup': {
@@ -253,10 +265,12 @@ const scrollResponderImpl = {
265
case 'touchcancel':
266
case 'touchend': {
267
if (state.isTouching) {
256
- if (state.isDragging) {
268
+ const onScrollDragEnd = props.onScrollDragEnd;
269
+
270
+ if (state.isDragging && isFunction(onScrollDragEnd)) {
271
dispatchEvent(
258
- 'onScrollDragEnd',
272
event,
273
+ onScrollDragEnd,
274
context,
275
state,
276
'scrolldragend',
@@ -293,6 +307,8 @@ export const ScrollResponder = React.unstable_createResponder(
307
scrollResponderImpl,
308
);
309
296
-export function useScrollListener(props: ScrollListenerProps): void {
297
- React.unstable_useListener(ScrollResponder, props);
310
+export function useScrollResponder(
311
+ props: ScrollProps,
312
+): ReactEventResponderListener<any, any> {
313
+ return React.unstable_useResponder(ScrollResponder, props);
314
}
packages/react-events/src/dom/Swipe.js
+65
-33
@@ -11,11 +11,23 @@ import type {
11
ReactDOMResponderEvent,
12
ReactDOMResponderContext,
13
} from 'shared/ReactDOMTypes';
14
-import type {EventPriority} from 'shared/ReactTypes';
14
+import type {
15
+ EventPriority,
16
+ ReactEventResponderListener,
17
+} from 'shared/ReactTypes';
18
19
import React from 'react';
20
import {UserBlockingEvent, DiscreteEvent} from 'shared/ReactTypes';
21
22
+type SwipeProps = {
23
+ disabled: boolean,
24
+ shouldClaimOwnership: () => boolean,
25
+ onSwipeMove: (e: SwipeEvent) => void,
26
+ onSwipeEnd: (e: SwipeEvent) => void,
27
+ onSwipeLeft: (e: SwipeEvent) => void,
28
+ onSwipeRight: (e: SwipeEvent) => void,
29
+};
30
+
31
const targetEventTypes = ['pointerdown'];
32
const rootEventTypes = ['pointerup', 'pointercancel', 'pointermove_active'];
33
@@ -46,6 +58,10 @@ type SwipeEvent = {|
58
diffY?: number,
59
|};
60
61
+function isFunction(obj): boolean {
62
+ return typeof obj === 'function';
63
+}
64
+
65
function createSwipeEvent(
66
context: ReactDOMResponderContext,
67
type: SwipeEventType,
@@ -63,8 +79,8 @@ function createSwipeEvent(
79
}
80
81
function dispatchSwipeEvent(
66
- eventPropName: string,
82
context: ReactDOMResponderContext,
83
+ listener: SwipeEvent => void,
84
name: SwipeEventType,
85
state: SwipeState,
86
eventPriority: EventPriority,
@@ -72,7 +88,7 @@ function dispatchSwipeEvent(
88
) {
89
const target = ((state.swipeTarget: any): Element | Document);
90
const syntheticEvent = createSwipeEvent(context, name, target, eventData);
75
- context.dispatchEvent(eventPropName, syntheticEvent, eventPriority);
91
+ context.dispatchEvent(syntheticEvent, listener, eventPriority);
92
}
93
94
type SwipeState = {
@@ -107,7 +123,7 @@ const swipeResponderImpl = {
123
onEvent(
124
event: ReactDOMResponderEvent,
125
context: ReactDOMResponderContext,
110
- props: Object,
126
+ props: SwipeProps,
127
state: SwipeState,
128
): void {
129
const {target, type, nativeEvent} = event;
@@ -152,7 +168,7 @@ const swipeResponderImpl = {
168
onRootEvent(
169
event: ReactDOMResponderEvent,
170
context: ReactDOMResponderContext,
155
- props: Object,
171
+ props: SwipeProps,
172
state: SwipeState,
173
): void {
174
const {type, nativeEvent} = event;
@@ -197,14 +213,18 @@ const swipeResponderImpl = {
213
diffX: x - state.startX,
214
diffY: y - state.startY,
215
};
200
- dispatchSwipeEvent(
201
- 'onSwipeMove',
202
- context,
203
- 'swipemove',
204
- state,
205
- UserBlockingEvent,
206
- eventData,
207
- );
216
+ const onSwipeMove = props.onSwipeMove;
217
+
218
+ if (isFunction(onSwipeMove)) {
219
+ dispatchSwipeEvent(
220
+ context,
221
+ onSwipeMove,
222
+ 'swipemove',
223
+ state,
224
+ UserBlockingEvent,
225
+ eventData,
226
+ );
227
+ }
228
(nativeEvent: any).preventDefault();
229
}
230
break;
@@ -224,28 +244,38 @@ const swipeResponderImpl = {
244
const direction = state.direction;
245
const lastDirection = state.lastDirection;
246
if (direction !== lastDirection) {
227
- if (props.onSwipeLeft && direction === 3) {
228
- dispatchSwipeEvent(
229
- 'onSwipeLeft',
230
- context,
231
- 'swipeleft',
232
- state,
233
- DiscreteEvent,
234
- );
235
- } else if (props.onSwipeRight && direction === 1) {
236
- dispatchSwipeEvent(
237
- 'onSwipeRight',
238
- context,
239
- 'swiperight',
240
- state,
241
- DiscreteEvent,
242
- );
247
+ if (direction === 3) {
248
+ const onSwipeLeft = props.onSwipeLeft;
249
+
250
+ if (isFunction(onSwipeLeft)) {
251
+ dispatchSwipeEvent(
252
+ context,
253
+ onSwipeLeft,
254
+ 'swipeleft',
255
+ state,
256
+ DiscreteEvent,
257
+ );
258
+ }
259
+ } else if (direction === 1) {
260
+ const onSwipeRight = props.onSwipeRight;
261
+
262
+ if (isFunction(onSwipeRight)) {
263
+ dispatchSwipeEvent(
264
+ context,
265
+ onSwipeRight,
266
+ 'swiperight',
267
+ state,
268
+ DiscreteEvent,
269
+ );
270
+ }
271
}
272
}
245
- if (props.onSwipeEnd) {
273
+ const onSwipeEnd = props.onSwipeEnd;
274
+
275
+ if (isFunction(onSwipeEnd)) {
276
dispatchSwipeEvent(
247
- 'onSwipeEnd',
277
context,
278
+ onSwipeEnd,
279
'swipeend',
280
state,
281
DiscreteEvent,
@@ -268,6 +298,8 @@ export const SwipeResponder = React.unstable_createResponder(
298
swipeResponderImpl,
299
);
300
271
-export function useSwipeListener(props: Object): void {
272
- React.unstable_useListener(SwipeResponder, props);
301
+export function useSwipeListener(
302
+ props: SwipeProps,
303
+): ReactEventResponderListener<any, any> {
304
+ return React.unstable_useListener(SwipeResponder, props);
305
}
packages/react-events/src/dom/__tests__/Drag-test.internal.js
+11
-14
@@ -12,8 +12,7 @@
12
let React;
13
let ReactFeatureFlags;
14
let ReactDOM;
15
-let DragResponder;
16
-let useDragListener;
15
+let useDragResponder;
16
17
describe('Drag event responder', () => {
18
let container;
@@ -24,8 +23,7 @@ describe('Drag event responder', () => {
23
ReactFeatureFlags.enableFlareAPI = true;
24
React = require('react');
25
ReactDOM = require('react-dom');
27
- DragResponder = require('react-events/drag').DragResponder;
28
- useDragListener = require('react-events/drag').useDragListener;
26
+ useDragResponder = require('react-events/drag').useDragResponder;
27
28
container = document.createElement('div');
29
document.body.appendChild(container);
@@ -46,11 +44,11 @@ describe('Drag event responder', () => {
44
}
45
46
function Component() {
49
- useDragListener({
47
+ const listener = useDragResponder({
48
onDragChange: handleOnDrag,
49
});
50
return (
53
- <div ref={divRef} responders={<DragResponder />}>
51
+ <div ref={divRef} listeners={listener}>
52
Drag me!
53
</div>
54
);
@@ -102,12 +100,12 @@ describe('Drag event responder', () => {
100
}
101
102
function Component() {
105
- useDragListener({
103
+ const listener = useDragResponder({
104
onDragStart: handleDragStart,
105
onDragEnd: handleDragEnd,
106
});
107
return (
110
- <div ref={divRef} responders={<DragResponder />}>
108
+ <div ref={divRef} listeners={listener}>
109
Drag me!
110
</div>
111
);
@@ -156,14 +154,13 @@ describe('Drag event responder', () => {
154
}
155
156
function Component() {
159
- useDragListener({
157
+ const listener = useDragResponder({
158
onDragStart: handleDragStart,
159
onDragEnd: handleDragEnd,
160
+ shouldClaimOwnership: () => true,
161
});
162
return (
164
- <div
165
- ref={divRef}
166
- responders={<DragResponder shouldClaimOwnership={() => true} />}>
163
+ <div ref={divRef} listeners={listener}>
164
Drag me!
165
</div>
166
);
@@ -211,11 +208,11 @@ describe('Drag event responder', () => {
208
}
209
210
function Component() {
214
- useDragListener({
211
+ const listener = useDragResponder({
212
onDragMove: handleDragMove,
213
});
214
return (
218
- <div ref={divRef} responders={<DragResponder />}>
215
+ <div ref={divRef} listeners={listener}>
216
Drag me!
217
</div>
218
);
packages/react-events/src/dom/__tests__/Focus-test.internal.js
+28
-32
@@ -14,8 +14,8 @@ let ReactFeatureFlags;
14
let ReactDOM;
15
let FocusResponder;
16
let FocusWithinResponder;
17
-let useFocusListener;
18
-let useFocusWithinListener;
17
+let useFocusResponder;
18
+let useFocusWithinResponder;
19
20
const createEvent = (type, data) => {
21
const event = document.createEvent('CustomEvent');
@@ -43,8 +43,9 @@ const modulesInit = () => {
43
ReactDOM = require('react-dom');
44
FocusResponder = require('react-events/focus').FocusResponder;
45
FocusWithinResponder = require('react-events/focus').FocusWithinResponder;
46
- useFocusListener = require('react-events/focus').useFocusListener;
47
- useFocusWithinListener = require('react-events/focus').useFocusWithinListener;
46
+ useFocusResponder = require('react-events/focus').useFocusResponder;
47
+ useFocusWithinResponder = require('react-events/focus')
48
+ .useFocusWithinResponder;
49
};
50
51
describe('Focus event responder', () => {
@@ -72,13 +73,12 @@ describe('Focus event responder', () => {
73
onFocus = jest.fn();
74
ref = React.createRef();
75
const Component = () => {
75
- useFocusListener({
76
+ const listener = useFocusResponder({
77
+ disabled: true,
78
onBlur,
79
onFocus,
80
});
79
- return (
80
- <div ref={ref} responders={<FocusResponder disabled={true} />} />
81
- );
81
+ return <div ref={ref} listeners={listener} />;
82
};
83
ReactDOM.render(<Component />, container);
84
});
@@ -98,10 +98,10 @@ describe('Focus event responder', () => {
98
onBlur = jest.fn();
99
ref = React.createRef();
100
const Component = () => {
101
- useFocusListener({
101
+ const listener = useFocusResponder({
102
onBlur,
103
});
104
- return <div ref={ref} responders={<FocusResponder />} />;
104
+ return <div ref={ref} listeners={listener} />;
105
};
106
ReactDOM.render(<Component />, container);
107
});
@@ -121,11 +121,11 @@ describe('Focus event responder', () => {
121
ref = React.createRef();
122
innerRef = React.createRef();
123
const Component = () => {
124
- useFocusListener({
124
+ const listener = useFocusResponder({
125
onFocus,
126
});
127
return (
128
- <div ref={ref} responders={<FocusResponder />}>
128
+ <div ref={ref} listeners={listener}>
129
<a ref={innerRef} />
130
</div>
131
);
@@ -252,11 +252,11 @@ describe('Focus event responder', () => {
252
ref = React.createRef();
253
innerRef = React.createRef();
254
const Component = () => {
255
- useFocusListener({
255
+ const listener = useFocusResponder({
256
onFocusChange,
257
});
258
return (
259
- <div ref={ref} responders={<FocusResponder />}>
259
+ <div ref={ref} listeners={listener}>
260
<div ref={innerRef} />
261
</div>
262
);
@@ -289,11 +289,11 @@ describe('Focus event responder', () => {
289
ref = React.createRef();
290
innerRef = React.createRef();
291
const Component = () => {
292
- useFocusListener({
292
+ const listener = useFocusResponder({
293
onFocusVisibleChange,
294
});
295
return (
296
- <div ref={ref} responders={<FocusResponder />}>
296
+ <div ref={ref} listeners={listener}>
297
<div ref={innerRef} />
298
</div>
299
);
@@ -353,7 +353,7 @@ describe('Focus event responder', () => {
353
});
354
355
describe('nested Focus components', () => {
356
- it('do not propagate events by default', () => {
356
+ it('propagates events in the correct order', () => {
357
const events = [];
358
const innerRef = React.createRef();
359
const outerRef = React.createRef();
@@ -362,22 +362,22 @@ describe('Focus event responder', () => {
362
};
363
364
const Inner = () => {
365
- useFocusListener({
365
+ const listener = useFocusResponder({
366
onBlur: createEventHandler('inner: onBlur'),
367
onFocus: createEventHandler('inner: onFocus'),
368
onFocusChange: createEventHandler('inner: onFocusChange'),
369
});
370
- return <div ref={innerRef} responders={<FocusResponder />} />;
370
+ return <div ref={innerRef} listeners={listener} />;
371
};
372
373
const Outer = () => {
374
- useFocusListener({
374
+ const listener = useFocusResponder({
375
onBlur: createEventHandler('outer: onBlur'),
376
onFocus: createEventHandler('outer: onFocus'),
377
onFocusChange: createEventHandler('outer: onFocusChange'),
378
});
379
return (
380
- <div ref={outerRef} responders={<FocusResponder />}>
380
+ <div ref={outerRef} listeners={listener}>
381
<Inner />
382
</div>
383
);
@@ -432,16 +432,12 @@ describe('FocusWithin event responder', () => {
432
onFocusWithinVisibleChange = jest.fn();
433
ref = React.createRef();
434
const Component = () => {
435
- useFocusWithinListener({
435
+ const listener = useFocusWithinResponder({
436
+ disabled: true,
437
onFocusWithinChange,
438
onFocusWithinVisibleChange,
439
});
439
- return (
440
- <div
441
- ref={ref}
442
- responders={<FocusWithinResponder disabled={true} />}
443
- />
444
- );
440
+ return <div ref={ref} listeners={listener} />;
441
};
442
ReactDOM.render(<Component />, container);
443
});
@@ -463,11 +459,11 @@ describe('FocusWithin event responder', () => {
459
innerRef = React.createRef();
460
innerRef2 = React.createRef();
461
const Component = () => {
466
- useFocusWithinListener({
462
+ const listener = useFocusWithinResponder({
463
onFocusWithinChange,
464
});
465
return (
470
- <div ref={ref} responders={<FocusWithinResponder />}>
466
+ <div ref={ref} listeners={listener}>
467
<div ref={innerRef} />
468
<div ref={innerRef2} />
469
</div>
@@ -534,11 +530,11 @@ describe('FocusWithin event responder', () => {
530
innerRef = React.createRef();
531
innerRef2 = React.createRef();
532
const Component = () => {
537
- useFocusWithinListener({
533
+ const listener = useFocusWithinResponder({
534
onFocusWithinVisibleChange,
535
});
536
return (
541
- <div ref={ref} responders={<FocusWithinResponder />}>
537
+ <div ref={ref} listeners={listener}>
538
<div ref={innerRef} />
539
<div ref={innerRef2} />
540
</div>
packages/react-events/src/dom/__tests__/Hover-test.internal.js
+22
-23
@@ -15,7 +15,7 @@ let ReactDOM;
15
let TestUtils;
16
let Scheduler;
17
let HoverResponder;
18
-let useHoverListener;
18
+let useHoverResponder;
19
20
const createEvent = (type, data) => {
21
const event = document.createEvent('CustomEvent');
@@ -52,7 +52,7 @@ describe('Hover event responder', () => {
52
TestUtils = require('react-dom/test-utils');
53
Scheduler = require('scheduler');
54
HoverResponder = require('react-events/hover').HoverResponder;
55
- useHoverListener = require('react-events/hover').useHoverListener;
55
+ useHoverResponder = require('react-events/hover').useHoverResponder;
56
container = document.createElement('div');
57
document.body.appendChild(container);
58
});
@@ -71,13 +71,12 @@ describe('Hover event responder', () => {
71
onHoverEnd = jest.fn();
72
ref = React.createRef();
73
const Component = () => {
74
- useHoverListener({
74
+ const listener = useHoverResponder({
75
+ disabled: true,
76
onHoverStart: onHoverStart,
77
onHoverEnd: onHoverEnd,
78
});
78
- return (
79
- <div ref={ref} responders={<HoverResponder disabled={true} />} />
80
- );
79
+ return <div ref={ref} listeners={listener} />;
80
};
81
ReactDOM.render(<Component />, container);
82
});
@@ -97,10 +96,10 @@ describe('Hover event responder', () => {
96
onHoverStart = jest.fn();
97
ref = React.createRef();
98
const Component = () => {
100
- useHoverListener({
99
+ const listener = useHoverResponder({
100
onHoverStart: onHoverStart,
101
});
103
- return <div ref={ref} responders={<HoverResponder />} />;
102
+ return <div ref={ref} listeners={listener} />;
103
};
104
ReactDOM.render(<Component />, container);
105
});
@@ -176,10 +175,10 @@ describe('Hover event responder', () => {
175
onHoverChange = jest.fn();
176
ref = React.createRef();
177
const Component = () => {
179
- useHoverListener({
178
+ const listener = useHoverResponder({
179
onHoverChange,
180
});
182
- return <div ref={ref} responders={<HoverResponder />} />;
181
+ return <div ref={ref} listeners={listener} />;
182
};
183
ReactDOM.render(<Component />, container);
184
});
@@ -214,11 +213,11 @@ describe('Hover event responder', () => {
213
const target = React.createRef(null);
214
function Foo() {
215
const [isHover, setHover] = useState(false);
217
- useHoverListener({
216
+ const listener = useHoverResponder({
217
onHoverChange: setHover,
218
});
219
return (
221
- <div ref={target} responders={<HoverResponder />}>
220
+ <div ref={target} listeners={listener}>
221
{isHover ? 'hovered' : 'not hovered'}
222
</div>
223
);
@@ -246,10 +245,10 @@ describe('Hover event responder', () => {
245
onHoverEnd = jest.fn();
246
ref = React.createRef();
247
const Component = () => {
249
- useHoverListener({
248
+ const listener = useHoverResponder({
249
onHoverEnd,
250
});
252
- return <div ref={ref} responders={<HoverResponder />} />;
251
+ return <div ref={ref} listeners={listener} />;
252
};
253
ReactDOM.render(<Component />, container);
254
});
@@ -315,10 +314,10 @@ describe('Hover event responder', () => {
314
const onHoverMove = jest.fn();
315
const ref = React.createRef();
316
const Component = () => {
318
- useHoverListener({
317
+ const listener = useHoverResponder({
318
onHoverMove,
319
});
321
- return <div ref={ref} responders={<HoverResponder />} />;
320
+ return <div ref={ref} listeners={listener} />;
321
};
322
ReactDOM.render(<Component />, container);
323
@@ -342,7 +341,7 @@ describe('Hover event responder', () => {
341
});
342
343
describe('nested Hover components', () => {
345
- it('do not propagate events by default', () => {
344
+ it('not propagate by default', () => {
345
const events = [];
346
const innerRef = React.createRef();
347
const outerRef = React.createRef();
@@ -351,22 +350,22 @@ describe('Hover event responder', () => {
350
};
351
352
const Inner = () => {
354
- useHoverListener({
353
+ const listener = useHoverResponder({
354
onHoverStart: createEventHandler('inner: onHoverStart'),
355
onHoverEnd: createEventHandler('inner: onHoverEnd'),
356
onHoverChange: createEventHandler('inner: onHoverChange'),
357
});
359
- return <div ref={innerRef} responders={<HoverResponder />} />;
358
+ return <div ref={innerRef} listeners={listener} />;
359
};
360
361
const Outer = () => {
363
- useHoverListener({
362
+ const listener = useHoverResponder({
363
onHoverStart: createEventHandler('outer: onHoverStart'),
364
onHoverEnd: createEventHandler('outer: onHoverEnd'),
365
onHoverChange: createEventHandler('outer: onHoverChange'),
366
});
367
return (
369
- <div ref={outerRef} responders={<HoverResponder />}>
368
+ <div ref={outerRef} listeners={listener}>
369
<Inner />
370
</div>
371
);
@@ -427,12 +426,12 @@ describe('Hover event responder', () => {
426
eventLog.push(propertiesWeCareAbout);
427
};
428
const Component = () => {
430
- useHoverListener({
429
+ const listener = useHoverResponder({
430
onHoverStart: logEvent,
431
onHoverEnd: logEvent,
432
onHoverMove: logEvent,
433
});
435
- return <div ref={ref} responders={<HoverResponder />} />;
434
+ return <div ref={ref} listeners={listener} />;
435
};
436
ReactDOM.render(<Component />, container);
437
packages/react-events/src/dom/__tests__/Input-test.internal.js
+53
-70
@@ -13,9 +13,8 @@ let React;
13
let ReactFeatureFlags;
14
let ReactDOM;
15
let InputResponder;
16
-let useInputListener;
17
-let PressResponder;
18
-let usePressListener;
16
+let useInputResponder;
17
+let usePressResponder;
18
let Scheduler;
19
20
const setUntrackedChecked = Object.getOwnPropertyDescriptor(
@@ -42,9 +41,8 @@ const modulesInit = () => {
41
ReactDOM = require('react-dom');
42
Scheduler = require('scheduler');
43
InputResponder = require('react-events/input').InputResponder;
45
- useInputListener = require('react-events/input').useInputListener;
46
- PressResponder = require('react-events/press').PressResponder;
47
- usePressListener = require('react-events/press').usePressListener;
44
+ useInputResponder = require('react-events/input').useInputResponder;
45
+ usePressResponder = require('react-events/press').usePressResponder;
46
};
47
48
describe('Input event responder', () => {
@@ -72,13 +70,12 @@ describe('Input event responder', () => {
70
ref = React.createRef();
71
72
function Component() {
75
- useInputListener({
73
+ const listener = useInputResponder({
74
+ disabled: true,
75
onChange,
76
onValueChange,
77
});
79
- return (
80
- <input ref={ref} responders={<InputResponder disabled={true} />} />
81
- );
78
+ return <input ref={ref} listeners={listener} />;
79
}
80
ReactDOM.render(<Component />, container);
81
});
@@ -120,7 +117,7 @@ describe('Input event responder', () => {
117
}
118
119
function Component() {
123
- useInputListener({
120
+ const listener = useInputResponder({
121
onChange,
122
onValueChange,
123
});
@@ -129,7 +126,7 @@ describe('Input event responder', () => {
126
type="text"
127
ref={ref}
128
defaultValue="foo"
132
- responders={<InputResponder />}
129
+ listeners={listener}
130
/>
131
);
132
}
@@ -160,7 +157,7 @@ describe('Input event responder', () => {
157
}
158
159
function Component() {
163
- useInputListener({
160
+ const listener = useInputResponder({
161
onChange,
162
onValueChange,
163
});
@@ -169,7 +166,7 @@ describe('Input event responder', () => {
166
type="checkbox"
167
ref={ref}
168
defaultChecked={true}
172
- responders={<InputResponder />}
169
+ listeners={listener}
170
/>
171
);
172
}
@@ -203,7 +200,7 @@ describe('Input event responder', () => {
200
}
201
202
function Component() {
206
- useInputListener({
203
+ const listener = useInputResponder({
204
onChange,
205
onValueChange,
206
});
@@ -212,7 +209,7 @@ describe('Input event responder', () => {
209
type="checkbox"
210
ref={ref}
211
defaultChecked={false}
215
- responders={<InputResponder />}
212
+ listeners={listener}
213
/>
214
);
215
}
@@ -245,13 +242,11 @@ describe('Input event responder', () => {
242
}
243
244
function Component() {
248
- useInputListener({
245
+ const listener = useInputResponder({
246
onChange,
247
onValueChange,
248
});
252
- return (
253
- <input type="checkbox" ref={ref} responders={<InputResponder />} />
254
- );
249
+ return <input type="checkbox" ref={ref} listeners={listener} />;
250
}
251
ReactDOM.render(<Component />, container);
252
@@ -288,7 +283,7 @@ describe('Input event responder', () => {
283
}
284
285
function Component() {
291
- useInputListener({
286
+ const listener = useInputResponder({
287
onChange,
288
onValueChange,
289
});
@@ -297,7 +292,7 @@ describe('Input event responder', () => {
292
type="text"
293
defaultValue="foo"
294
ref={ref}
300
- responders={<InputResponder />}
295
+ listeners={listener}
296
/>
297
);
298
}
@@ -350,17 +345,12 @@ describe('Input event responder', () => {
345
}
346
347
function Component() {
353
- useInputListener({
348
+ const listener = useInputResponder({
349
onChange,
350
onValueChange,
351
});
352
return (
358
- <input
359
- type="text"
360
- defaultValue="42"
361
- ref={ref}
362
- responders={<InputResponder />}
363
- />
353
+ <input type="text" defaultValue="42" ref={ref} listeners={listener} />
354
);
355
}
356
ReactDOM.render(<Component />, container);
@@ -395,7 +385,7 @@ describe('Input event responder', () => {
385
}
386
387
function Component() {
398
- useInputListener({
388
+ const listener = useInputResponder({
389
onChange,
390
onValueChange,
391
});
@@ -404,7 +394,7 @@ describe('Input event responder', () => {
394
type="checkbox"
395
defaultChecked={false}
396
ref={ref}
407
- responders={<InputResponder />}
397
+ listeners={listener}
398
/>
399
);
400
}
@@ -448,11 +438,11 @@ describe('Input event responder', () => {
438
}
439
440
function Component() {
451
- useInputListener({
441
+ const listener = useInputResponder({
442
onChange,
443
onValueChange,
444
});
455
- return <input type="radio" ref={ref} responders={<InputResponder />} />;
445
+ return <input type="radio" ref={ref} listeners={listener} />;
446
}
447
ReactDOM.render(<Component />, container);
448
@@ -493,23 +483,19 @@ describe('Input event responder', () => {
483
}
484
485
function Radio1() {
496
- useInputListener({
486
+ const listener = useInputResponder({
487
onChange: onChange1,
488
onValueChange: onValueChange1,
489
});
500
- return (
501
- <input type="radio" name="group" responders={<InputResponder />} />
502
- );
490
+ return <input type="radio" name="group" listeners={listener} />;
491
}
492
493
function Radio2() {
506
- useInputListener({
494
+ const listener = useInputResponder({
495
onChange: onChange2,
496
onValueChange: onValueChange2,
497
});
510
- return (
511
- <input type="radio" name="group" responders={<InputResponder />} />
512
- );
498
+ return <input type="radio" name="group" listeners={listener} />;
499
}
500
501
function Component() {
@@ -572,17 +558,12 @@ describe('Input event responder', () => {
558
onChangeCalled = 0;
559
onValueChangeCalled = 0;
560
function Component() {
575
- useInputListener({
561
+ const listener = useInputResponder({
562
onChange,
563
onValueChange,
564
});
565
return (
580
- <input
581
- type={type}
582
- name="group"
583
- ref={ref}
584
- responders={<InputResponder />}
585
- />
566
+ <input type={type} name="group" ref={ref} listeners={listener} />
567
);
568
}
569
ReactDOM.render(<Component />, container);
@@ -605,13 +586,11 @@ describe('Input event responder', () => {
586
onChangeCalled = 0;
587
onValueChangeCalled = 0;
588
function Component2() {
608
- useInputListener({
589
+ const listener = useInputResponder({
590
onChange,
591
onValueChange,
592
});
612
- return (
613
- <input type={type} ref={ref} responders={<InputResponder />} />
614
- );
593
+ return <input type={type} ref={ref} listeners={listener} />;
594
}
595
ReactDOM.render(<Component2 />, container);
596
// Should be ignored (no change):
@@ -633,13 +612,11 @@ describe('Input event responder', () => {
612
onChangeCalled = 0;
613
onValueChangeCalled = 0;
614
function Component3() {
636
- useInputListener({
615
+ const listener = useInputResponder({
616
onChange,
617
onValueChange,
618
});
640
- return (
641
- <input type={type} ref={ref} responders={<InputResponder />} />
642
- );
619
+ return <input type={type} ref={ref} listeners={listener} />;
620
}
621
ReactDOM.render(<Component3 />, container);
622
// Should be ignored (no change):
@@ -675,11 +652,11 @@ describe('Input event responder', () => {
652
}
653
654
function Component() {
678
- useInputListener({
655
+ const listener = useInputResponder({
656
onChange,
657
onValueChange,
658
});
682
- return <input type="range" ref={ref} responders={<InputResponder />} />;
659
+ return <input type="range" ref={ref} listeners={listener} />;
660
}
661
ReactDOM.render(<Component />, container);
662
@@ -712,11 +689,11 @@ describe('Input event responder', () => {
689
}
690
691
function Component() {
715
- useInputListener({
692
+ const listener = useInputResponder({
693
onChange,
694
onValueChange,
695
});
719
- return <input type="range" ref={ref} responders={<InputResponder />} />;
696
+ return <input type="range" ref={ref} listeners={listener} />;
697
}
698
ReactDOM.render(<Component />, container);
699
@@ -784,7 +761,7 @@ describe('Input event responder', () => {
761
let ops = [];
762
763
function Component({innerRef, onChange, controlledValue}) {
787
- useInputListener({
764
+ const listener = useInputResponder({
765
onChange,
766
});
767
return (
@@ -792,7 +769,7 @@ describe('Input event responder', () => {
769
type="text"
770
ref={innerRef}
771
value={controlledValue}
795
- responders={<InputResponder />}
772
+ listeners={listener}
773
/>
774
);
775
}
@@ -844,7 +821,7 @@ describe('Input event responder', () => {
821
let ops = [];
822
823
function Component({innerRef, onChange, controlledValue}) {
847
- useInputListener({
824
+ const listener = useInputResponder({
825
onChange,
826
});
827
return (
@@ -852,7 +829,7 @@ describe('Input event responder', () => {
829
type="checkbox"
830
ref={innerRef}
831
checked={controlledValue}
855
- responders={<InputResponder />}
832
+ listeners={listener}
833
/>
834
);
835
}
@@ -919,7 +896,7 @@ describe('Input event responder', () => {
896
let ops = [];
897
898
function Component({innerRef, onChange, controlledValue}) {
922
- useInputListener({
899
+ const listener = useInputResponder({
900
onChange,
901
});
902
return (
@@ -927,7 +904,7 @@ describe('Input event responder', () => {
904
type="text"
905
ref={innerRef}
906
value={controlledValue}
930
- responders={<InputResponder />}
907
+ listeners={listener}
908
/>
909
);
910
}
@@ -978,8 +955,13 @@ describe('Input event responder', () => {
955
956
let ops = [];
957
981
- function Component({innerRef, onChange, controlledValue}) {
982
- useInputListener({
958
+ function Component({
959
+ innerRef,
960
+ onChange,
961
+ controlledValue,
962
+ pressListener,
963
+ }) {
964
+ const inputListener = useInputResponder({
965
onChange,
966
});
967
return (
@@ -987,13 +969,13 @@ describe('Input event responder', () => {
969
type="text"
970
ref={innerRef}
971
value={controlledValue}
990
- responders={[<InputResponder />, <PressResponder />]}
972
+ listeners={[inputListener, pressListener]}
973
/>
974
);
975
}
976
977
function PressWrapper({innerRef, onPress, onChange, controlledValue}) {
996
- usePressListener({
978
+ const pressListener = usePressResponder({
979
onPress,
980
});
981
return (
@@ -1001,6 +983,7 @@ describe('Input event responder', () => {
983
onChange={onChange}
984
innerRef={el => (input = el)}
985
controlledValue={controlledValue}
986
+ pressListener={pressListener}
987
/>
988
);
989
}
packages/react-events/src/dom/__tests__/Keyboard-test.internal.js
+10
-12
@@ -12,8 +12,7 @@
12
let React;
13
let ReactFeatureFlags;
14
let ReactDOM;
15
-let KeyboardResponder;
16
-let useKeyboardListener;
15
+let useKeyboardResponder;
16
17
const createEvent = (type, data) => {
18
const event = document.createEvent('CustomEvent');
@@ -35,8 +34,8 @@ describe('Keyboard event responder', () => {
34
ReactFeatureFlags.enableFlareAPI = true;
35
React = require('react');
36
ReactDOM = require('react-dom');
38
- KeyboardResponder = require('react-events/keyboard').KeyboardResponder;
39
- useKeyboardListener = require('react-events/keyboard').useKeyboardListener;
37
+ useKeyboardResponder = require('react-events/keyboard')
38
+ .useKeyboardResponder;
39
40
container = document.createElement('div');
41
document.body.appendChild(container);
@@ -56,13 +55,12 @@ describe('Keyboard event responder', () => {
55
onKeyUp = jest.fn();
56
ref = React.createRef();
57
const Component = () => {
59
- useKeyboardListener({
58
+ const listener = useKeyboardResponder({
59
+ disabled: true,
60
onKeyDown,
61
onKeyUp,
62
});
63
- return (
64
- <div ref={ref} responders={<KeyboardResponder disabled={true} />} />
65
- );
63
+ return <div ref={ref} listeners={listener} />;
64
};
65
ReactDOM.render(<Component />, container);
66
});
@@ -81,10 +79,10 @@ describe('Keyboard event responder', () => {
79
onKeyDown = jest.fn();
80
ref = React.createRef();
81
const Component = () => {
84
- useKeyboardListener({
82
+ const listener = useKeyboardResponder({
83
onKeyDown,
84
});
87
- return <div ref={ref} responders={<KeyboardResponder />} />;
85
+ return <div ref={ref} listeners={listener} />;
86
};
87
ReactDOM.render(<Component />, container);
88
});
@@ -112,11 +110,11 @@ describe('Keyboard event responder', () => {
110
onKeyUp = jest.fn();
111
ref = React.createRef();
112
const Component = () => {
115
- useKeyboardListener({
113
+ const listener = useKeyboardResponder({
114
onKeyDown,
115
onKeyUp,
116
});
119
- return <div ref={ref} responders={<KeyboardResponder />} />;
117
+ return <div ref={ref} listeners={listener} />;
118
};
119
ReactDOM.render(<Component />, container);
120
});
packages/react-events/src/dom/__tests__/Press-test.internal.js
+125
-149
@@ -13,7 +13,7 @@ let React;
13
let ReactFeatureFlags;
14
let ReactDOM;
15
let PressResponder;
16
-let usePressListener;
16
+let usePressResponder;
17
let Scheduler;
18
19
const createEvent = (type, data) => {
@@ -54,7 +54,7 @@ function init() {
54
React = require('react');
55
ReactDOM = require('react-dom');
56
PressResponder = require('react-events/press').PressResponder;
57
- usePressListener = require('react-events/press').usePressListener;
57
+ usePressResponder = require('react-events/press').usePressResponder;
58
Scheduler = require('scheduler');
59
}
60
@@ -83,14 +83,13 @@ describe('Event responder: Press', () => {
83
onPressEnd = jest.fn();
84
ref = React.createRef();
85
const Component = () => {
86
- usePressListener({
86
+ const listener = usePressResponder({
87
+ disabled: true,
88
onPressStart,
89
onPress,
90
onPressEnd,
91
});
91
- return (
92
- <div ref={ref} responders={<PressResponder disabled={true} />} />
93
- );
92
+ return <div ref={ref} listeners={listener} />;
93
};
94
ReactDOM.render(<Component />, container);
95
});
@@ -111,10 +110,10 @@ describe('Event responder: Press', () => {
110
onPressStart = jest.fn();
111
ref = React.createRef();
112
const Component = () => {
114
- usePressListener({
113
+ const listener = usePressResponder({
114
onPressStart,
115
});
117
- return <div ref={ref} responders={<PressResponder />} />;
116
+ return <div ref={ref} listeners={listener} />;
117
};
118
ReactDOM.render(<Component />, container);
119
});
@@ -269,10 +268,10 @@ describe('Event responder: Press', () => {
268
onPressEnd = jest.fn();
269
ref = React.createRef();
270
const Component = () => {
272
- usePressListener({
271
+ const listener = usePressResponder({
272
onPressEnd,
273
});
275
- return <div ref={ref} responders={<PressResponder />} />;
274
+ return <div ref={ref} listeners={listener} />;
275
};
276
ReactDOM.render(<Component />, container);
277
});
@@ -433,10 +432,10 @@ describe('Event responder: Press', () => {
432
onPressChange = jest.fn();
433
ref = React.createRef();
434
const Component = () => {
436
- usePressListener({
435
+ const listener = usePressResponder({
436
onPressChange,
437
});
439
- return <div ref={ref} responders={<PressResponder />} />;
438
+ return <div ref={ref} listeners={listener} />;
439
};
440
ReactDOM.render(<Component />, container);
441
});
@@ -467,10 +466,10 @@ describe('Event responder: Press', () => {
466
onPress = jest.fn();
467
ref = React.createRef();
468
const Component = () => {
470
- usePressListener({
469
+ const listener = usePressResponder({
470
onPress,
471
});
473
- return <div ref={ref} responders={<PressResponder />} />;
472
+ return <div ref={ref} listeners={listener} />;
473
};
474
ReactDOM.render(<Component />, container);
475
ref.current.getBoundingClientRect = () => ({
@@ -514,10 +513,10 @@ describe('Event responder: Press', () => {
513
514
it('is not called after auxillary-button press', () => {
515
const Component = () => {
517
- usePressListener({
516
+ const listener = usePressResponder({
517
onPress,
518
});
520
- return <div ref={ref} responders={<PressResponder />} />;
519
+ return <div ref={ref} listeners={listener} />;
520
};
521
ReactDOM.render(<Component />, container);
522
@@ -540,10 +539,10 @@ describe('Event responder: Press', () => {
539
it('is not called after invalid "keyup" event', () => {
540
const inputRef = React.createRef();
541
const Component = () => {
543
- usePressListener({
542
+ const listener = usePressResponder({
543
onPress,
544
});
546
- return <input ref={inputRef} responders={<PressResponder />} />;
545
+ return <input ref={inputRef} listeners={listener} />;
546
};
547
ReactDOM.render(<Component />, container);
548
inputRef.current.dispatchEvent(
@@ -580,11 +579,11 @@ describe('Event responder: Press', () => {
579
const divRef = React.createRef();
580
581
const Component = () => {
583
- usePressListener({
582
+ const listener = usePressResponder({
583
onPress,
584
});
585
return (
587
- <div ref={divRef} responders={<PressResponder />}>
586
+ <div ref={divRef} listeners={listener}>
587
<button ref={buttonRef} />
588
</div>
589
);
@@ -620,10 +619,10 @@ describe('Event responder: Press', () => {
619
const onPressMove = jest.fn();
620
const ref = React.createRef();
621
const Component = () => {
623
- usePressListener({
622
+ const listener = usePressResponder({
623
onPressMove,
624
});
626
- return <div ref={ref} responders={<PressResponder />} />;
625
+ return <div ref={ref} listeners={listener} />;
626
};
627
ReactDOM.render(<Component />, container);
628
@@ -653,10 +652,10 @@ describe('Event responder: Press', () => {
652
const onPressMove = jest.fn();
653
const ref = React.createRef();
654
const Component = () => {
656
- usePressListener({
655
+ const listener = usePressResponder({
656
onPressMove,
657
});
659
- return <div ref={ref} responders={<PressResponder />} />;
658
+ return <div ref={ref} listeners={listener} />;
659
};
660
ReactDOM.render(<Component />, container);
661
@@ -681,10 +680,10 @@ describe('Event responder: Press', () => {
680
const onPressMove = jest.fn();
681
const ref = React.createRef();
682
const Component = () => {
684
- usePressListener({
683
+ const listener = usePressResponder({
684
onPressMove,
685
});
687
- return <div ref={ref} responders={<PressResponder />} />;
686
+ return <div ref={ref} listeners={listener} />;
687
};
688
ReactDOM.render(<Component />, container);
689
@@ -757,14 +756,14 @@ describe('Event responder: Press', () => {
756
};
757
758
const Component = () => {
760
- usePressListener({
759
+ const listener = usePressResponder({
760
onPress: createEventHandler('onPress'),
761
onPressChange: createEventHandler('onPressChange'),
762
onPressMove: createEventHandler('onPressMove'),
763
onPressStart: createEventHandler('onPressStart'),
764
onPressEnd: createEventHandler('onPressEnd'),
765
});
767
- return <div ref={ref} responders={<PressResponder />} />;
766
+ return <div ref={ref} listeners={listener} />;
767
};
768
ReactDOM.render(<Component />, container);
769
@@ -795,7 +794,7 @@ describe('Event responder: Press', () => {
794
};
795
796
const Component = () => {
798
- usePressListener({
797
+ const listener = usePressResponder({
798
onPress: createEventHandler('onPress'),
799
onPressChange: createEventHandler('onPressChange'),
800
onPressMove: createEventHandler('onPressMove'),
@@ -804,7 +803,7 @@ describe('Event responder: Press', () => {
803
});
804
return (
805
<div ref={outerRef}>
807
- <div ref={innerRef} responders={<PressResponder />} />
806
+ <div ref={innerRef} listeners={listener} />
807
</div>
808
);
809
};
@@ -845,21 +844,15 @@ describe('Event responder: Press', () => {
844
const pressRetentionOffset = {top: 40, bottom: 40, left: 40, right: 40};
845
846
const Component = () => {
848
- usePressListener({
847
+ const listener = usePressResponder({
848
onPress: createEventHandler('onPress'),
849
onPressChange: createEventHandler('onPressChange'),
850
onPressMove: createEventHandler('onPressMove'),
851
onPressStart: createEventHandler('onPressStart'),
852
onPressEnd: createEventHandler('onPressEnd'),
853
+ pressRetentionOffset,
854
});
855
- return (
856
- <div
857
- ref={ref}
858
- responders={
859
- <PressResponder pressRetentionOffset={pressRetentionOffset} />
860
- }
861
- />
862
- );
855
+ return <div ref={ref} listeners={listener} />;
856
};
857
ReactDOM.render(<Component />, container);
858
@@ -890,12 +883,12 @@ describe('Event responder: Press', () => {
883
};
884
885
const Component = () => {
893
- usePressListener({
886
+ const listener = usePressResponder({
887
onPress: createEventHandler('onPress'),
888
onPressStart: createEventHandler('onPressStart'),
889
onPressEnd: createEventHandler('onPressEnd'),
890
});
898
- return <div ref={ref} responders={<PressResponder />} />;
891
+ return <div ref={ref} listeners={listener} />;
892
};
893
ReactDOM.render(<Component />, container);
894
@@ -928,12 +921,12 @@ describe('Event responder: Press', () => {
921
};
922
923
const Component = () => {
931
- usePressListener({
924
+ const listener = usePressResponder({
925
onPress: createEventHandler('onPress'),
926
onPressStart: createEventHandler('onPressStart'),
927
onPressEnd: createEventHandler('onPressEnd'),
928
});
936
- return <div ref={ref} responders={<PressResponder />} />;
929
+ return <div ref={ref} listeners={listener} />;
930
};
931
ReactDOM.render(<Component />, container);
932
@@ -977,14 +970,14 @@ describe('Event responder: Press', () => {
970
};
971
972
const Component = () => {
980
- usePressListener({
973
+ const listener = usePressResponder({
974
onPress: createEventHandler('onPress'),
975
onPressChange: createEventHandler('onPressChange'),
976
onPressMove: createEventHandler('onPressMove'),
977
onPressStart: createEventHandler('onPressStart'),
978
onPressEnd: createEventHandler('onPressEnd'),
979
});
987
- return <div ref={ref} responders={<PressResponder />} />;
980
+ return <div ref={ref} listeners={listener} />;
981
};
982
ReactDOM.render(<Component />, container);
983
@@ -1015,14 +1008,14 @@ describe('Event responder: Press', () => {
1008
};
1009
1010
const Component = () => {
1018
- usePressListener({
1011
+ const listener = usePressResponder({
1012
onPress: createEventHandler('onPress'),
1013
onPressChange: createEventHandler('onPressChange'),
1014
onPressMove: createEventHandler('onPressMove'),
1015
onPressStart: createEventHandler('onPressStart'),
1016
onPressEnd: createEventHandler('onPressEnd'),
1017
});
1025
- return <div ref={ref} responders={<PressResponder />} />;
1018
+ return <div ref={ref} listeners={listener} />;
1019
};
1020
ReactDOM.render(<Component />, container);
1021
@@ -1069,14 +1062,14 @@ describe('Event responder: Press', () => {
1062
};
1063
1064
const Component = () => {
1072
- usePressListener({
1065
+ const listener = usePressResponder({
1066
onPress: createEventHandler('onPress'),
1067
onPressChange: createEventHandler('onPressChange'),
1068
onPressMove: createEventHandler('onPressMove'),
1069
onPressStart: createEventHandler('onPressStart'),
1070
onPressEnd: createEventHandler('onPressEnd'),
1071
});
1079
- return <div ref={ref} responders={<PressResponder />} />;
1072
+ return <div ref={ref} listeners={listener} />;
1073
};
1074
ReactDOM.render(<Component />, container);
1075
@@ -1134,14 +1127,14 @@ describe('Event responder: Press', () => {
1127
};
1128
1129
const Component = () => {
1137
- usePressListener({
1130
+ const listener = usePressResponder({
1131
onPress: createEventHandler('onPress'),
1132
onPressChange: createEventHandler('onPressChange'),
1133
onPressMove: createEventHandler('onPressMove'),
1134
onPressStart: createEventHandler('onPressStart'),
1135
onPressEnd: createEventHandler('onPressEnd'),
1136
});
1144
- return <div ref={ref} responders={<PressResponder />} />;
1137
+ return <div ref={ref} listeners={listener} />;
1138
};
1139
ReactDOM.render(<Component />, container);
1140
@@ -1257,14 +1250,14 @@ describe('Event responder: Press', () => {
1250
};
1251
1252
const Component = () => {
1260
- usePressListener({
1253
+ const listener = usePressResponder({
1254
onPress: createEventHandler('onPress'),
1255
onPressChange: createEventHandler('onPressChange'),
1256
onPressMove: createEventHandler('onPressMove'),
1257
onPressStart: createEventHandler('onPressStart'),
1258
onPressEnd: createEventHandler('onPressEnd'),
1259
});
1267
- return <div ref={ref} responders={<PressResponder />} />;
1260
+ return <div ref={ref} listeners={listener} />;
1261
};
1262
ReactDOM.render(<Component />, container);
1263
@@ -1308,21 +1301,15 @@ describe('Event responder: Press', () => {
1301
const pressRetentionOffset = {top: 40, bottom: 40, left: 40, right: 40};
1302
1303
const Component = () => {
1311
- usePressListener({
1304
+ const listener = usePressResponder({
1305
onPress: createEventHandler('onPress'),
1306
onPressChange: createEventHandler('onPressChange'),
1307
onPressMove: createEventHandler('onPressMove'),
1308
onPressStart: createEventHandler('onPressStart'),
1309
onPressEnd: createEventHandler('onPressEnd'),
1310
+ pressRetentionOffset,
1311
});
1318
- return (
1319
- <div
1320
- ref={ref}
1321
- responders={
1322
- <PressResponder pressRetentionOffset={pressRetentionOffset} />
1323
- }
1324
- />
1325
- );
1312
+ return <div ref={ref} listeners={listener} />;
1313
};
1314
ReactDOM.render(<Component />, container);
1315
@@ -1364,12 +1351,12 @@ describe('Event responder: Press', () => {
1351
};
1352
1353
const Component = () => {
1367
- usePressListener({
1354
+ const listener = usePressResponder({
1355
onPress: createEventHandler('onPress'),
1356
onPressStart: createEventHandler('onPressStart'),
1357
onPressEnd: createEventHandler('onPressEnd'),
1358
});
1372
- return <div ref={ref} responders={<PressResponder />} />;
1359
+ return <div ref={ref} listeners={listener} />;
1360
};
1361
ReactDOM.render(<Component />, container);
1362
@@ -1417,12 +1404,12 @@ describe('Event responder: Press', () => {
1404
};
1405
1406
const Component = () => {
1420
- usePressListener({
1407
+ const listener = usePressResponder({
1408
onPress: createEventHandler('onPress'),
1409
onPressStart: createEventHandler('onPressStart'),
1410
onPressEnd: createEventHandler('onPressEnd'),
1411
});
1425
- return <div ref={ref} responders={<PressResponder />} />;
1412
+ return <div ref={ref} listeners={listener} />;
1413
};
1414
ReactDOM.render(<Component />, container);
1415
@@ -1481,14 +1468,14 @@ describe('Event responder: Press', () => {
1468
};
1469
1470
const Component = () => {
1484
- usePressListener({
1471
+ const listener = usePressResponder({
1472
onPress: createEventHandler('onPress'),
1473
onPressChange: createEventHandler('onPressChange'),
1474
onPressMove: createEventHandler('onPressMove'),
1475
onPressStart: createEventHandler('onPressStart'),
1476
onPressEnd: createEventHandler('onPressEnd'),
1477
});
1491
- return <div ref={ref} responders={<PressResponder />} />;
1478
+ return <div ref={ref} listeners={listener} />;
1479
};
1480
ReactDOM.render(<Component />, container);
1481
@@ -1538,14 +1525,14 @@ describe('Event responder: Press', () => {
1525
};
1526
1527
const Component = () => {
1541
- usePressListener({
1528
+ const listener = usePressResponder({
1529
onPress: createEventHandler('onPress'),
1530
onPressChange: createEventHandler('onPressChange'),
1531
onPressMove: createEventHandler('onPressMove'),
1532
onPressStart: createEventHandler('onPressStart'),
1533
onPressEnd: createEventHandler('onPressEnd'),
1534
});
1548
- return <div ref={ref} responders={<PressResponder />} />;
1535
+ return <div ref={ref} listeners={listener} />;
1536
};
1537
ReactDOM.render(<Component />, container);
1538
@@ -1608,17 +1595,18 @@ describe('Event responder: Press', () => {
1595
};
1596
1597
const Inner = () => {
1611
- usePressListener({
1598
+ const listener = usePressResponder({
1599
onPress: createEventHandler('inner: onPress'),
1600
onPressChange: createEventHandler('inner: onPressChange'),
1601
onPressMove: createEventHandler('inner: onPressMove'),
1602
onPressStart: createEventHandler('inner: onPressStart'),
1603
onPressEnd: createEventHandler('inner: onPressEnd'),
1604
+ stopPropagation: false,
1605
});
1606
return (
1607
<div
1608
ref={ref}
1621
- responders={<PressResponder stopPropagation={false} />}
1609
+ listeners={listener}
1610
onPointerDown={createEventHandler('pointerdown')}
1611
onPointerUp={createEventHandler('pointerup')}
1612
onKeyDown={createEventHandler('keydown')}
@@ -1628,7 +1616,7 @@ describe('Event responder: Press', () => {
1616
};
1617
1618
const Outer = () => {
1631
- usePressListener({
1619
+ const listener = usePressResponder({
1620
onPress: createEventHandler('outer: onPress'),
1621
onPressChange: createEventHandler('outer: onPressChange'),
1622
onPressMove: createEventHandler('outer: onPressMove'),
@@ -1636,7 +1624,7 @@ describe('Event responder: Press', () => {
1624
onPressEnd: createEventHandler('outer: onPressEnd'),
1625
});
1626
return (
1639
- <div responders={<PressResponder />}>
1627
+ <div listeners={listener}>
1628
<Inner />
1629
</div>
1630
);
@@ -1665,24 +1653,24 @@ describe('Event responder: Press', () => {
1653
]);
1654
});
1655
1668
- describe('correctly get propagation stopped and do not bubble', () => {
1656
+ describe('correctly not propagate', () => {
1657
it('for onPress', () => {
1658
const ref = React.createRef();
1659
const fn = jest.fn();
1660
1661
const Inner = () => {
1674
- usePressListener({
1662
+ const listener = usePressResponder({
1663
onPress: fn,
1664
});
1677
- return <div ref={ref} responders={<PressResponder />} />;
1665
+ return <div ref={ref} listeners={listener} />;
1666
};
1667
1668
const Outer = () => {
1681
- usePressListener({
1669
+ const listener = usePressResponder({
1670
onPress: fn,
1671
});
1672
return (
1685
- <div responders={<PressResponder />}>
1673
+ <div listeners={listener}>
1674
<Inner />
1675
</div>
1676
);
@@ -1709,20 +1697,20 @@ describe('Event responder: Press', () => {
1697
const fn2 = jest.fn();
1698
1699
const Inner = () => {
1712
- usePressListener({
1700
+ const listener = usePressResponder({
1701
onPressStart: fn,
1702
onPressEnd: fn2,
1703
});
1716
- return <div ref={ref} responders={<PressResponder />} />;
1704
+ return <div ref={ref} listeners={listener} />;
1705
};
1706
1707
const Outer = () => {
1720
- usePressListener({
1708
+ const listener = usePressResponder({
1709
onPressStart: fn,
1710
onPressEnd: fn2,
1711
});
1712
return (
1725
- <div responders={<PressResponder />}>
1713
+ <div listeners={listener}>
1714
<Inner />
1715
</div>
1716
);
@@ -1742,18 +1730,18 @@ describe('Event responder: Press', () => {
1730
const fn = jest.fn();
1731
1732
const Inner = () => {
1745
- usePressListener({
1733
+ const listener = usePressResponder({
1734
onPressChange: fn,
1735
});
1748
- return <div ref={ref} responders={<PressResponder />} />;
1736
+ return <div ref={ref} listeners={listener} />;
1737
};
1738
1739
const Outer = () => {
1752
- usePressListener({
1740
+ const listener = usePressResponder({
1741
onPressChange: fn,
1742
});
1743
return (
1756
- <div responders={<PressResponder />}>
1744
+ <div listeners={listener}>
1745
<Inner />
1746
</div>
1747
);
@@ -1775,10 +1763,10 @@ describe('Event responder: Press', () => {
1763
const ref = React.createRef();
1764
1765
const Component = () => {
1778
- usePressListener({
1766
+ const listener = usePressResponder({
1767
onPress,
1768
});
1781
- return <a href="#" ref={ref} responders={<PressResponder />} />;
1769
+ return <a href="#" ref={ref} listeners={listener} />;
1770
};
1771
ReactDOM.render(<Component />, container);
1772
@@ -1802,10 +1790,10 @@ describe('Event responder: Press', () => {
1790
const ref = React.createRef();
1791
1792
const Component = () => {
1805
- usePressListener({
1793
+ const listener = usePressResponder({
1794
onPress,
1795
});
1808
- return <a href="#" ref={ref} responders={<PressResponder />} />;
1796
+ return <a href="#" ref={ref} listeners={listener} />;
1797
};
1798
ReactDOM.render(<Component />, container);
1799
@@ -1824,12 +1812,12 @@ describe('Event responder: Press', () => {
1812
const buttonRef = React.createRef();
1813
1814
const Component = () => {
1827
- usePressListener({
1815
+ const listener = usePressResponder({
1816
onPress,
1817
});
1818
return (
1819
<a href="#">
1832
- <button ref={buttonRef} responders={<PressResponder />} />
1820
+ <button ref={buttonRef} listeners={listener} />
1821
</a>
1822
);
1823
};
@@ -1852,11 +1840,11 @@ describe('Event responder: Press', () => {
1840
const ref = React.createRef();
1841
1842
const Component = () => {
1855
- usePressListener({
1843
+ const listener = usePressResponder({
1844
onPress,
1845
});
1846
return (
1859
- <a href="#" responders={<PressResponder />}>
1847
+ <a href="#" listeners={listener}>
1848
<div ref={ref} />
1849
</a>
1850
);
@@ -1883,10 +1871,10 @@ describe('Event responder: Press', () => {
1871
const ref = React.createRef();
1872
1873
const Component = () => {
1886
- usePressListener({
1874
+ const listener = usePressResponder({
1875
onPress,
1876
});
1889
- return <a href="#" ref={ref} responders={<PressResponder />} />;
1877
+ return <a href="#" ref={ref} listeners={listener} />;
1878
};
1879
ReactDOM.render(<Component />, container);
1880
@@ -1917,16 +1905,11 @@ describe('Event responder: Press', () => {
1905
const ref = React.createRef();
1906
1907
const Component = () => {
1920
- usePressListener({
1908
+ const listener = usePressResponder({
1909
onPress,
1910
+ preventDefault: false,
1911
});
1923
- return (
1924
- <a
1925
- href="#"
1926
- ref={ref}
1927
- responders={<PressResponder preventDefault={false} />}
1928
- />
1929
- );
1912
+ return <a href="#" ref={ref} listeners={listener} />;
1913
};
1914
ReactDOM.render(<Component />, container);
1915
@@ -1950,16 +1933,11 @@ describe('Event responder: Press', () => {
1933
const ref = React.createRef();
1934
1935
const Component = () => {
1953
- usePressListener({
1936
+ const listener = usePressResponder({
1937
onPress,
1938
+ preventDefault: false,
1939
});
1956
- return (
1957
- <a
1958
- href="#"
1959
- ref={ref}
1960
- responders={<PressResponder preventDefault={false} />}
1961
- />
1962
- );
1940
+ return <a href="#" ref={ref} listeners={listener} />;
1941
};
1942
ReactDOM.render(<Component />, container);
1943
@@ -1979,10 +1957,10 @@ describe('Event responder: Press', () => {
1957
const ref = React.createRef();
1958
1959
const Component = () => {
1982
- usePressListener({
1960
+ const listener = usePressResponder({
1961
onPressEnd,
1962
});
1985
- return <a href="#" ref={ref} responders={<PressResponder />} />;
1963
+ return <a href="#" ref={ref} listeners={listener} />;
1964
};
1965
ReactDOM.render(<Component />, container);
1966
@@ -2048,10 +2026,10 @@ describe('Event responder: Press', () => {
2026
const ref = React.createRef();
2027
2028
const Component = () => {
2051
- usePressListener({
2029
+ const listener = usePressResponder({
2030
onPressEnd,
2031
});
2054
- return <a href="#" ref={ref} responders={<PressResponder />} />;
2032
+ return <a href="#" ref={ref} listeners={listener} />;
2033
};
2034
ReactDOM.render(<Component />, container);
2035
@@ -2066,12 +2044,12 @@ describe('Event responder: Press', () => {
2044
const containerRef = React.createRef();
2045
2046
const Component = () => {
2069
- usePressListener({
2047
+ const listener = usePressResponder({
2048
onPressEnd,
2049
});
2050
return (
2051
<div ref={containerRef}>
2074
- <a ref={ref} responders={<PressResponder />} />
2052
+ <a ref={ref} listeners={listener} />
2053
</div>
2054
);
2055
};
@@ -2088,12 +2066,12 @@ describe('Event responder: Press', () => {
2066
const outsideRef = React.createRef();
2067
2068
const Component = () => {
2091
- usePressListener({
2069
+ const listener = usePressResponder({
2070
onPressEnd,
2071
});
2072
return (
2073
<div>
2096
- <a ref={ref} responders={<PressResponder />} />
2074
+ <a ref={ref} listeners={listener} />
2075
<span ref={outsideRef} />
2076
</div>
2077
);
@@ -2145,13 +2123,13 @@ describe('Event responder: Press', () => {
2123
};
2124
2125
const Component = () => {
2148
- usePressListener({
2126
+ const listener = usePressResponder({
2127
onPressStart: logEvent,
2128
onPressEnd: logEvent,
2129
onPressMove: logEvent,
2130
onPress: logEvent,
2131
});
2154
- return <button ref={ref} responders={<PressResponder />} />;
2132
+ return <button ref={ref} listeners={listener} />;
2133
};
2134
ReactDOM.render(<Component />, container);
2135
@@ -2294,7 +2272,7 @@ describe('Event responder: Press', () => {
2272
updateCounter(count => count + 1);
2273
}
2274
2297
- usePressListener({
2275
+ const listener = usePressResponder({
2276
onPress: handlePress,
2277
});
2278
@@ -2302,7 +2280,7 @@ describe('Event responder: Press', () => {
2280
<div>
2281
<button
2282
ref={ref}
2305
- responders={<PressResponder />}
2283
+ listeners={listener}
2284
onClick={() => {
2285
updateCounter(count => count + 1);
2286
}}>
@@ -2361,7 +2339,7 @@ describe('Event responder: Press', () => {
2339
updateCounter(count => count + 1);
2340
}
2341
2364
- usePressListener({
2342
+ const listener = usePressResponder({
2343
onPress: handlePress,
2344
});
2345
@@ -2369,7 +2347,7 @@ describe('Event responder: Press', () => {
2347
<div>
2348
<button
2349
ref={ref}
2372
- responders={<PressResponder />}
2350
+ listeners={listener}
2351
onClick={() => {
2352
// This should flush synchronously
2353
ReactDOM.unstable_flushDiscreteUpdates();
@@ -2442,14 +2420,14 @@ describe('Event responder: Press', () => {
2420
updatePressesCount(pressesCount + 1);
2421
}
2422
2445
- usePressListener({
2423
+ const listener = usePressResponder({
2424
onPress: handlePress,
2425
});
2426
2427
return (
2428
<div>
2429
<button
2452
- responders={<PressResponder />}
2430
+ listeners={listener}
2431
ref={button}
2432
onClick={() => updateClicksCount(clicksCount + 1)}>
2433
Presses: {pressesCount}, Clicks: {clicksCount}
@@ -2481,9 +2459,9 @@ describe('Event responder: Press', () => {
2459
const onContextMenu = jest.fn();
2460
const ref = React.createRef();
2461
const Component = () => {
2484
- usePressListener({onContextMenu});
2462
+ const listener = usePressResponder({onContextMenu});
2463
2486
- return <div ref={ref} responders={<PressResponder />} />;
2464
+ return <div ref={ref} listeners={listener} />;
2465
};
2466
ReactDOM.render(<Component />, container);
2467
@@ -2507,9 +2485,9 @@ describe('Event responder: Press', () => {
2485
const ref = React.createRef();
2486
2487
const Component = () => {
2510
- usePressListener({onContextMenu});
2488
+ const listener = usePressResponder({onContextMenu});
2489
2512
- return <div ref={ref} responders={<PressResponder />} />;
2490
+ return <div ref={ref} listeners={listener} />;
2491
};
2492
ReactDOM.render(<Component />, container);
2493
@@ -2538,9 +2516,9 @@ describe('Event responder: Press', () => {
2516
const ref = React.createRef();
2517
2518
const Component = () => {
2541
- usePressListener({onContextMenu});
2519
+ const listener = usePressResponder({onContextMenu});
2520
2543
- return <div ref={ref} responders={<PressResponder />} />;
2521
+ return <div ref={ref} listeners={listener} />;
2522
};
2523
ReactDOM.render(<Component />, container);
2524
@@ -2561,9 +2539,9 @@ describe('Event responder: Press', () => {
2539
const ref = React.createRef();
2540
2541
const Component = () => {
2564
- usePressListener({onContextMenu});
2542
+ const listener = usePressResponder({onContextMenu});
2543
2566
- return <div ref={ref} responders={<PressResponder />} />;
2544
+ return <div ref={ref} listeners={listener} />;
2545
};
2546
ReactDOM.render(<Component />, container);
2547
@@ -2579,14 +2557,12 @@ describe('Event responder: Press', () => {
2557
const ref = React.createRef();
2558
2559
const Component = () => {
2582
- usePressListener({onContextMenu});
2560
+ const listener = usePressResponder({
2561
+ onContextMenu,
2562
+ preventContextMenu: true,
2563
+ });
2564
2584
- return (
2585
- <div
2586
- ref={ref}
2587
- responders={<PressResponder preventContextMenu={true} />}
2588
- />
2589
- );
2565
+ return <div ref={ref} listeners={listener} />;
2566
};
2567
ReactDOM.render(<Component />, container);
2568
@@ -2606,9 +2582,9 @@ describe('Event responder: Press', () => {
2582
const pointerDownEvent = jest.fn();
2583
2584
const Component = () => {
2609
- return (
2610
- <div ref={ref} responders={<PressResponder stopPropagation={true} />} />
2611
- );
2585
+ const listener = usePressResponder({stopPropagation: true});
2586
+
2587
+ return <div ref={ref} listeners={listener} />;
2588
};
2589
2590
container.addEventListener('pointerdown', pointerDownEvent);
@@ -2625,11 +2601,11 @@ describe('Event responder: Press', () => {
2601
const ref = React.createRef();
2602
const onPress = jest.fn();
2603
const Component = () => {
2628
- usePressListener({onPress});
2604
+ const listener = usePressResponder({onPress});
2605
2606
return (
2607
<div>
2632
- <a href="#" ref={ref} responders={<PressResponder />} />
2608
+ <a href="#" ref={ref} listeners={listener} />
2609
</div>
2610
);
2611
};
packages/react-events/src/dom/__tests__/Scroll-test.internal.js
+11
-14
@@ -12,8 +12,7 @@
12
let React;
13
let ReactFeatureFlags;
14
let ReactDOM;
15
-let ScrollResponder;
16
-let useScrollListener;
15
+let useScrollResponder;
16
17
const createEvent = (type, data) => {
18
const event = document.createEvent('CustomEvent');
@@ -35,8 +34,7 @@ describe('Scroll event responder', () => {
34
ReactFeatureFlags.enableFlareAPI = true;
35
React = require('react');
36
ReactDOM = require('react-dom');
38
- ScrollResponder = require('react-events/scroll').ScrollResponder;
39
- useScrollListener = require('react-events/scroll').useScrollListener;
37
+ useScrollResponder = require('react-events/scroll').useScrollResponder;
38
39
container = document.createElement('div');
40
document.body.appendChild(container);
@@ -55,12 +53,11 @@ describe('Scroll event responder', () => {
53
onScroll = jest.fn();
54
ref = React.createRef();
55
const Component = () => {
58
- useScrollListener({
56
+ const listener = useScrollResponder({
57
+ disabled: true,
58
onScroll,
59
});
61
- return (
62
- <div ref={ref} responders={<ScrollResponder disabled={true} />} />
63
- );
60
+ return <div ref={ref} listeners={listener} />;
61
};
62
ReactDOM.render(<Component />, container);
63
});
@@ -78,10 +75,10 @@ describe('Scroll event responder', () => {
75
onScroll = jest.fn();
76
ref = React.createRef();
77
const Component = () => {
81
- useScrollListener({
78
+ const listener = useScrollResponder({
79
onScroll,
80
});
84
- return <div ref={ref} responders={<ScrollResponder />} />;
81
+ return <div ref={ref} listeners={listener} />;
82
};
83
ReactDOM.render(<Component />, container);
84
});
@@ -229,10 +226,10 @@ describe('Scroll event responder', () => {
226
onScrollDragStart = jest.fn();
227
ref = React.createRef();
228
const Component = () => {
232
- useScrollListener({
229
+ const listener = useScrollResponder({
230
onScrollDragStart,
231
});
235
- return <div ref={ref} responders={<ScrollResponder />} />;
232
+ return <div ref={ref} listeners={listener} />;
233
};
234
ReactDOM.render(<Component />, container);
235
});
@@ -263,10 +260,10 @@ describe('Scroll event responder', () => {
260
onScrollDragEnd = jest.fn();
261
ref = React.createRef();
262
const Component = () => {
266
- useScrollListener({
263
+ const listener = useScrollResponder({
264
onScrollDragEnd,
265
});
269
- return <div ref={ref} responders={<ScrollResponder />} />;
266
+ return <div ref={ref} listeners={listener} />;
267
};
268
ReactDOM.render(<Component />, container);
269
});
packages/react-events/src/rn/Press.js
+91
-192
@@ -20,30 +20,21 @@ import {
20
DiscreteEvent,
21
UserBlockingEvent,
22
} from 'react-native-renderer/src/ReactNativeTypes';
23
-
24
-type PressListenerProps = {|
25
- onLongPress: (e: PressEvent) => void,
26
- onLongPressChange: boolean => void,
27
- onPress: (e: PressEvent) => void,
28
- onPressChange: boolean => void,
29
- onPressEnd: (e: PressEvent) => void,
30
- onPressMove: (e: PressEvent) => void,
31
- onPressStart: (e: PressEvent) => void,
32
-|};
23
+import type {ReactEventResponderListener} from 'shared/ReactTypes';
24
25
type PressProps = {
26
disabled: boolean,
36
- delayLongPress: number,
37
- delayPressEnd: number,
38
- delayPressStart: number,
27
pressRetentionOffset: {
28
top: number,
29
right: number,
30
bottom: number,
31
left: number,
32
},
45
- enableLongPress: boolean,
46
- longPressShouldCancelPress: () => 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 PressEvent = {|
@@ -68,14 +59,10 @@ type PressState = {
59
addedRootEvents: boolean,
60
isActivePressed: boolean,
61
isActivePressStart: boolean,
71
- isLongPressed: boolean,
62
isPressed: boolean,
63
isPressWithinResponderRegion: boolean,
74
- longPressTimeout: null | number,
64
pointerType: PointerType,
65
pressTarget: null | ReactNativeEventTarget,
77
- pressEndTimeout: null | number,
78
- pressStartTimeout: null | number,
66
responderRegionOnActivation: null | $ReadOnly<{|
67
bottom: number,
68
left: number,
@@ -97,13 +84,8 @@ type PressEventType =
84
| 'pressmove'
85
| 'pressstart'
86
| 'pressend'
100
- | 'presschange'
101
- | 'longpress'
102
- | 'longpresschange';
87
+ | 'presschange';
88
104
-const DEFAULT_PRESS_END_DELAY_MS = 0;
105
-const DEFAULT_PRESS_START_DELAY_MS = 0;
106
-const DEFAULT_LONG_PRESS_DELAY_MS = 500;
89
const DEFAULT_PRESS_RETENTION_OFFSET = {
90
bottom: 20,
91
top: 20,
@@ -114,9 +96,8 @@ const DEFAULT_PRESS_RETENTION_OFFSET = {
96
const targetEventTypes = ['topTouchStart'];
97
const rootEventTypes = ['topTouchMove', 'topTouchEnd', 'topTouchCancel'];
98
117
-function calculateDelayMS(delay: ?number, min = 0, fallback = 0) {
118
- const maybeNumber = delay == null ? null : delay;
119
- return Math.max(min, maybeNumber != null ? maybeNumber : fallback);
99
+function isFunction(obj): boolean {
100
+ return typeof obj === 'function';
101
}
102
103
function createPressEvent(
@@ -163,8 +144,8 @@ function createPressEvent(
144
}
145
146
function dispatchEvent(
166
- eventPropName: string,
147
event: ?ReactNativeResponderEvent,
148
+ listener: any => void,
149
context: ReactNativeResponderContext,
150
state: PressState,
151
name: PressEventType,
@@ -179,7 +160,7 @@ function dispatchEvent(
160
pointerType,
161
state.touchEvent,
162
);
182
- context.dispatchEvent(eventPropName, syntheticEvent, eventPriority);
163
+ context.dispatchEvent(syntheticEvent, listener, eventPriority);
164
}
165
166
function dispatchCancel(event, context, props, state): void {
@@ -267,46 +248,15 @@ function calculateResponderRegion(
248
});
249
}
250
270
-function dispatchPressChangeEvent(context, state): void {
271
- const bool = state.isActivePressed;
272
- context.dispatchEvent('onPressChange', bool, DiscreteEvent);
273
-}
274
-
275
-function dispatchLongPressChangeEvent(context, state): void {
276
- const bool = state.isLongPressed;
277
- context.dispatchEvent('onLongPressChange', bool, DiscreteEvent);
278
-}
279
-
280
-function activate(event: ReactNativeResponderEvent, context, props, state) {
281
- const {pageX: x, pageY: y} = ((state.touchEvent: any): ReactFaricEventTouch);
282
- const wasActivePressed = state.isActivePressed;
283
- state.isActivePressed = true;
284
- if (x !== null && y !== null) {
285
- state.activationPosition = {x, y};
286
- }
287
-
288
- dispatchEvent(
289
- 'onPressStart',
290
- event,
291
- context,
292
- state,
293
- 'pressstart',
294
- DiscreteEvent,
295
- );
296
- if (!wasActivePressed) {
297
- dispatchPressChangeEvent(context, state);
298
- }
299
-}
300
-
301
-function deactivate(event, context, props, state) {
302
- const wasLongPressed = state.isLongPressed;
303
- state.isActivePressed = false;
304
- state.isLongPressed = false;
305
-
306
- dispatchEvent('onPressEnd', event, context, state, 'pressend', DiscreteEvent);
307
- dispatchPressChangeEvent(context, state);
308
- if (wasLongPressed && props.enableLongPress) {
309
- dispatchLongPressChangeEvent(context, state);
251
+function dispatchPressChangeEvent(
252
+ context: ReactNativeResponderContext,
253
+ props: PressProps,
254
+ state: PressState,
255
+): void {
256
+ const onPressChange = props.onPressChange;
257
+ if (isFunction(onPressChange)) {
258
+ const bool = state.isActivePressed;
259
+ context.dispatchEvent(bool, onPressChange, DiscreteEvent);
260
}
261
}
262
@@ -367,97 +317,67 @@ function updateIsPressWithinResponderRegion(
317
cb();
318
}
319
370
-function dispatchPressStartEvents(event, context, props, state) {
320
+function dispatchPressStartEvents(
321
+ event: ReactNativeResponderEvent,
322
+ context: ReactNativeResponderContext,
323
+ props: PressProps,
324
+ state: PressState,
325
+): void {
326
state.isPressed = true;
327
373
- if (state.pressEndTimeout !== null) {
374
- context.clearTimeout(state.pressEndTimeout);
375
- state.pressEndTimeout = null;
376
- }
377
-
378
- const dispatch = () => {
328
+ if (!state.isActivePressStart) {
329
state.isActivePressStart = true;
380
- activate(event, context, props, state);
381
-
382
- if (!state.isLongPressed && props.enableLongPress) {
383
- const delayLongPress = calculateDelayMS(
384
- props.delayLongPress,
385
- 10,
386
- DEFAULT_LONG_PRESS_DELAY_MS,
330
+ const {
331
+ pageX: x,
332
+ pageY: y,
333
+ } = ((state.touchEvent: any): ReactFaricEventTouch);
334
+ const wasActivePressed = state.isActivePressed;
335
+ state.isActivePressed = true;
336
+ if (x !== undefined && y !== undefined) {
337
+ state.activationPosition = {x, y};
338
+ }
339
+ const onPressStart = props.onPressStart;
340
+
341
+ if (isFunction(onPressStart)) {
342
+ dispatchEvent(
343
+ event,
344
+ onPressStart,
345
+ context,
346
+ state,
347
+ 'pressstart',
348
+ DiscreteEvent,
349
);
388
- state.longPressTimeout = context.setTimeout(() => {
389
- state.isLongPressed = true;
390
- state.longPressTimeout = null;
391
- dispatchEvent(
392
- 'onLongPress',
393
- event,
394
- context,
395
- state,
396
- 'longpress',
397
- DiscreteEvent,
398
- );
399
- dispatchLongPressChangeEvent(context, state);
400
- }, delayLongPress);
350
}
402
- };
403
-
404
- if (!state.isActivePressStart) {
405
- const delayPressStart = calculateDelayMS(
406
- props.delayPressStart,
407
- 0,
408
- DEFAULT_PRESS_START_DELAY_MS,
409
- );
410
- if (delayPressStart > 0) {
411
- state.pressStartTimeout = context.setTimeout(() => {
412
- state.pressStartTimeout = null;
413
- dispatch();
414
- }, delayPressStart);
415
- } else {
416
- dispatch();
351
+ if (!wasActivePressed) {
352
+ dispatchPressChangeEvent(context, props, state);
353
}
354
}
355
}
356
421
-function dispatchPressEndEvents(event, context, props, state): void {
422
- const wasActivePressStart = state.isActivePressStart;
423
- let activationWasForced = false;
424
-
357
+function dispatchPressEndEvents(
358
+ event: ?ReactNativeResponderEvent,
359
+ context: ReactNativeResponderContext,
360
+ props: PressProps,
361
+ state: PressState,
362
+): void {
363
state.isActivePressStart = false;
364
state.isPressed = false;
365
428
- if (state.longPressTimeout !== null) {
429
- context.clearTimeout(state.longPressTimeout);
430
- state.longPressTimeout = null;
431
- }
432
-
433
- if (!wasActivePressStart && state.pressStartTimeout !== null) {
434
- context.clearTimeout(state.pressStartTimeout);
435
- state.pressStartTimeout = null;
436
- // don't activate if a press has moved beyond the responder region
437
- if (state.isPressWithinResponderRegion && event != null) {
438
- // if we haven't yet activated (due to delays), activate now
439
- activate(event, context, props, state);
440
- activationWasForced = true;
441
- }
442
- }
443
-
366
if (state.isActivePressed) {
445
- const delayPressEnd = calculateDelayMS(
446
- props.delayPressEnd,
447
- // if activation and deactivation occur during the same event there's no
448
- // time for visual user feedback therefore a small delay is added before
449
- // deactivating.
450
- activationWasForced ? 10 : 0,
451
- DEFAULT_PRESS_END_DELAY_MS,
452
- );
453
- if (delayPressEnd > 0) {
454
- state.pressEndTimeout = context.setTimeout(() => {
455
- state.pressEndTimeout = null;
456
- deactivate(event, context, props, state);
457
- }, delayPressEnd);
458
- } else {
459
- deactivate(event, context, props, state);
367
+ state.isActivePressed = false;
368
+ const onPressEnd = props.onPressEnd;
369
+
370
+ if (isFunction(onPressEnd)) {
371
+ dispatchEvent(
372
+ event,
373
+ onPressEnd,
374
+ context,
375
+ state,
376
+ 'pressend',
377
+ DiscreteEvent,
378
+ );
379
}
380
+ dispatchPressChangeEvent(context, props, state);
381
}
382
383
state.responderRegionOnDeactivation = null;
@@ -472,13 +392,9 @@ const pressResponderImpl = {
392
addedRootEvents: false,
393
isActivePressed: false,
394
isActivePressStart: false,
475
- isLongPressed: false,
395
isPressed: false,
396
isPressWithinResponderRegion: false,
478
- longPressTimeout: null,
397
pointerType: '',
480
- pressEndTimeout: null,
481
- pressStartTimeout: null,
398
pressTarget: null,
399
responderRegionOnActivation: null,
400
responderRegionOnDeactivation: null,
@@ -545,26 +461,16 @@ const pressResponderImpl = {
461
() => {
462
if (state.isPressWithinResponderRegion) {
463
if (state.isPressed) {
548
- dispatchEvent(
549
- 'onPressMove',
550
- event,
551
- context,
552
- state,
553
- 'pressmove',
554
- UserBlockingEvent,
555
- );
556
- if (
557
- state.activationPosition != null &&
558
- state.longPressTimeout != null
559
- ) {
560
- const deltaX = state.activationPosition.x - touchEvent.pageX;
561
- const deltaY = state.activationPosition.y - touchEvent.pageY;
562
- if (
563
- Math.hypot(deltaX, deltaY) > 10 &&
564
- state.longPressTimeout != null
565
- ) {
566
- context.clearTimeout(state.longPressTimeout);
567
- }
464
+ const onPressMove = props.onPressMove;
465
+ if (isFunction(onPressMove)) {
466
+ dispatchEvent(
467
+ event,
468
+ onPressMove,
469
+ context,
470
+ state,
471
+ 'pressmove',
472
+ UserBlockingEvent,
473
+ );
474
}
475
} else {
476
dispatchPressStartEvents(event, context, props, state);
@@ -583,10 +489,10 @@ const pressResponderImpl = {
489
return;
490
}
491
state.touchEvent = touchEvent;
586
- const wasLongPressed = state.isLongPressed;
492
dispatchPressEndEvents(event, context, props, state);
493
+ const onPress = props.onPress;
494
589
- if (state.pressTarget !== null) {
495
+ if (state.pressTarget !== null && isFunction(onPress)) {
496
// If the event target isn't within the press target, check if we're still
497
// within the responder region. The region may have changed if the
498
// element's layout was modified after activation.
@@ -598,23 +504,14 @@ const pressResponderImpl = {
504
state,
505
() => {
506
if (state.isPressWithinResponderRegion) {
601
- if (
602
- !(
603
- wasLongPressed &&
604
- props.enableLongPress &&
605
- props.longPressShouldCancelPress &&
606
- props.longPressShouldCancelPress()
607
- )
608
- ) {
609
- dispatchEvent(
610
- 'onPress',
611
- event,
612
- context,
613
- state,
614
- 'press',
615
- DiscreteEvent,
616
- );
617
- }
507
+ dispatchEvent(
508
+ event,
509
+ onPress,
510
+ context,
511
+ state,
512
+ 'press',
513
+ DiscreteEvent,
514
+ );
515
}
516
},
517
);
@@ -636,6 +533,8 @@ export const PressResponder = React.unstable_createResponder(
533
pressResponderImpl,
534
);
535
639
-export function usePressListener(props: PressListenerProps): void {
640
- React.unstable_useListener(PressResponder, props);
536
+export function usePressResponder(
537
+ props: PressProps,
538
+): ReactEventResponderListener<any, any> {
539
+ return React.unstable_useResponder(PressResponder, props);
540
}
packages/react-native-renderer/src/ReactFabricEventResponderSystem.js
+11
-83
@@ -7,12 +7,7 @@
7
* @flow
8
*/
9
10
-import {
11
- HostComponent,
12
- FunctionComponent,
13
- MemoComponent,
14
- ForwardRef,
15
-} from 'shared/ReactWorkTags';
10
+import {HostComponent} from 'shared/ReactWorkTags';
11
import type {Fiber} from 'react-reconciler/src/ReactFiber';
12
import {
13
batchedEventUpdates,
@@ -49,7 +44,7 @@ const {
44
} = Scheduler;
45
46
type EventQueueItem = {|
52
- listeners: Array<(val: any) => void>,
47
+ listener: (val: any) => void,
48
value: any,
49
|};
50
type EventQueue = Array<EventQueueItem>;
@@ -98,8 +93,8 @@ let currentTimerIDCounter = 0;
93
94
const eventResponderContext: ReactNativeResponderContext = {
95
dispatchEvent(
101
- eventProp: string,
96
eventValue: any,
97
+ eventListener: any => void,
98
eventPriority: EventPriority,
99
): void {
100
validateResponderContext();
@@ -107,15 +102,9 @@ const eventResponderContext: ReactNativeResponderContext = {
102
if (eventPriority < currentEventQueuePriority) {
103
currentEventQueuePriority = eventPriority;
104
}
110
- const responderInstance = ((currentInstance: any): ReactNativeEventResponderInstance);
111
- const target = responderInstance.fiber;
112
- const responder = responderInstance.responder;
113
- const listeners = collectListeners(eventProp, responder, target);
114
- if (listeners.length !== 0) {
115
- ((currentEventQueue: any): EventQueue).push(
116
- createEventQueueItem(eventValue, listeners),
117
- );
118
- }
105
+ ((currentEventQueue: any): EventQueue).push(
106
+ createEventQueueItem(eventValue, eventListener),
107
+ );
108
},
109
isTargetWithinNode(
110
childTarget: ReactNativeEventTarget,
@@ -228,11 +217,11 @@ const eventResponderContext: ReactNativeResponderContext = {
217
218
function createEventQueueItem(
219
value: any,
231
- listeners: Array<(val: any) => void>,
220
+ listener: (val: any) => void,
221
): EventQueueItem {
222
return {
223
value,
235
- listeners,
224
+ listener,
225
};
226
}
227
@@ -390,74 +379,13 @@ function releaseOwnershipForEventResponderInstance(
379
return false;
380
}
381
393
-// TODO this function is almost an exact copy of the DOM version, we should
394
-// somehow share the logic
395
-function collectListeners(
396
- eventProp: string,
397
- eventResponder: ReactNativeEventResponder,
398
- target: Fiber,
399
-): Array<(any) => void> {
400
- const eventListeners = [];
401
- let node = target.return;
402
- nodeTraversal: while (node !== null) {
403
- switch (node.tag) {
404
- case HostComponent: {
405
- const dependencies = node.dependencies;
406
-
407
- if (dependencies !== null) {
408
- const respondersMap = dependencies.responders;
409
-
410
- if (respondersMap !== null && respondersMap.has(eventResponder)) {
411
- break nodeTraversal;
412
- }
413
- }
414
- break;
415
- }
416
- case FunctionComponent:
417
- case MemoComponent:
418
- case ForwardRef: {
419
- const dependencies = node.dependencies;
420
-
421
- if (dependencies !== null) {
422
- const listeners = dependencies.listeners;
423
-
424
- if (listeners !== null) {
425
- for (
426
- let s = 0, listenersLength = listeners.length;
427
- s < listenersLength;
428
- s++
429
- ) {
430
- const listener = listeners[s];
431
- const {responder, props} = listener;
432
- const listenerFunc = props[eventProp];
433
-
434
- if (
435
- responder === eventResponder &&
436
- typeof listenerFunc === 'function'
437
- ) {
438
- eventListeners.push(listenerFunc);
439
- }
440
- }
441
- }
442
- }
443
- }
444
- }
445
- node = node.return;
446
- }
447
- return eventListeners;
448
-}
449
-
382
// TODO this function is almost an exact copy of the DOM version, we should
383
// somehow share the logic
384
function processEvents(eventQueue: EventQueue): void {
385
for (let i = 0, length = eventQueue.length; i < length; i++) {
454
- const {value, listeners} = eventQueue[i];
455
- for (let s = 0, length2 = listeners.length; s < length2; s++) {
456
- const listener = listeners[s];
457
- const type =
458
- typeof value === 'object' && value !== null ? value.type : '';
459
- invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, value);
460
- }
386
+ const {value, listener} = eventQueue[i];
387
+ const type = typeof value === 'object' && value !== null ? value.type : '';
388
+ invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, value);
389
}
390
}
391
packages/react-native-renderer/src/ReactNativeTypes.js
+1
-1
@@ -198,8 +198,8 @@ export type ReactNativeResponderEvent = {
198
199
export type ReactNativeResponderContext = {
200
dispatchEvent: (
201
- eventProp: string,
201
eventValue: any,
202
+ listener: (any) => void,
203
eventPriority: EventPriority,
204
) => void,
205
isTargetWithinNode: (
packages/react-reconciler/src/ReactFiber.js
-6
@@ -107,10 +107,6 @@ if (__DEV__) {
107
export type Dependencies = {
108
expirationTime: ExpirationTime,
109
firstContext: ContextDependency<mixed> | null,
110
- listeners: Array<{
111
- responder: ReactEventResponder<any, any>,
112
- props: Object,
113
- }> | null,
110
responders: Map<
111
ReactEventResponder<any, any>,
112
ReactEventResponderInstance<any, any>,
@@ -457,7 +453,6 @@ export function createWorkInProgress(
453
: {
454
expirationTime: currentDependencies.expirationTime,
455
firstContext: currentDependencies.firstContext,
460
- listeners: currentDependencies.listeners,
456
responders: currentDependencies.responders,
457
};
458
@@ -553,7 +548,6 @@ export function resetWorkInProgress(
548
: {
549
expirationTime: currentDependencies.expirationTime,
550
firstContext: currentDependencies.firstContext,
556
- listeners: currentDependencies.listeners,
551
responders: currentDependencies.responders,
552
};
553
packages/react-reconciler/src/ReactFiberBeginWork.js
-20
@@ -60,7 +60,6 @@ import {
60
enableProfilerTimer,
61
enableSchedulerTracing,
62
enableSuspenseServerRenderer,
63
- enableFlareAPI,
63
enableFundamentalAPI,
64
warnAboutDefaultPropsOnFunctionComponents,
65
} from 'shared/ReactFeatureFlags';
@@ -173,7 +172,6 @@ import {
172
requestCurrentTime,
173
retryTimedOutBoundary,
174
} from './ReactFiberWorkLoop';
176
-import {prepareToReadListenerHooks} from './ReactFiberEvents';
175
176
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
177
@@ -302,9 +300,6 @@ function updateForwardRef(
300
// The rest is a fork of updateFunctionComponent
301
let nextChildren;
302
prepareToReadContext(workInProgress, renderExpirationTime);
305
- if (enableFlareAPI) {
306
- prepareToReadListenerHooks(workInProgress);
307
- }
303
if (__DEV__) {
304
ReactCurrentOwner.current = workInProgress;
305
setCurrentPhase('render');
@@ -323,9 +318,6 @@ function updateForwardRef(
318
) {
319
// Only double-render components with Hooks
320
if (workInProgress.memoizedState !== null) {
326
- if (enableFlareAPI) {
327
- prepareToReadListenerHooks(workInProgress);
328
- }
321
nextChildren = renderWithHooks(
322
current,
323
workInProgress,
@@ -628,9 +620,6 @@ function updateFunctionComponent(
620
621
let nextChildren;
622
prepareToReadContext(workInProgress, renderExpirationTime);
631
- if (enableFlareAPI) {
632
- prepareToReadListenerHooks(workInProgress);
633
- }
623
if (__DEV__) {
624
ReactCurrentOwner.current = workInProgress;
625
setCurrentPhase('render');
@@ -649,9 +638,6 @@ function updateFunctionComponent(
638
) {
639
// Only double-render components with Hooks
640
if (workInProgress.memoizedState !== null) {
652
- if (enableFlareAPI) {
653
- prepareToReadListenerHooks(workInProgress);
654
- }
641
nextChildren = renderWithHooks(
642
current,
643
workInProgress,
@@ -1248,9 +1234,6 @@ function mountIndeterminateComponent(
1234
const context = getMaskedContext(workInProgress, unmaskedContext);
1235
1236
prepareToReadContext(workInProgress, renderExpirationTime);
1251
- if (enableFlareAPI) {
1252
- prepareToReadListenerHooks(workInProgress);
1253
- }
1237
let value;
1238
1239
if (__DEV__) {
@@ -1373,9 +1356,6 @@ function mountIndeterminateComponent(
1356
) {
1357
// Only double-render components with Hooks
1358
if (workInProgress.memoizedState !== null) {
1376
- if (enableFlareAPI) {
1377
- prepareToReadListenerHooks(workInProgress);
1378
- }
1359
value = renderWithHooks(
1360
null,
1361
workInProgress,
packages/react-reconciler/src/ReactFiberCompleteWork.js
+43
-30
@@ -13,6 +13,7 @@ import type {
13
ReactEventResponder,
14
ReactEventResponderInstance,
15
ReactFundamentalComponentInstance,
16
+ ReactEventResponderListener,
17
} from 'shared/ReactTypes';
18
import type {FiberRoot} from './ReactFiberRoot';
19
import type {
@@ -133,6 +134,7 @@ import {
134
import {createFundamentalStateInstance} from './ReactFiberFundamental';
135
import {Never} from './ReactFiberExpirationTime';
136
import {resetChildFibers} from './ReactChildFiber';
137
+import warning from 'shared/warning';
138
139
const emptyObject = {};
140
const isArray = Array.isArray;
@@ -690,12 +692,12 @@ function completeWork(
692
);
693
694
if (enableFlareAPI) {
693
- const prevResponders = current.memoizedProps.responders;
694
- const nextResponders = newProps.responders;
695
+ const prevListeners = current.memoizedProps.listeners;
696
+ const nextListeners = newProps.listeners;
697
const instance = workInProgress.stateNode;
696
- if (prevResponders !== nextResponders) {
697
- updateEventResponders(
698
- nextResponders,
698
+ if (prevListeners !== nextListeners) {
699
+ updateEventListeners(
700
+ nextListeners,
701
instance,
702
rootContainerInstance,
703
workInProgress,
@@ -749,10 +751,10 @@ function completeWork(
751
appendAllChildren(instance, workInProgress, false, false);
752
753
if (enableFlareAPI) {
752
- const responders = newProps.responders;
753
- if (responders != null) {
754
- updateEventResponders(
755
- responders,
754
+ const listeners = newProps.listeners;
755
+ if (listeners != null) {
756
+ updateEventListeners(
757
+ listeners,
758
instance,
759
rootContainerInstance,
760
workInProgress,
@@ -1270,9 +1272,8 @@ function mountEventResponder(
1272
respondersMap.set(responder, responderInstance);
1273
}
1274
1273
-function updateEventResponder(
1274
- responder: ReactEventResponder<any, any>,
1275
- props: Object,
1275
+function updateEventListener(
1276
+ listener: ReactEventResponderListener<any, any>,
1277
fiber: Fiber,
1278
visistedResponders: Set<ReactEventResponder<any, any>>,
1279
respondersMap: Map<
@@ -1282,13 +1283,29 @@ function updateEventResponder(
1283
instance: Instance,
1284
rootContainerInstance: Container,
1285
): void {
1286
+ let responder;
1287
+ let props;
1288
+
1289
+ if (listener) {
1290
+ responder = listener.responder;
1291
+ props = listener.props;
1292
+ }
1293
invariant(
1294
responder && responder.$$typeof === REACT_RESPONDER_TYPE,
1287
- 'An invalid value was used as an event responder. Expect one or many event ' +
1288
- 'responders created via React.unstable_createResponer().',
1295
+ 'An invalid value was used as an event listener. Expect one or many event ' +
1296
+ 'listeners created via React.unstable_useResponer().',
1297
);
1298
+ const listenerProps = ((props: any): Object);
1299
if (visistedResponders.has(responder)) {
1300
// show warning
1301
+ if (__DEV__) {
1302
+ warning(
1303
+ false,
1304
+ 'Duplicate event responder "%s" found in event listeners. ' +
1305
+ 'Event listeners passed to elements cannot use the same event responder more than once.',
1306
+ responder.displayName,
1307
+ );
1308
+ }
1309
return;
1310
}
1311
visistedResponders.add(responder);
@@ -1298,7 +1315,7 @@ function updateEventResponder(
1315
// Mount
1316
mountEventResponder(
1317
responder,
1301
- props,
1318
+ listenerProps,
1319
instance,
1320
rootContainerInstance,
1321
fiber,
@@ -1306,25 +1323,24 @@ function updateEventResponder(
1323
);
1324
} else {
1325
// Update
1309
- responderInstance.props = props;
1326
+ responderInstance.props = listenerProps;
1327
responderInstance.fiber = fiber;
1328
}
1329
}
1330
1314
-function updateEventResponders(
1315
- responders: any,
1331
+function updateEventListeners(
1332
+ listeners: any,
1333
instance: Instance,
1334
rootContainerInstance: Container,
1335
fiber: Fiber,
1336
): void {
1337
const visistedResponders = new Set();
1338
let dependencies = fiber.dependencies;
1322
- if (responders != null) {
1339
+ if (listeners != null) {
1340
if (dependencies === null) {
1341
dependencies = fiber.dependencies = {
1342
expirationTime: NoWork,
1343
firstContext: null,
1327
- listeners: null,
1344
responders: new Map(),
1345
};
1346
}
@@ -1332,12 +1348,11 @@ function updateEventResponders(
1348
if (respondersMap === null) {
1349
respondersMap = new Map();
1350
}
1335
- if (isArray(responders)) {
1336
- for (let i = 0, length = responders.length; i < length; i++) {
1337
- const {type, props} = responders[i];
1338
- updateEventResponder(
1339
- type,
1340
- props,
1351
+ if (isArray(listeners)) {
1352
+ for (let i = 0, length = listeners.length; i < length; i++) {
1353
+ const listener = listeners[i];
1354
+ updateEventListener(
1355
+ listener,
1356
fiber,
1357
visistedResponders,
1358
respondersMap,
@@ -1346,10 +1361,8 @@ function updateEventResponders(
1361
);
1362
}
1363
} else {
1349
- const {type, props} = responders;
1350
- updateEventResponder(
1351
- type,
1352
- props,
1364
+ updateEventListener(
1365
+ listeners,
1366
fiber,
1367
visistedResponders,
1368
respondersMap,
packages/react-reconciler/src/ReactFiberEvents.js
+11
-46
@@ -7,63 +7,28 @@
7
* @flow
8
*/
9
10
-import type {Fiber, Dependencies} from './ReactFiber';
10
+import type {Fiber} from './ReactFiber';
11
import type {
12
ReactEventResponder,
13
ReactEventResponderInstance,
14
+ ReactEventResponderListener,
15
} from 'shared/ReactTypes';
16
import type {Instance} from './ReactFiberHostConfig';
17
17
-import {NoWork} from './ReactFiberExpirationTime';
18
-
18
import {SuspenseComponent, Fragment} from 'shared/ReactWorkTags';
19
21
-let currentlyRenderingFiber: null | Fiber = null;
22
-let currentListenerHookIndex: number = 0;
23
-
24
-export function prepareToReadListenerHooks(workInProgress: Fiber): void {
25
- currentlyRenderingFiber = workInProgress;
26
- currentListenerHookIndex = 0;
27
-}
28
-
29
-function getListenerHooks(): Array<{
30
- responder: ReactEventResponder<any, any>,
31
- props: Object,
32
-}> {
33
- let listeners;
34
- let dependencies: Dependencies | null = ((currentlyRenderingFiber: any): Fiber)
35
- .dependencies;
36
- if (dependencies === null) {
37
- dependencies = ((currentlyRenderingFiber: any): Fiber).dependencies = {
38
- expirationTime: NoWork,
39
- firstContext: null,
40
- listeners: [],
41
- responders: null,
42
- };
43
- }
44
- listeners = dependencies.listeners;
45
- if (listeners === null) {
46
- dependencies.listeners = listeners = [];
47
- }
48
- return listeners;
49
-}
50
-
51
-export function updateListenerHook(
20
+export function createResponderListener(
21
responder: ReactEventResponder<any, any>,
22
props: Object,
54
-) {
55
- const listeners = getListenerHooks();
56
- if (listeners.length === currentListenerHookIndex) {
57
- listeners.push({
58
- responder,
59
- props,
60
- });
61
- currentListenerHookIndex++;
62
- } else {
63
- const currentListenerHook = listeners[currentListenerHookIndex++];
64
- currentListenerHook.responder = responder;
65
- currentListenerHook.props = props;
23
+): ReactEventResponderListener<any, any> {
24
+ const eventResponderListener = {
25
+ responder,
26
+ props,
27
+ };
28
+ if (__DEV__) {
29
+ Object.freeze(eventResponderListener);
30
}
31
+ return eventResponderListener;
32
}
33
34
export function isFiberSuspenseAndTimedOut(fiber: Fiber): boolean {
packages/react-reconciler/src/ReactFiberHooks.js
+44
-22
@@ -7,7 +7,11 @@
7
* @flow
8
*/
9
10
-import type {ReactEventResponder, ReactContext} from 'shared/ReactTypes';
10
+import type {
11
+ ReactEventResponder,
12
+ ReactContext,
13
+ ReactEventResponderListener,
14
+} from 'shared/ReactTypes';
15
import type {SideEffectTag} from 'shared/ReactSideEffectTags';
16
import type {Fiber} from './ReactFiber';
17
import type {ExpirationTime} from './ReactFiberExpirationTime';
@@ -19,7 +23,7 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
23
24
import {NoWork} from './ReactFiberExpirationTime';
25
import {readContext} from './ReactFiberNewContext';
22
-import {updateListenerHook} from './ReactFiberEvents';
26
+import {createResponderListener} from './ReactFiberEvents';
27
import {
28
Update as UpdateEffect,
29
Passive as PassiveEffect,
@@ -85,7 +89,10 @@ export type Dispatcher = {
89
deps: Array<mixed> | void | null,
90
): void,
91
useDebugValue<T>(value: T, formatterFn: ?(value: T) => mixed): void,
88
- useListener<E, C>(responder: ReactEventResponder<E, C>, props: Object): void,
92
+ useResponder<E, C>(
93
+ responder: ReactEventResponder<E, C>,
94
+ props: Object,
95
+ ): ReactEventResponderListener<E, C>,
96
};
97
98
type Update<S, A> = {
@@ -117,7 +124,7 @@ export type HookType =
124
| 'useMemo'
125
| 'useImperativeHandle'
126
| 'useDebugValue'
120
- | 'useListener';
127
+ | 'useResponder';
128
129
let didWarnAboutMismatchedHooksForComponent;
130
if (__DEV__) {
@@ -1262,7 +1269,7 @@ export const ContextOnlyDispatcher: Dispatcher = {
1269
useRef: throwInvalidHookError,
1270
useState: throwInvalidHookError,
1271
useDebugValue: throwInvalidHookError,
1265
- useListener: throwInvalidHookError,
1272
+ useResponder: throwInvalidHookError,
1273
};
1274
1275
const HooksDispatcherOnMount: Dispatcher = {
@@ -1278,7 +1285,7 @@ const HooksDispatcherOnMount: Dispatcher = {
1285
useRef: mountRef,
1286
useState: mountState,
1287
useDebugValue: mountDebugValue,
1281
- useListener: updateListenerHook,
1288
+ useResponder: createResponderListener,
1289
};
1290
1291
const HooksDispatcherOnUpdate: Dispatcher = {
@@ -1294,7 +1301,7 @@ const HooksDispatcherOnUpdate: Dispatcher = {
1301
useRef: updateRef,
1302
useState: updateState,
1303
useDebugValue: updateDebugValue,
1297
- useListener: updateListenerHook,
1304
+ useResponder: createResponderListener,
1305
};
1306
1307
let HooksDispatcherOnMountInDEV: Dispatcher | null = null;
@@ -1424,10 +1431,13 @@ if (__DEV__) {
1431
mountHookTypesDev();
1432
return mountDebugValue(value, formatterFn);
1433
},
1427
- useListener<E, C>(responder: ReactEventResponder<E, C>, props) {
1428
- currentHookNameInDev = 'useListener';
1434
+ useResponder<E, C>(
1435
+ responder: ReactEventResponder<E, C>,
1436
+ props,
1437
+ ): ReactEventResponderListener<E, C> {
1438
+ currentHookNameInDev = 'useResponder';
1439
mountHookTypesDev();
1430
- updateListenerHook(responder, props);
1440
+ return createResponderListener(responder, props);
1441
},
1442
};
1443
@@ -1526,10 +1536,13 @@ if (__DEV__) {
1536
updateHookTypesDev();
1537
return mountDebugValue(value, formatterFn);
1538
},
1529
- useListener<E, C>(responder: ReactEventResponder<E, C>, props) {
1530
- currentHookNameInDev = 'useListener';
1539
+ useResponder<E, C>(
1540
+ responder: ReactEventResponder<E, C>,
1541
+ props,
1542
+ ): ReactEventResponderListener<E, C> {
1543
+ currentHookNameInDev = 'useResponder';
1544
updateHookTypesDev();
1532
- updateListenerHook(responder, props);
1545
+ return createResponderListener(responder, props);
1546
},
1547
};
1548
@@ -1628,10 +1641,13 @@ if (__DEV__) {
1641
updateHookTypesDev();
1642
return updateDebugValue(value, formatterFn);
1643
},
1631
- useListener<E, C>(responder: ReactEventResponder<E, C>, props) {
1632
- currentHookNameInDev = 'useListener';
1644
+ useResponder<E, C>(
1645
+ responder: ReactEventResponder<E, C>,
1646
+ props,
1647
+ ): ReactEventResponderListener<E, C> {
1648
+ currentHookNameInDev = 'useResponder';
1649
updateHookTypesDev();
1634
- updateListenerHook(responder, props);
1650
+ return createResponderListener(responder, props);
1651
},
1652
};
1653
@@ -1741,11 +1757,14 @@ if (__DEV__) {
1757
mountHookTypesDev();
1758
return mountDebugValue(value, formatterFn);
1759
},
1744
- useListener<E, C>(responder: ReactEventResponder<E, C>, props) {
1745
- currentHookNameInDev = 'useListener';
1760
+ useResponder<E, C>(
1761
+ responder: ReactEventResponder<E, C>,
1762
+ props,
1763
+ ): ReactEventResponderListener<E, C> {
1764
+ currentHookNameInDev = 'useResponder';
1765
warnInvalidHookAccess();
1766
mountHookTypesDev();
1748
- updateListenerHook(responder, props);
1767
+ return createResponderListener(responder, props);
1768
},
1769
};
1770
@@ -1855,11 +1874,14 @@ if (__DEV__) {
1874
updateHookTypesDev();
1875
return updateDebugValue(value, formatterFn);
1876
},
1858
- useListener<E, C>(responder: ReactEventResponder<E, C>, props) {
1859
- currentHookNameInDev = 'useListener';
1877
+ useResponder<E, C>(
1878
+ responder: ReactEventResponder<E, C>,
1879
+ props,
1880
+ ): ReactEventResponderListener<E, C> {
1881
+ currentHookNameInDev = 'useResponder';
1882
warnInvalidHookAccess();
1883
updateHookTypesDev();
1862
- updateListenerHook(responder, props);
1884
+ return createResponderListener(responder, props);
1885
},
1886
};
1887
}
packages/react-reconciler/src/ReactFiberNewContext.js
-1
@@ -377,7 +377,6 @@ export function readContext<T>(
377
currentlyRenderingFiber.dependencies = {
378
expirationTime: NoWork,
379
firstContext: contextItem,
380
- listeners: null,
380
responders: null,
381
};
382
} else {
packages/react-test-renderer/src/ReactShallowRenderer.js
+13
-2
@@ -19,7 +19,10 @@ import warning from 'shared/warning';
19
import is from 'shared/objectIs';
20
21
import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberHooks';
22
-import type {ReactContext} from 'shared/ReactTypes';
22
+import type {
23
+ ReactContext,
24
+ ReactEventResponderListener,
25
+} from 'shared/ReactTypes';
26
import type {ReactElement} from 'shared/ReactElementType';
27
28
type BasicStateAction<S> = (S => S) | S;
@@ -366,6 +369,14 @@ class ReactShallowRenderer {
369
return fn;
370
};
371
372
+ const useResponder = (
373
+ responder,
374
+ props,
375
+ ): ReactEventResponderListener<any, any> => ({
376
+ props: props,
377
+ responder,
378
+ });
379
+
380
return {
381
readContext,
382
useCallback: (identity: any),
@@ -381,7 +392,7 @@ class ReactShallowRenderer {
392
useReducer,
393
useRef,
394
useState,
384
- useListener: noOp,
395
+ useResponder,
396
};
397
}
398
packages/react-test-renderer/src/ReactTestHostConfig.js
+5
-5
@@ -142,11 +142,11 @@ export function createInstance(
142
): Instance {
143
let propsToUse = props;
144
if (enableFlareAPI) {
145
- if (props.responders != null) {
146
- // We want to remove the "responders" prop
147
- // as we don't want it into the test renderer instance's
148
- // props object.
149
- const {responders, ...otherProps} = props; // eslint-disable-line
145
+ if (props.listeners != null) {
146
+ // We want to remove the "listeners" prop
147
+ // as we don't want it in the test renderer's
148
+ // instance props.
149
+ const {listeners, ...otherProps} = props; // eslint-disable-line
150
propsToUse = otherProps;
151
}
152
}
packages/react/src/React.js
+2
-2
@@ -39,7 +39,7 @@ import {
39
useReducer,
40
useRef,
41
useState,
42
- useListener,
42
+ useResponder,
43
} from './ReactHooks';
44
import {withSuspenseConfig} from './ReactBatchConfig';
45
import {
@@ -106,7 +106,7 @@ const React = {
106
};
107
108
if (enableFlareAPI) {
109
- React.unstable_useListener = useListener;
109
+ React.unstable_useResponder = useResponder;
110
React.unstable_createResponder = createResponder;
111
}
112
packages/react/src/ReactHooks.js
+10
-6
@@ -7,7 +7,11 @@
7
* @flow
8
*/
9
10
-import type {ReactContext, ReactEventResponder} from 'shared/ReactTypes';
10
+import type {
11
+ ReactContext,
12
+ ReactEventResponder,
13
+ ReactEventResponderListener,
14
+} from 'shared/ReactTypes';
15
import invariant from 'shared/invariant';
16
import warning from 'shared/warning';
17
import {REACT_RESPONDER_TYPE} from 'shared/ReactSymbols';
@@ -139,20 +143,20 @@ export function useDebugValue(value: any, formatterFn: ?(value: any) => any) {
143
144
export const emptyObject = {};
145
142
-export function useListener(
146
+export function useResponder(
147
responder: ReactEventResponder<any, any>,
144
- hookProps: ?Object,
145
-) {
148
+ listenerProps: ?Object,
149
+): ?ReactEventResponderListener<any, any> {
150
const dispatcher = resolveDispatcher();
151
if (__DEV__) {
152
if (responder == null || responder.$$typeof !== REACT_RESPONDER_TYPE) {
153
warning(
154
false,
151
- 'useListener: invalid first argument. Expected an event responder, but instead got %s',
155
+ 'useResponder: invalid first argument. Expected an event responder, but instead got %s',
156
responder,
157
);
158
return;
159
}
160
}
157
- return dispatcher.useListener(responder, hookProps || emptyObject);
161
+ return dispatcher.useResponder(responder, listenerProps || emptyObject);
162
}
packages/shared/ReactDOMTypes.js
+1
-1
@@ -52,8 +52,8 @@ export type ReactDOMFundamentalComponentInstance = ReactFundamentalComponentInst
52
53
export type ReactDOMResponderContext = {
54
dispatchEvent: (
55
- eventProp: string,
55
eventValue: any,
56
+ listener: (any) => void,
57
eventPriority: EventPriority,
58
) => void,
59
isTargetWithinNode: (
packages/shared/ReactTypes.js
+5
@@ -88,6 +88,11 @@ export type ReactEventResponderInstance<E, C> = {|
88
target: mixed,
89
|};
90
91
+export type ReactEventResponderListener<E, C> = {|
92
+ props: Object,
93
+ responder: ReactEventResponder<E, C>,
94
+|};
95
+
96
export type ReactEventResponder<E, C> = {
97
$$typeof: Symbol | number,
98
displayName: string,
scripts/error-codes/codes.json
+2
-1
@@ -337,5 +337,6 @@
337
"336": "The \"%s\" event responder cannot be used via the \"useEvent\" hook.",
338
"337": "An invalid event responder was provided to host component",
339
"338": "ReactDOMServer does not yet support the fundamental API.",
340
- "339": "An invalid value was used as an event responder. Expect one or many event responders created via React.unstable_createResponer()."
340
+ "339": "An invalid value was used as an event responder. Expect one or many event responders created via React.unstable_createResponer().",
341
+ "340": "An invalid value was used as an event listener. Expect one or many event listeners created via React.unstable_useResponer()."
342
}