react-native-tvos
Version:
A framework for building native apps using React
84 lines (74 loc) • 3.01 kB
JavaScript
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import type EventTarget from '../../webapis/dom/events/EventTarget';
import {
customBubblingEventTypes,
customDirectEventTypes,
} from '../../../../Libraries/Renderer/shims/ReactNativeViewConfigRegistry';
import {setEventInitTimeStamp} from '../../webapis/dom/events/internals/EventInternals';
import {dispatchTrustedEvent} from '../../webapis/dom/events/internals/EventTargetInternals';
import LegacySyntheticEvent from './LegacySyntheticEvent';
import {topLevelTypeToEventType} from './ReactNativeEventTypeMapping';
import {
processResponderEvent,
rethrowCaughtError,
} from './ReactNativeResponder';
/**
* Dispatches a native event through the EventTarget-based dispatch system.
* This handles:
* 1. Responder negotiation (touch handling, grant/release lifecycle)
* 2. Normal event dispatch via dispatchTrustedEvent (capture/bubble phases)
*
* Called from the React renderer's dispatchEvent when
* enableNativeEventTargetEventDispatching is enabled.
*/
export default function dispatchNativeEvent(
target: EventTarget,
type: string,
payload: {[string]: unknown},
): void {
// Process responder events before normal event dispatch.
processResponderEvent(type, target, payload);
// Normal EventTarget dispatch
const bubbleConfig = customBubblingEventTypes[type];
const directConfig = customDirectEventTypes[type];
// Skip events that are not registered in the view config
if (bubbleConfig != null || directConfig != null) {
// Honor `skipBubbling` declared in the view config: when set, the bubble
// phase only fires on the target itself (matching the legacy renderer's
// behavior). The synthesized event reports `bubbles: false`, which causes
// the EventTarget bubble loop to short-circuit after dispatching to the
// target. Capture-phase listeners are unaffected.
const bubbles =
bubbleConfig != null &&
bubbleConfig.phasedRegistrationNames.skipBubbling !== true;
const eventType = topLevelTypeToEventType(type);
const options: {bubbles: boolean, cancelable: boolean} = {
bubbles,
cancelable: true,
};
// Preserve the native event timestamp for backwards compatibility.
const nativeTimestamp = payload.timeStamp ?? payload.timestamp;
if (typeof nativeTimestamp === 'number') {
setEventInitTimeStamp(options, nativeTimestamp);
}
const syntheticEvent = new LegacySyntheticEvent(
eventType,
options,
payload,
bubbleConfig ?? directConfig,
);
dispatchTrustedEvent(target, syntheticEvent);
}
// Rethrow the first error caught during responder lifecycle dispatch,
// after all dispatching is complete. This matches the old system's
// runEventsInBatch → rethrowCaughtError pattern.
rethrowCaughtError();
}