diff --git a/packages/react-dom/src/events/DOMEventResponderSystem.js b/packages/react-dom/src/events/DOMEventResponderSystem.js index a1d00e83b3..9e4d66cafd 100644 --- a/packages/react-dom/src/events/DOMEventResponderSystem.js +++ b/packages/react-dom/src/events/DOMEventResponderSystem.js @@ -372,29 +372,6 @@ const eventResponderContext: ReactDOMResponderContext = { }, getActiveDocument, objectAssign: Object.assign, - getEventCurrentTarget(event: ReactDOMResponderEvent): Element { - validateResponderContext(); - const target = event.target; - let fiber = getClosestInstanceFromNode(target); - let hostComponent = target; - const currentResponder = ((currentInstance: any): ReactDOMEventComponentInstance) - .responder; - - while (fiber !== null) { - const stateNode = fiber.stateNode; - if ( - fiber.tag === EventComponent && - (stateNode === null || stateNode.responder === currentResponder) - ) { - break; - } - if (fiber.tag === HostComponent) { - hostComponent = fiber.stateNode; - } - fiber = fiber.return; - } - return ((hostComponent: any): Element); - }, getTimeStamp(): number { validateResponderContext(); return currentTimeStamp; @@ -553,6 +530,7 @@ function createDOMResponderEvent( } return { + currentTarget: nativeEventTarget, nativeEvent: nativeEvent, passive, passiveSupported, @@ -650,11 +628,12 @@ function getDOMTargetEventTypesSet( return cachedSet; } -function storeTargetEventResponderInstance( +function handleTargetEventResponderInstance( listeningName: string, + responderEvent: ReactDOMResponderEvent, eventComponentInstance: ReactDOMEventComponentInstance, - eventResponderInstances: Array, - eventComponentResponders: null | Set, + hookComponentResponderValidation: null | Set, + propagatedEventResponders: null | Set, ): void { const responder = eventComponentInstance.responder; const targetEventTypes = responder.targetEventTypes; @@ -662,74 +641,34 @@ function storeTargetEventResponderInstance( if (targetEventTypes !== undefined) { const targetEventTypesSet = getDOMTargetEventTypesSet(targetEventTypes); if (targetEventTypesSet.has(listeningName)) { - eventResponderInstances.push(eventComponentInstance); - if (eventComponentResponders !== null) { - eventComponentResponders.add(responder); + if (hookComponentResponderValidation !== null) { + hookComponentResponderValidation.add(responder); } - } - } -} - -function getTargetEventResponderInstances( - listeningName: string, - targetFiber: null | Fiber, -): Array { - // We use this to know if we should check add hooks. If there are - // no event targets, then we don't add the hook forms. - const eventComponentResponders = new Set(); - const eventResponderInstances = []; - let node = targetFiber; - while (node !== null) { - // Traverse up the fiber tree till we find event component fibers. - const tag = node.tag; - const dependencies = node.dependencies; - if (tag === EventComponent) { - const eventComponentInstance = node.stateNode; - // Switch to the current fiber tree - node = eventComponentInstance.currentFiber; - storeTargetEventResponderInstance( - listeningName, - eventComponentInstance, - eventResponderInstances, - eventComponentResponders, - ); - } else if (tag === FunctionComponent && dependencies !== null) { - const events = dependencies.events; - if (events !== null) { - for (let i = 0; i < events.length; i++) { - const eventComponentInstance = events[i]; - if (eventComponentResponders.has(eventComponentInstance.responder)) { - storeTargetEventResponderInstance( - listeningName, - eventComponentInstance, - eventResponderInstances, - null, - ); - } + const {isHook, props, state} = eventComponentInstance; + const onEvent = responder.onEvent; + if (onEvent !== undefined) { + if ( + shouldSkipEventComponent( + eventComponentInstance, + ((responder: any): ReactDOMEventResponder), + propagatedEventResponders, + isHook, + ) + ) { + return; + } + currentInstance = eventComponentInstance; + currentlyInHook = isHook; + onEvent(responderEvent, eventResponderContext, props, state); + if (!isHook) { + checkForLocalPropagationContinuation( + responder, + ((propagatedEventResponders: any): Set), + ); } } } - node = node.return; } - return eventResponderInstances; -} - -function getRootEventResponderInstances( - listeningName: string, -): Array { - const eventResponderInstances = []; - const rootEventInstances = rootEventTypesToEventComponentInstances.get( - listeningName, - ); - if (rootEventInstances !== undefined) { - const rootEventComponentInstances = Array.from(rootEventInstances); - - for (let i = 0; i < rootEventComponentInstances.length; i++) { - const rootEventComponentInstance = rootEventComponentInstances[i]; - eventResponderInstances.push(rootEventComponentInstance); - } - } - return eventResponderInstances; } function shouldSkipEventComponent( @@ -778,10 +717,6 @@ function traverseAndHandleEventResponderInstances( // - Bubble target phase // - Root phase - const targetEventResponderInstances = getTargetEventResponderInstances( - listeningName, - targetFiber, - ); const responderEvent = createDOMResponderEvent( ((topLevelType: any): string), nativeEvent, @@ -790,57 +725,70 @@ function traverseAndHandleEventResponderInstances( isPassiveSupported, ); const propagatedEventResponders: Set = new Set(); - let length = targetEventResponderInstances.length; - let i; + + // We use this to know if we should check add hooks. If there are + // no event targets, then we don't add the hook forms. + const hookComponentResponderValidation = new Set(); // Bubbled event phases have the notion of local propagation. // This means that the propgation chain can be stopped part of the the way - // through processing event component instances. The major difference to other - // events systems is that the stopping of propagation is localized to a single - // phase, rather than both phases. - if (length > 0) { - // Bubble target phase - for (i = 0; i < length; i++) { - const targetEventResponderInstance = targetEventResponderInstances[i]; - const {isHook, props, responder, state} = targetEventResponderInstance; - const eventListener = responder.onEvent; - if (eventListener !== undefined) { - if ( - shouldSkipEventComponent( - targetEventResponderInstance, - ((responder: any): ReactDOMEventResponder), - propagatedEventResponders, - isHook, - ) - ) { - continue; - } - currentInstance = targetEventResponderInstance; - currentlyInHook = isHook; - eventListener(responderEvent, eventResponderContext, props, state); - if (!isHook) { - checkForLocalPropagationContinuation( - responder, - propagatedEventResponders, - ); + // through processing event component instances. + let node = targetFiber; + while (node !== null) { + const {dependencies, stateNode, tag} = node; + if (tag === HostComponent) { + responderEvent.currentTarget = stateNode; + } else if (tag === EventComponent) { + const eventComponentInstance = stateNode; + // Switch to the current fiber tree + node = eventComponentInstance.currentFiber; + handleTargetEventResponderInstance( + listeningName, + responderEvent, + eventComponentInstance, + hookComponentResponderValidation, + propagatedEventResponders, + ); + } else if (tag === FunctionComponent && dependencies !== null) { + const events = dependencies.events; + if (events !== null) { + for (let i = 0; i < events.length; i++) { + const eventComponentInstance = events[i]; + if ( + hookComponentResponderValidation.has( + eventComponentInstance.responder, + ) + ) { + handleTargetEventResponderInstance( + listeningName, + responderEvent, + eventComponentInstance, + null, + null, + ); + } } } } + node = node.return; } + // Reset currentTarget to be null + responderEvent.currentTarget = null; // Root phase - const rootEventResponderInstances = getRootEventResponderInstances( + const rootEventInstances = rootEventTypesToEventComponentInstances.get( listeningName, ); - length = rootEventResponderInstances.length; - if (length > 0) { - for (i = 0; i < length; i++) { - const rootEventResponderInstance = rootEventResponderInstances[i]; - const {isHook, props, responder, state} = rootEventResponderInstance; - const eventListener = responder.onRootEvent; - if (eventListener !== undefined) { + if (rootEventInstances !== undefined) { + const rootEventComponentInstances = Array.from(rootEventInstances); + + for (let i = 0; i < rootEventComponentInstances.length; i++) { + const rootEventComponentInstance = rootEventComponentInstances[i]; + const {isHook, props, responder, state} = rootEventComponentInstance; + const onRootEvent = responder.onRootEvent; + if (onRootEvent !== undefined) { if ( shouldSkipEventComponent( - rootEventResponderInstance, + rootEventComponentInstance, responder, null, isHook, @@ -848,9 +796,9 @@ function traverseAndHandleEventResponderInstances( ) { continue; } - currentInstance = rootEventResponderInstance; + currentInstance = rootEventComponentInstance; currentlyInHook = isHook; - eventListener(responderEvent, eventResponderContext, props, state); + onRootEvent(responderEvent, eventResponderContext, props, state); } } } diff --git a/packages/react-events/src/dom/Focus.js b/packages/react-events/src/dom/Focus.js index 676ac32518..32c4101b4e 100644 --- a/packages/react-events/src/dom/Focus.js +++ b/packages/react-events/src/dom/Focus.js @@ -207,8 +207,10 @@ function handleRootPointerEvent( // Focus should stop being visible if a pointer is used on the element // after it was focused using a keyboard. + const focusTarget = state.focusTarget; if ( - state.focusTarget === context.getEventCurrentTarget(event) && + focusTarget !== null && + context.isTargetWithinNode(event.target, focusTarget) && (type === 'mousedown' || type === 'touchstart' || type === 'pointerdown') ) { dispatchFocusVisibleOutEvent(context, props, state); @@ -253,7 +255,7 @@ const FocusResponder: ReactDOMEventResponder = { if (!state.isFocused) { // Limit focus events to the direct child of the event component. // Browser focus is not expected to bubble. - state.focusTarget = context.getEventCurrentTarget(event); + state.focusTarget = event.currentTarget; if (state.focusTarget === target) { state.isFocused = true; state.isLocalFocusVisible = isGlobalFocusVisible; diff --git a/packages/react-events/src/dom/Hover.js b/packages/react-events/src/dom/Hover.js index 50628dadc7..6f95de69bf 100644 --- a/packages/react-events/src/dom/Hover.js +++ b/packages/react-events/src/dom/Hover.js @@ -321,7 +321,7 @@ const HoverResponder: ReactDOMEventResponder = { if (isEmulatedMouseEvent(event, state)) { return; } - state.hoverTarget = context.getEventCurrentTarget(event); + state.hoverTarget = event.currentTarget; state.ignoreEmulatedMouseEvents = true; dispatchHoverStartEvents(event, context, props, state); } diff --git a/packages/react-events/src/dom/Press.js b/packages/react-events/src/dom/Press.js index 0636fdd3e0..5ead8e9a97 100644 --- a/packages/react-events/src/dom/Press.js +++ b/packages/react-events/src/dom/Press.js @@ -57,7 +57,7 @@ type PressState = { isPressWithinResponderRegion: boolean, longPressTimeout: null | number, pointerType: PointerType, - pressTarget: null | Element, + pressTarget: null | Element | Document, pressEndTimeout: null | number, pressStartTimeout: null | number, responderRegionOnActivation: null | $ReadOnly<{| @@ -619,6 +619,11 @@ function handleStopPropagation( } } +function targetIsDocument(target: null | Node): boolean { + // When target is null, it is the root + return target === null || target.nodeType === 9; +} + const PressResponder: ReactDOMEventResponder = { displayName: 'Press', targetEventTypes, @@ -691,7 +696,7 @@ const PressResponder: ReactDOMEventResponder = { // We set these here, before the button check so we have this // data around for handling of the context menu state.pointerType = pointerType; - state.pressTarget = context.getEventCurrentTarget(event); + const pressTarget = (state.pressTarget = event.currentTarget); if (isPointerEvent) { state.activePointerId = pointerId; } else if (isTouchEvent) { @@ -712,12 +717,14 @@ const PressResponder: ReactDOMEventResponder = { ) { return; } - - state.responderRegionOnActivation = calculateResponderRegion( - context, - state.pressTarget, - props, - ); + // Exclude document targets + if (!targetIsDocument(pressTarget)) { + state.responderRegionOnActivation = calculateResponderRegion( + context, + ((pressTarget: any): Element), + props, + ); + } state.responderRegionOnDeactivation = null; state.isPressWithinResponderRegion = true; dispatchPressStartEvents(event, context, props, state); @@ -824,11 +831,13 @@ const PressResponder: ReactDOMEventResponder = { } state.touchEvent = touchEvent; } + const pressTarget = state.pressTarget; if ( - state.pressTarget !== null && + pressTarget !== null && + !targetIsDocument(pressTarget) && (pointerType !== 'mouse' || - !context.isTargetWithinNode(target, state.pressTarget)) + !context.isTargetWithinNode(target, pressTarget)) ) { // Calculate the responder region we use for deactivation, as the // element dimensions may have changed since activation. @@ -934,14 +943,16 @@ const PressResponder: ReactDOMEventResponder = { } const wasLongPressed = state.isLongPressed; + const pressTarget = state.pressTarget; dispatchPressEndEvents(event, context, props, state); - if (state.pressTarget !== null && props.onPress) { + if (pressTarget !== null && props.onPress) { if ( !isKeyboardEvent && - state.pressTarget !== null && + pressTarget !== null && + !targetIsDocument(pressTarget) && (pointerType !== 'mouse' || - !context.isTargetWithinNode(target, state.pressTarget)) + !context.isTargetWithinNode(target, pressTarget)) ) { // If the event target isn't within the press target, check if we're still // within the responder region. The region may have changed if the diff --git a/packages/react-events/src/rn/Press.js b/packages/react-events/src/rn/Press.js index 89928a9646..278f3622ce 100644 --- a/packages/react-events/src/rn/Press.js +++ b/packages/react-events/src/rn/Press.js @@ -537,9 +537,7 @@ const PressResponder: ReactNativeEventResponder = { if (type === 'topTouchStart') { if (!state.isPressed) { state.pointerType = 'touch'; - const pressTarget = (state.pressTarget = context.getEventCurrentTarget( - event, - )); + const pressTarget = (state.pressTarget = event.currentTarget); const touchEvent = getTouchFromPressEvent(nativeEvent); if (touchEvent === null) { diff --git a/packages/react-native-renderer/src/ReactFabricEventResponderSystem.js b/packages/react-native-renderer/src/ReactFabricEventResponderSystem.js index fa0a9f4b87..b670d75f2a 100644 --- a/packages/react-native-renderer/src/ReactFabricEventResponderSystem.js +++ b/packages/react-native-renderer/src/ReactFabricEventResponderSystem.js @@ -7,7 +7,11 @@ * @flow */ -import {EventComponent, HostComponent} from 'shared/ReactWorkTags'; +import { + EventComponent, + HostComponent, + FunctionComponent, +} from 'shared/ReactWorkTags'; import type {Fiber} from 'react-reconciler/src/ReactFiber'; import { batchedEventUpdates, @@ -192,31 +196,6 @@ const eventResponderContext: ReactNativeResponderContext = { } return false; }, - getEventCurrentTarget( - event: ReactNativeResponderEvent, - ): ReactNativeEventTarget { - validateResponderContext(); - const target = event.target; - let fiber = getFiberFromTarget(target); - let hostComponent = target; - const currentResponder = ((currentInstance: any): ReactNativeEventComponentInstance) - .responder; - - while (fiber !== null) { - const stateNode = fiber.stateNode; - if ( - fiber.tag === EventComponent && - (stateNode === null || stateNode.responder === currentResponder) - ) { - break; - } - if (fiber.tag === HostComponent) { - hostComponent = fiber.stateNode; - } - fiber = fiber.return; - } - return ((hostComponent: any): ReactNativeEventTarget); - }, getTargetBoundingRect( target: ReactNativeEventTarget, callback: ({ @@ -320,7 +299,7 @@ function getFiberFromTarget( if (target === null) { return null; } - return ((target.canonical._internalInstanceHandle: any): Fiber); + return ((target.canonical._internalInstanceHandle: any): Fiber) || null; } function processTimers( @@ -355,15 +334,12 @@ function createFabricResponderEvent( nativeEvent: ReactFaricEvent, target: null | ReactNativeEventTarget, ): ReactNativeResponderEvent { - const responderEvent = { + return { + currentTarget: target, nativeEvent, target, type: topLevelType, }; - if (__DEV__) { - Object.freeze(responderEvent); - } - return responderEvent; } function validateResponderContext(): void { @@ -490,35 +466,6 @@ function getFabricTargetEventTypesSet( return cachedSet; } -// TODO this function is almost an exact copy of the DOM version, we should -// somehow share the logic -function getTargetEventResponderInstances( - topLevelType: ReactNativeEventResponderEventType, - targetFiber: null | Fiber, -): Array { - const eventResponderInstances = []; - let node = targetFiber; - while (node !== null) { - // Traverse up the fiber tree till we find event component fibers. - if (node.tag === EventComponent) { - const eventComponentInstance = node.stateNode; - const responder = eventComponentInstance.responder; - const targetEventTypes = responder.targetEventTypes; - // Validate the target event type exists on the responder - if (targetEventTypes !== undefined) { - const targetEventTypesSet = getFabricTargetEventTypesSet( - targetEventTypes, - ); - if (targetEventTypesSet.has(topLevelType)) { - eventResponderInstances.push(eventComponentInstance); - } - } - } - node = node.return; - } - return eventResponderInstances; -} - // TODO this function is almost an exact copy of the DOM version, we should // somehow share the logic function shouldSkipEventComponent( @@ -551,22 +498,47 @@ function checkForLocalPropagationContinuation( // TODO this function is almost an exact copy of the DOM version, we should // somehow share the logic -function getRootEventResponderInstances( - topLevelType: string, -): Array { - const eventResponderInstances = []; - const rootEventInstances = rootEventTypesToEventComponentInstances.get( - topLevelType, - ); - if (rootEventInstances !== undefined) { - const rootEventComponentInstances = Array.from(rootEventInstances); - - for (let i = 0; i < rootEventComponentInstances.length; i++) { - const rootEventComponentInstance = rootEventComponentInstances[i]; - eventResponderInstances.push(rootEventComponentInstance); +function handleTargetEventResponderInstance( + topLevelType: ReactNativeEventResponderEventType, + responderEvent: ReactNativeResponderEvent, + eventComponentInstance: ReactNativeEventComponentInstance, + hookComponentResponderValidation: null | Set, + propagatedEventResponders: null | Set, +): void { + const responder = eventComponentInstance.responder; + const targetEventTypes = responder.targetEventTypes; + // Validate the target event type exists on the responder + if (targetEventTypes !== undefined) { + const targetEventTypesSet = getFabricTargetEventTypesSet(targetEventTypes); + if (targetEventTypesSet.has(topLevelType)) { + if (hookComponentResponderValidation !== null) { + hookComponentResponderValidation.add(responder); + } + const {isHook, props, state} = eventComponentInstance; + const eventListener = responder.onEvent; + if (eventListener !== undefined) { + if ( + shouldSkipEventComponent( + eventComponentInstance, + ((responder: any): ReactNativeEventResponder), + propagatedEventResponders, + isHook, + ) + ) { + return; + } + currentInstance = eventComponentInstance; + currentlyInHook = isHook; + eventListener(responderEvent, eventResponderContext, props, state); + if (!isHook) { + checkForLocalPropagationContinuation( + responder, + ((propagatedEventResponders: any): Set), + ); + } + } } } - return eventResponderInstances; } // TODO this function is almost an exact copy of the DOM version, we should @@ -580,10 +552,6 @@ function traverseAndHandleEventResponderInstances( // - Bubble target phase // - Root phase - const targetEventResponderInstances = getTargetEventResponderInstances( - topLevelType, - targetFiber, - ); const responderEvent = createFabricResponderEvent( topLevelType, nativeEvent, @@ -592,58 +560,70 @@ function traverseAndHandleEventResponderInstances( : null, ); const propagatedEventResponders: Set = new Set(); - let length = targetEventResponderInstances.length; - let i; + + // We use this to know if we should check add hooks. If there are + // no event targets, then we don't add the hook forms. + const hookComponentResponderValidation = new Set(); // Bubbled event phases have the notion of local propagation. // This means that the propgation chain can be stopped part of the the way - // through processing event component instances. The major difference to other - // events systems is that the stopping of propagation is localized to a single - // phase, rather than both phases. - if (length > 0) { - // Bubble target phase - for (i = 0; i < length; i++) { - const targetEventResponderInstance = targetEventResponderInstances[i]; - const {isHook, responder, props, state} = targetEventResponderInstance; - const eventListener = ((responder: any): ReactNativeEventResponder) - .onEvent; - if (eventListener !== undefined) { - if ( - shouldSkipEventComponent( - targetEventResponderInstance, - ((responder: any): ReactNativeEventResponder), - propagatedEventResponders, - isHook, - ) - ) { - continue; - } - currentInstance = targetEventResponderInstance; - currentlyInHook = isHook; - eventListener(responderEvent, eventResponderContext, props, state); - if (!isHook) { - checkForLocalPropagationContinuation( - ((responder: any): ReactNativeEventResponder), - propagatedEventResponders, - ); + // through processing event component instances. + let node = targetFiber; + while (node !== null) { + const {dependencies, stateNode, tag} = node; + if (tag === HostComponent) { + responderEvent.currentTarget = stateNode; + } else if (tag === EventComponent) { + const eventComponentInstance = stateNode; + // Switch to the current fiber tree + node = eventComponentInstance.currentFiber; + handleTargetEventResponderInstance( + topLevelType, + responderEvent, + eventComponentInstance, + hookComponentResponderValidation, + propagatedEventResponders, + ); + } else if (tag === FunctionComponent && dependencies !== null) { + const events = dependencies.events; + if (events !== null) { + for (let i = 0; i < events.length; i++) { + const eventComponentInstance = events[i]; + if ( + hookComponentResponderValidation.has( + eventComponentInstance.responder, + ) + ) { + handleTargetEventResponderInstance( + topLevelType, + responderEvent, + eventComponentInstance, + null, + null, + ); + } } } } + node = node.return; } + // Reset currentTarget to be null + responderEvent.currentTarget = null; // Root phase - const rootEventResponderInstances = getRootEventResponderInstances( + const rootEventInstances = rootEventTypesToEventComponentInstances.get( topLevelType, ); - length = rootEventResponderInstances.length; - if (length > 0) { - for (i = 0; i < length; i++) { - const rootEventResponderInstance = rootEventResponderInstances[i]; - const {isHook, props, responder, state} = rootEventResponderInstance; - const eventListener = responder.onRootEvent; - if (eventListener !== undefined) { + if (rootEventInstances !== undefined) { + const rootEventComponentInstances = Array.from(rootEventInstances); + + for (let i = 0; i < rootEventComponentInstances.length; i++) { + const rootEventComponentInstance = rootEventComponentInstances[i]; + const {isHook, props, responder, state} = rootEventComponentInstance; + const onRootEvent = responder.onRootEvent; + if (onRootEvent !== undefined) { if ( shouldSkipEventComponent( - rootEventResponderInstance, + rootEventComponentInstance, responder, null, isHook, @@ -651,9 +631,9 @@ function traverseAndHandleEventResponderInstances( ) { continue; } - currentInstance = rootEventResponderInstance; + currentInstance = rootEventComponentInstance; currentlyInHook = isHook; - eventListener(responderEvent, eventResponderContext, props, state); + onRootEvent(responderEvent, eventResponderContext, props, state); } } } diff --git a/packages/react-native-renderer/src/ReactNativeTypes.js b/packages/react-native-renderer/src/ReactNativeTypes.js index 999fe94ced..923915f11f 100644 --- a/packages/react-native-renderer/src/ReactNativeTypes.js +++ b/packages/react-native-renderer/src/ReactNativeTypes.js @@ -199,6 +199,7 @@ export type ReactFaricEvent = { }; export type ReactNativeResponderEvent = { + currentTarget: null | ReactNativeEventTarget, nativeEvent: ReactFaricEvent, target: null | ReactNativeEventTarget, type: ReactNativeEventResponderEventType, @@ -229,9 +230,6 @@ export type ReactNativeResponderContext = { removeRootEventTypes: ( rootEventTypes: Array, ) => void, - getEventCurrentTarget( - event: ReactNativeResponderEvent, - ): ReactNativeEventTarget, setTimeout: (func: () => void, timeout: number) => number, clearTimeout: (timerId: number) => void, getTimeStamp: () => number, diff --git a/packages/shared/ReactDOMTypes.js b/packages/shared/ReactDOMTypes.js index 5f14ecf2b0..e13331ca2c 100644 --- a/packages/shared/ReactDOMTypes.js +++ b/packages/shared/ReactDOMTypes.js @@ -28,6 +28,7 @@ export type PointerType = | 'trackpad'; export type ReactDOMResponderEvent = { + currentTarget: null | Element | Document, nativeEvent: AnyNativeEvent, passive: boolean, passiveSupported: boolean, @@ -75,7 +76,6 @@ export type ReactDOMResponderContext = { getFocusableElementsInScope(): Array, getActiveDocument(): Document, objectAssign: Function, - getEventCurrentTarget(event: ReactDOMResponderEvent): Element, getTimeStamp: () => number, isTargetWithinHostComponent: ( target: Element | Document,