[Flare] Add currentTarget and unify RN and DOM codepaths (#16066)
Dominic Gannaway committed
Jul 8, 2019 at 11:50 UTC
aa519c17cc10c071906d06abeade9e1bd0ed3dc1
8 files changed
+215
-278
packages/react-dom/src/events/DOMEventResponderSystem.js
+82
-134
@@ -372,29 +372,6 @@ const eventResponderContext: ReactDOMResponderContext = {
372
},
373
getActiveDocument,
374
objectAssign: Object.assign,
375
- getEventCurrentTarget(event: ReactDOMResponderEvent): Element {
376
- validateResponderContext();
377
- const target = event.target;
378
- let fiber = getClosestInstanceFromNode(target);
379
- let hostComponent = target;
380
- const currentResponder = ((currentInstance: any): ReactDOMEventComponentInstance)
381
- .responder;
382
-
383
- while (fiber !== null) {
384
- const stateNode = fiber.stateNode;
385
- if (
386
- fiber.tag === EventComponent &&
387
- (stateNode === null || stateNode.responder === currentResponder)
388
- ) {
389
- break;
390
- }
391
- if (fiber.tag === HostComponent) {
392
- hostComponent = fiber.stateNode;
393
- }
394
- fiber = fiber.return;
395
- }
396
- return ((hostComponent: any): Element);
397
- },
375
getTimeStamp(): number {
376
validateResponderContext();
377
return currentTimeStamp;
@@ -553,6 +530,7 @@ function createDOMResponderEvent(
530
}
531
532
return {
533
+ currentTarget: nativeEventTarget,
534
nativeEvent: nativeEvent,
535
passive,
536
passiveSupported,
@@ -650,11 +628,12 @@ function getDOMTargetEventTypesSet(
628
return cachedSet;
629
}
630
653
-function storeTargetEventResponderInstance(
631
+function handleTargetEventResponderInstance(
632
listeningName: string,
633
+ responderEvent: ReactDOMResponderEvent,
634
eventComponentInstance: ReactDOMEventComponentInstance,
656
- eventResponderInstances: Array<ReactDOMEventComponentInstance>,
657
- eventComponentResponders: null | Set<ReactDOMEventResponder>,
635
+ hookComponentResponderValidation: null | Set<ReactDOMEventResponder>,
636
+ propagatedEventResponders: null | Set<ReactDOMEventResponder>,
637
): void {
638
const responder = eventComponentInstance.responder;
639
const targetEventTypes = responder.targetEventTypes;
@@ -662,74 +641,34 @@ function storeTargetEventResponderInstance(
641
if (targetEventTypes !== undefined) {
642
const targetEventTypesSet = getDOMTargetEventTypesSet(targetEventTypes);
643
if (targetEventTypesSet.has(listeningName)) {
665
- eventResponderInstances.push(eventComponentInstance);
666
- if (eventComponentResponders !== null) {
667
- eventComponentResponders.add(responder);
644
+ if (hookComponentResponderValidation !== null) {
645
+ hookComponentResponderValidation.add(responder);
646
}
669
- }
670
- }
671
-}
672
-
673
-function getTargetEventResponderInstances(
674
- listeningName: string,
675
- targetFiber: null | Fiber,
676
-): Array<ReactDOMEventComponentInstance> {
677
- // We use this to know if we should check add hooks. If there are
678
- // no event targets, then we don't add the hook forms.
679
- const eventComponentResponders = new Set();
680
- const eventResponderInstances = [];
681
- let node = targetFiber;
682
- while (node !== null) {
683
- // Traverse up the fiber tree till we find event component fibers.
684
- const tag = node.tag;
685
- const dependencies = node.dependencies;
686
- if (tag === EventComponent) {
687
- const eventComponentInstance = node.stateNode;
688
- // Switch to the current fiber tree
689
- node = eventComponentInstance.currentFiber;
690
- storeTargetEventResponderInstance(
691
- listeningName,
692
- eventComponentInstance,
693
- eventResponderInstances,
694
- eventComponentResponders,
695
- );
696
- } else if (tag === FunctionComponent && dependencies !== null) {
697
- const events = dependencies.events;
698
- if (events !== null) {
699
- for (let i = 0; i < events.length; i++) {
700
- const eventComponentInstance = events[i];
701
- if (eventComponentResponders.has(eventComponentInstance.responder)) {
702
- storeTargetEventResponderInstance(
703
- listeningName,
704
- eventComponentInstance,
705
- eventResponderInstances,
706
- null,
707
- );
708
- }
647
+ const {isHook, props, state} = eventComponentInstance;
648
+ const onEvent = responder.onEvent;
649
+ if (onEvent !== undefined) {
650
+ if (
651
+ shouldSkipEventComponent(
652
+ eventComponentInstance,
653
+ ((responder: any): ReactDOMEventResponder),
654
+ propagatedEventResponders,
655
+ isHook,
656
+ )
657
+ ) {
658
+ return;
659
+ }
660
+ currentInstance = eventComponentInstance;
661
+ currentlyInHook = isHook;
662
+ onEvent(responderEvent, eventResponderContext, props, state);
663
+ if (!isHook) {
664
+ checkForLocalPropagationContinuation(
665
+ responder,
666
+ ((propagatedEventResponders: any): Set<ReactDOMEventResponder>),
667
+ );
668
}
669
}
670
}
712
- node = node.return;
713
- }
714
- return eventResponderInstances;
715
-}
716
-
717
-function getRootEventResponderInstances(
718
- listeningName: string,
719
-): Array<ReactDOMEventComponentInstance> {
720
- const eventResponderInstances = [];
721
- const rootEventInstances = rootEventTypesToEventComponentInstances.get(
722
- listeningName,
723
- );
724
- if (rootEventInstances !== undefined) {
725
- const rootEventComponentInstances = Array.from(rootEventInstances);
726
-
727
- for (let i = 0; i < rootEventComponentInstances.length; i++) {
728
- const rootEventComponentInstance = rootEventComponentInstances[i];
729
- eventResponderInstances.push(rootEventComponentInstance);
730
- }
671
}
732
- return eventResponderInstances;
672
}
673
674
function shouldSkipEventComponent(
@@ -778,10 +717,6 @@ function traverseAndHandleEventResponderInstances(
717
// - Bubble target phase
718
// - Root phase
719
781
- const targetEventResponderInstances = getTargetEventResponderInstances(
782
- listeningName,
783
- targetFiber,
784
- );
720
const responderEvent = createDOMResponderEvent(
721
((topLevelType: any): string),
722
nativeEvent,
@@ -790,57 +725,70 @@ function traverseAndHandleEventResponderInstances(
725
isPassiveSupported,
726
);
727
const propagatedEventResponders: Set<ReactDOMEventResponder> = new Set();
793
- let length = targetEventResponderInstances.length;
794
- let i;
728
+
729
+ // We use this to know if we should check add hooks. If there are
730
+ // no event targets, then we don't add the hook forms.
731
+ const hookComponentResponderValidation = new Set();
732
733
// Bubbled event phases have the notion of local propagation.
734
// This means that the propgation chain can be stopped part of the the way
798
- // through processing event component instances. The major difference to other
799
- // events systems is that the stopping of propagation is localized to a single
800
- // phase, rather than both phases.
801
- if (length > 0) {
802
- // Bubble target phase
803
- for (i = 0; i < length; i++) {
804
- const targetEventResponderInstance = targetEventResponderInstances[i];
805
- const {isHook, props, responder, state} = targetEventResponderInstance;
806
- const eventListener = responder.onEvent;
807
- if (eventListener !== undefined) {
808
- if (
809
- shouldSkipEventComponent(
810
- targetEventResponderInstance,
811
- ((responder: any): ReactDOMEventResponder),
812
- propagatedEventResponders,
813
- isHook,
814
- )
815
- ) {
816
- continue;
817
- }
818
- currentInstance = targetEventResponderInstance;
819
- currentlyInHook = isHook;
820
- eventListener(responderEvent, eventResponderContext, props, state);
821
- if (!isHook) {
822
- checkForLocalPropagationContinuation(
823
- responder,
824
- propagatedEventResponders,
825
- );
735
+ // through processing event component instances.
736
+ let node = targetFiber;
737
+ while (node !== null) {
738
+ const {dependencies, stateNode, tag} = node;
739
+ if (tag === HostComponent) {
740
+ responderEvent.currentTarget = stateNode;
741
+ } else if (tag === EventComponent) {
742
+ const eventComponentInstance = stateNode;
743
+ // Switch to the current fiber tree
744
+ node = eventComponentInstance.currentFiber;
745
+ handleTargetEventResponderInstance(
746
+ listeningName,
747
+ responderEvent,
748
+ eventComponentInstance,
749
+ hookComponentResponderValidation,
750
+ propagatedEventResponders,
751
+ );
752
+ } else if (tag === FunctionComponent && dependencies !== null) {
753
+ const events = dependencies.events;
754
+ if (events !== null) {
755
+ for (let i = 0; i < events.length; i++) {
756
+ const eventComponentInstance = events[i];
757
+ if (
758
+ hookComponentResponderValidation.has(
759
+ eventComponentInstance.responder,
760
+ )
761
+ ) {
762
+ handleTargetEventResponderInstance(
763
+ listeningName,
764
+ responderEvent,
765
+ eventComponentInstance,
766
+ null,
767
+ null,
768
+ );
769
+ }
770
}
771
}
772
}
773
+ node = node.return;
774
}
775
+ // Reset currentTarget to be null
776
+ responderEvent.currentTarget = null;
777
// Root phase
831
- const rootEventResponderInstances = getRootEventResponderInstances(
778
+ const rootEventInstances = rootEventTypesToEventComponentInstances.get(
779
listeningName,
780
);
834
- length = rootEventResponderInstances.length;
835
- if (length > 0) {
836
- for (i = 0; i < length; i++) {
837
- const rootEventResponderInstance = rootEventResponderInstances[i];
838
- const {isHook, props, responder, state} = rootEventResponderInstance;
839
- const eventListener = responder.onRootEvent;
840
- if (eventListener !== undefined) {
781
+ if (rootEventInstances !== undefined) {
782
+ const rootEventComponentInstances = Array.from(rootEventInstances);
783
+
784
+ for (let i = 0; i < rootEventComponentInstances.length; i++) {
785
+ const rootEventComponentInstance = rootEventComponentInstances[i];
786
+ const {isHook, props, responder, state} = rootEventComponentInstance;
787
+ const onRootEvent = responder.onRootEvent;
788
+ if (onRootEvent !== undefined) {
789
if (
790
shouldSkipEventComponent(
843
- rootEventResponderInstance,
791
+ rootEventComponentInstance,
792
responder,
793
null,
794
isHook,
@@ -848,9 +796,9 @@ function traverseAndHandleEventResponderInstances(
796
) {
797
continue;
798
}
851
- currentInstance = rootEventResponderInstance;
799
+ currentInstance = rootEventComponentInstance;
800
currentlyInHook = isHook;
853
- eventListener(responderEvent, eventResponderContext, props, state);
801
+ onRootEvent(responderEvent, eventResponderContext, props, state);
802
}
803
}
804
}
packages/react-events/src/dom/Focus.js
+4
-2
@@ -207,8 +207,10 @@ function handleRootPointerEvent(
207
208
// Focus should stop being visible if a pointer is used on the element
209
// after it was focused using a keyboard.
210
+ const focusTarget = state.focusTarget;
211
if (
211
- state.focusTarget === context.getEventCurrentTarget(event) &&
212
+ focusTarget !== null &&
213
+ context.isTargetWithinNode(event.target, focusTarget) &&
214
(type === 'mousedown' || type === 'touchstart' || type === 'pointerdown')
215
) {
216
dispatchFocusVisibleOutEvent(context, props, state);
@@ -253,7 +255,7 @@ const FocusResponder: ReactDOMEventResponder = {
255
if (!state.isFocused) {
256
// Limit focus events to the direct child of the event component.
257
// Browser focus is not expected to bubble.
256
- state.focusTarget = context.getEventCurrentTarget(event);
258
+ state.focusTarget = event.currentTarget;
259
if (state.focusTarget === target) {
260
state.isFocused = true;
261
state.isLocalFocusVisible = isGlobalFocusVisible;
packages/react-events/src/dom/Hover.js
+1
-1
@@ -321,7 +321,7 @@ const HoverResponder: ReactDOMEventResponder = {
321
if (isEmulatedMouseEvent(event, state)) {
322
return;
323
}
324
- state.hoverTarget = context.getEventCurrentTarget(event);
324
+ state.hoverTarget = event.currentTarget;
325
state.ignoreEmulatedMouseEvents = true;
326
dispatchHoverStartEvents(event, context, props, state);
327
}
packages/react-events/src/dom/Press.js
+24
-13
@@ -57,7 +57,7 @@ type PressState = {
57
isPressWithinResponderRegion: boolean,
58
longPressTimeout: null | number,
59
pointerType: PointerType,
60
- pressTarget: null | Element,
60
+ pressTarget: null | Element | Document,
61
pressEndTimeout: null | number,
62
pressStartTimeout: null | number,
63
responderRegionOnActivation: null | $ReadOnly<{|
@@ -619,6 +619,11 @@ function handleStopPropagation(
619
}
620
}
621
622
+function targetIsDocument(target: null | Node): boolean {
623
+ // When target is null, it is the root
624
+ return target === null || target.nodeType === 9;
625
+}
626
+
627
const PressResponder: ReactDOMEventResponder = {
628
displayName: 'Press',
629
targetEventTypes,
@@ -691,7 +696,7 @@ const PressResponder: ReactDOMEventResponder = {
696
// We set these here, before the button check so we have this
697
// data around for handling of the context menu
698
state.pointerType = pointerType;
694
- state.pressTarget = context.getEventCurrentTarget(event);
699
+ const pressTarget = (state.pressTarget = event.currentTarget);
700
if (isPointerEvent) {
701
state.activePointerId = pointerId;
702
} else if (isTouchEvent) {
@@ -712,12 +717,14 @@ const PressResponder: ReactDOMEventResponder = {
717
) {
718
return;
719
}
715
-
716
- state.responderRegionOnActivation = calculateResponderRegion(
717
- context,
718
- state.pressTarget,
719
- props,
720
- );
720
+ // Exclude document targets
721
+ if (!targetIsDocument(pressTarget)) {
722
+ state.responderRegionOnActivation = calculateResponderRegion(
723
+ context,
724
+ ((pressTarget: any): Element),
725
+ props,
726
+ );
727
+ }
728
state.responderRegionOnDeactivation = null;
729
state.isPressWithinResponderRegion = true;
730
dispatchPressStartEvents(event, context, props, state);
@@ -824,11 +831,13 @@ const PressResponder: ReactDOMEventResponder = {
831
}
832
state.touchEvent = touchEvent;
833
}
834
+ const pressTarget = state.pressTarget;
835
836
if (
829
- state.pressTarget !== null &&
837
+ pressTarget !== null &&
838
+ !targetIsDocument(pressTarget) &&
839
(pointerType !== 'mouse' ||
831
- !context.isTargetWithinNode(target, state.pressTarget))
840
+ !context.isTargetWithinNode(target, pressTarget))
841
) {
842
// Calculate the responder region we use for deactivation, as the
843
// element dimensions may have changed since activation.
@@ -934,14 +943,16 @@ const PressResponder: ReactDOMEventResponder = {
943
}
944
945
const wasLongPressed = state.isLongPressed;
946
+ const pressTarget = state.pressTarget;
947
dispatchPressEndEvents(event, context, props, state);
948
939
- if (state.pressTarget !== null && props.onPress) {
949
+ if (pressTarget !== null && props.onPress) {
950
if (
951
!isKeyboardEvent &&
942
- state.pressTarget !== null &&
952
+ pressTarget !== null &&
953
+ !targetIsDocument(pressTarget) &&
954
(pointerType !== 'mouse' ||
944
- !context.isTargetWithinNode(target, state.pressTarget))
955
+ !context.isTargetWithinNode(target, pressTarget))
956
) {
957
// If the event target isn't within the press target, check if we're still
958
// within the responder region. The region may have changed if the
packages/react-events/src/rn/Press.js
+1
-3
@@ -537,9 +537,7 @@ const PressResponder: ReactNativeEventResponder = {
537
if (type === 'topTouchStart') {
538
if (!state.isPressed) {
539
state.pointerType = 'touch';
540
- const pressTarget = (state.pressTarget = context.getEventCurrentTarget(
541
- event,
542
- ));
540
+ const pressTarget = (state.pressTarget = event.currentTarget);
541
542
const touchEvent = getTouchFromPressEvent(nativeEvent);
543
if (touchEvent === null) {
packages/react-native-renderer/src/ReactFabricEventResponderSystem.js
+101
-121
@@ -7,7 +7,11 @@
7
* @flow
8
*/
9
10
-import {EventComponent, HostComponent} from 'shared/ReactWorkTags';
10
+import {
11
+ EventComponent,
12
+ HostComponent,
13
+ FunctionComponent,
14
+} from 'shared/ReactWorkTags';
15
import type {Fiber} from 'react-reconciler/src/ReactFiber';
16
import {
17
batchedEventUpdates,
@@ -192,31 +196,6 @@ const eventResponderContext: ReactNativeResponderContext = {
196
}
197
return false;
198
},
195
- getEventCurrentTarget(
196
- event: ReactNativeResponderEvent,
197
- ): ReactNativeEventTarget {
198
- validateResponderContext();
199
- const target = event.target;
200
- let fiber = getFiberFromTarget(target);
201
- let hostComponent = target;
202
- const currentResponder = ((currentInstance: any): ReactNativeEventComponentInstance)
203
- .responder;
204
-
205
- while (fiber !== null) {
206
- const stateNode = fiber.stateNode;
207
- if (
208
- fiber.tag === EventComponent &&
209
- (stateNode === null || stateNode.responder === currentResponder)
210
- ) {
211
- break;
212
- }
213
- if (fiber.tag === HostComponent) {
214
- hostComponent = fiber.stateNode;
215
- }
216
- fiber = fiber.return;
217
- }
218
- return ((hostComponent: any): ReactNativeEventTarget);
219
- },
199
getTargetBoundingRect(
200
target: ReactNativeEventTarget,
201
callback: ({
@@ -320,7 +299,7 @@ function getFiberFromTarget(
299
if (target === null) {
300
return null;
301
}
323
- return ((target.canonical._internalInstanceHandle: any): Fiber);
302
+ return ((target.canonical._internalInstanceHandle: any): Fiber) || null;
303
}
304
305
function processTimers(
@@ -355,15 +334,12 @@ function createFabricResponderEvent(
334
nativeEvent: ReactFaricEvent,
335
target: null | ReactNativeEventTarget,
336
): ReactNativeResponderEvent {
358
- const responderEvent = {
337
+ return {
338
+ currentTarget: target,
339
nativeEvent,
340
target,
341
type: topLevelType,
342
};
363
- if (__DEV__) {
364
- Object.freeze(responderEvent);
365
- }
366
- return responderEvent;
343
}
344
345
function validateResponderContext(): void {
@@ -490,35 +466,6 @@ function getFabricTargetEventTypesSet(
466
return cachedSet;
467
}
468
493
-// TODO this function is almost an exact copy of the DOM version, we should
494
-// somehow share the logic
495
-function getTargetEventResponderInstances(
496
- topLevelType: ReactNativeEventResponderEventType,
497
- targetFiber: null | Fiber,
498
-): Array<ReactNativeEventComponentInstance> {
499
- const eventResponderInstances = [];
500
- let node = targetFiber;
501
- while (node !== null) {
502
- // Traverse up the fiber tree till we find event component fibers.
503
- if (node.tag === EventComponent) {
504
- const eventComponentInstance = node.stateNode;
505
- const responder = eventComponentInstance.responder;
506
- const targetEventTypes = responder.targetEventTypes;
507
- // Validate the target event type exists on the responder
508
- if (targetEventTypes !== undefined) {
509
- const targetEventTypesSet = getFabricTargetEventTypesSet(
510
- targetEventTypes,
511
- );
512
- if (targetEventTypesSet.has(topLevelType)) {
513
- eventResponderInstances.push(eventComponentInstance);
514
- }
515
- }
516
- }
517
- node = node.return;
518
- }
519
- return eventResponderInstances;
520
-}
521
-
469
// TODO this function is almost an exact copy of the DOM version, we should
470
// somehow share the logic
471
function shouldSkipEventComponent(
@@ -551,22 +498,47 @@ function checkForLocalPropagationContinuation(
498
499
// TODO this function is almost an exact copy of the DOM version, we should
500
// somehow share the logic
554
-function getRootEventResponderInstances(
555
- topLevelType: string,
556
-): Array<ReactNativeEventComponentInstance> {
557
- const eventResponderInstances = [];
558
- const rootEventInstances = rootEventTypesToEventComponentInstances.get(
559
- topLevelType,
560
- );
561
- if (rootEventInstances !== undefined) {
562
- const rootEventComponentInstances = Array.from(rootEventInstances);
563
-
564
- for (let i = 0; i < rootEventComponentInstances.length; i++) {
565
- const rootEventComponentInstance = rootEventComponentInstances[i];
566
- eventResponderInstances.push(rootEventComponentInstance);
501
+function handleTargetEventResponderInstance(
502
+ topLevelType: ReactNativeEventResponderEventType,
503
+ responderEvent: ReactNativeResponderEvent,
504
+ eventComponentInstance: ReactNativeEventComponentInstance,
505
+ hookComponentResponderValidation: null | Set<ReactNativeEventResponder>,
506
+ propagatedEventResponders: null | Set<ReactNativeEventResponder>,
507
+): void {
508
+ const responder = eventComponentInstance.responder;
509
+ const targetEventTypes = responder.targetEventTypes;
510
+ // Validate the target event type exists on the responder
511
+ if (targetEventTypes !== undefined) {
512
+ const targetEventTypesSet = getFabricTargetEventTypesSet(targetEventTypes);
513
+ if (targetEventTypesSet.has(topLevelType)) {
514
+ if (hookComponentResponderValidation !== null) {
515
+ hookComponentResponderValidation.add(responder);
516
+ }
517
+ const {isHook, props, state} = eventComponentInstance;
518
+ const eventListener = responder.onEvent;
519
+ if (eventListener !== undefined) {
520
+ if (
521
+ shouldSkipEventComponent(
522
+ eventComponentInstance,
523
+ ((responder: any): ReactNativeEventResponder),
524
+ propagatedEventResponders,
525
+ isHook,
526
+ )
527
+ ) {
528
+ return;
529
+ }
530
+ currentInstance = eventComponentInstance;
531
+ currentlyInHook = isHook;
532
+ eventListener(responderEvent, eventResponderContext, props, state);
533
+ if (!isHook) {
534
+ checkForLocalPropagationContinuation(
535
+ responder,
536
+ ((propagatedEventResponders: any): Set<ReactNativeEventResponder>),
537
+ );
538
+ }
539
+ }
540
}
541
}
569
- return eventResponderInstances;
542
}
543
544
// TODO this function is almost an exact copy of the DOM version, we should
@@ -580,10 +552,6 @@ function traverseAndHandleEventResponderInstances(
552
// - Bubble target phase
553
// - Root phase
554
583
- const targetEventResponderInstances = getTargetEventResponderInstances(
584
- topLevelType,
585
- targetFiber,
586
- );
555
const responderEvent = createFabricResponderEvent(
556
topLevelType,
557
nativeEvent,
@@ -592,58 +560,70 @@ function traverseAndHandleEventResponderInstances(
560
: null,
561
);
562
const propagatedEventResponders: Set<ReactNativeEventResponder> = new Set();
595
- let length = targetEventResponderInstances.length;
596
- let i;
563
+
564
+ // We use this to know if we should check add hooks. If there are
565
+ // no event targets, then we don't add the hook forms.
566
+ const hookComponentResponderValidation = new Set();
567
568
// Bubbled event phases have the notion of local propagation.
569
// This means that the propgation chain can be stopped part of the the way
600
- // through processing event component instances. The major difference to other
601
- // events systems is that the stopping of propagation is localized to a single
602
- // phase, rather than both phases.
603
- if (length > 0) {
604
- // Bubble target phase
605
- for (i = 0; i < length; i++) {
606
- const targetEventResponderInstance = targetEventResponderInstances[i];
607
- const {isHook, responder, props, state} = targetEventResponderInstance;
608
- const eventListener = ((responder: any): ReactNativeEventResponder)
609
- .onEvent;
610
- if (eventListener !== undefined) {
611
- if (
612
- shouldSkipEventComponent(
613
- targetEventResponderInstance,
614
- ((responder: any): ReactNativeEventResponder),
615
- propagatedEventResponders,
616
- isHook,
617
- )
618
- ) {
619
- continue;
620
- }
621
- currentInstance = targetEventResponderInstance;
622
- currentlyInHook = isHook;
623
- eventListener(responderEvent, eventResponderContext, props, state);
624
- if (!isHook) {
625
- checkForLocalPropagationContinuation(
626
- ((responder: any): ReactNativeEventResponder),
627
- propagatedEventResponders,
628
- );
570
+ // through processing event component instances.
571
+ let node = targetFiber;
572
+ while (node !== null) {
573
+ const {dependencies, stateNode, tag} = node;
574
+ if (tag === HostComponent) {
575
+ responderEvent.currentTarget = stateNode;
576
+ } else if (tag === EventComponent) {
577
+ const eventComponentInstance = stateNode;
578
+ // Switch to the current fiber tree
579
+ node = eventComponentInstance.currentFiber;
580
+ handleTargetEventResponderInstance(
581
+ topLevelType,
582
+ responderEvent,
583
+ eventComponentInstance,
584
+ hookComponentResponderValidation,
585
+ propagatedEventResponders,
586
+ );
587
+ } else if (tag === FunctionComponent && dependencies !== null) {
588
+ const events = dependencies.events;
589
+ if (events !== null) {
590
+ for (let i = 0; i < events.length; i++) {
591
+ const eventComponentInstance = events[i];
592
+ if (
593
+ hookComponentResponderValidation.has(
594
+ eventComponentInstance.responder,
595
+ )
596
+ ) {
597
+ handleTargetEventResponderInstance(
598
+ topLevelType,
599
+ responderEvent,
600
+ eventComponentInstance,
601
+ null,
602
+ null,
603
+ );
604
+ }
605
}
606
}
607
}
608
+ node = node.return;
609
}
610
+ // Reset currentTarget to be null
611
+ responderEvent.currentTarget = null;
612
// Root phase
634
- const rootEventResponderInstances = getRootEventResponderInstances(
613
+ const rootEventInstances = rootEventTypesToEventComponentInstances.get(
614
topLevelType,
615
);
637
- length = rootEventResponderInstances.length;
638
- if (length > 0) {
639
- for (i = 0; i < length; i++) {
640
- const rootEventResponderInstance = rootEventResponderInstances[i];
641
- const {isHook, props, responder, state} = rootEventResponderInstance;
642
- const eventListener = responder.onRootEvent;
643
- if (eventListener !== undefined) {
616
+ if (rootEventInstances !== undefined) {
617
+ const rootEventComponentInstances = Array.from(rootEventInstances);
618
+
619
+ for (let i = 0; i < rootEventComponentInstances.length; i++) {
620
+ const rootEventComponentInstance = rootEventComponentInstances[i];
621
+ const {isHook, props, responder, state} = rootEventComponentInstance;
622
+ const onRootEvent = responder.onRootEvent;
623
+ if (onRootEvent !== undefined) {
624
if (
625
shouldSkipEventComponent(
646
- rootEventResponderInstance,
626
+ rootEventComponentInstance,
627
responder,
628
null,
629
isHook,
@@ -651,9 +631,9 @@ function traverseAndHandleEventResponderInstances(
631
) {
632
continue;
633
}
654
- currentInstance = rootEventResponderInstance;
634
+ currentInstance = rootEventComponentInstance;
635
currentlyInHook = isHook;
656
- eventListener(responderEvent, eventResponderContext, props, state);
636
+ onRootEvent(responderEvent, eventResponderContext, props, state);
637
}
638
}
639
}
packages/react-native-renderer/src/ReactNativeTypes.js
+1
-3
@@ -199,6 +199,7 @@ export type ReactFaricEvent = {
199
};
200
201
export type ReactNativeResponderEvent = {
202
+ currentTarget: null | ReactNativeEventTarget,
203
nativeEvent: ReactFaricEvent,
204
target: null | ReactNativeEventTarget,
205
type: ReactNativeEventResponderEventType,
@@ -229,9 +230,6 @@ export type ReactNativeResponderContext = {
230
removeRootEventTypes: (
231
rootEventTypes: Array<ReactNativeEventResponderEventType>,
232
) => void,
232
- getEventCurrentTarget(
233
- event: ReactNativeResponderEvent,
234
- ): ReactNativeEventTarget,
233
setTimeout: (func: () => void, timeout: number) => number,
234
clearTimeout: (timerId: number) => void,
235
getTimeStamp: () => number,
packages/shared/ReactDOMTypes.js
+1
-1
@@ -28,6 +28,7 @@ export type PointerType =
28
| 'trackpad';
29
30
export type ReactDOMResponderEvent = {
31
+ currentTarget: null | Element | Document,
32
nativeEvent: AnyNativeEvent,
33
passive: boolean,
34
passiveSupported: boolean,
@@ -75,7 +76,6 @@ export type ReactDOMResponderContext = {
76
getFocusableElementsInScope(): Array<HTMLElement>,
77
getActiveDocument(): Document,
78
objectAssign: Function,
78
- getEventCurrentTarget(event: ReactDOMResponderEvent): Element,
79
getTimeStamp: () => number,
80
isTargetWithinHostComponent: (
81
target: Element | Document,