@samitouri / QOS-React-2 / commits / 42794557ca

[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 }