From a30d41a0b1f931a52a45a454dc9b8030a96beca1 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Thu, 23 Jan 2025 08:37:20 -0800 Subject: [PATCH] add isUnique option to Fantom.dispatchNativeEvent (#48801) Summary: changelog: [internal] Adds isUnique option to Fantom.dispatchNativeEvent. isUnique controls whether only the last event of the same type and target is dispatched to JavaScript or all events are queued and dispatched. Reviewed By: rubennorte Differential Revision: D68416157 --- .../src/__tests__/Fantom-itest.js | 56 ++++++++++++++++++- packages/react-native-fantom/src/index.js | 5 +- .../__snapshots__/public-api-test.js.snap | 3 +- .../src/private/specs/modules/NativeFantom.js | 1 + 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/packages/react-native-fantom/src/__tests__/Fantom-itest.js b/packages/react-native-fantom/src/__tests__/Fantom-itest.js index ab514a81da69..09669e63d434 100644 --- a/packages/react-native-fantom/src/__tests__/Fantom-itest.js +++ b/packages/react-native-fantom/src/__tests__/Fantom-itest.js @@ -22,7 +22,7 @@ import { runWorkLoop, } from '..'; import * as React from 'react'; -import {Text, TextInput, View} from 'react-native'; +import {ScrollView, Text, TextInput, View} from 'react-native'; import ensureInstance from 'react-native/src/private/utilities/ensureInstance'; import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement'; @@ -443,4 +443,58 @@ describe('Fantom', () => { const [entry] = onChange.mock.lastCall; expect(entry.text).toEqual('Hello World'); }); + + it('it batches events with isUnique option', () => { + const root = createRoot(); + let maybeNode; + const onScroll = jest.fn(); + + runTask(() => { + root.render( + { + onScroll(event.nativeEvent); + }} + ref={node => { + maybeNode = node; + }} + />, + ); + }); + + const element = ensureInstance(maybeNode, ReactNativeElement); + + runOnUIThread(() => { + dispatchNativeEvent(element, 'scroll', { + contentOffset: { + x: 0, + y: 1, + }, + }); + dispatchNativeEvent( + element, + 'scroll', + { + contentOffset: { + x: 0, + y: 2, + }, + }, + { + isUnique: true, + }, + ); + }); + + runWorkLoop(); + + expect(onScroll).toHaveBeenCalledTimes(1); + const [entry] = onScroll.mock.lastCall; + expect(entry.contentOffset).toEqual({ + x: 0, + y: 2, + }); + + root.destroy(); + }); }); diff --git a/packages/react-native-fantom/src/index.js b/packages/react-native-fantom/src/index.js index 2ade04c6b61c..2585a3bf5c97 100644 --- a/packages/react-native-fantom/src/index.js +++ b/packages/react-native-fantom/src/index.js @@ -155,9 +155,7 @@ export function dispatchNativeEvent( node: ReactNativeElement, type: string, payload?: {[key: string]: mixed}, - options?: { - category?: NativeEventCategory, - }, + options?: {category?: NativeEventCategory, isUnique?: boolean}, ) { const shadowNode = getShadowNode(node); NativeFantom.dispatchNativeEvent( @@ -165,6 +163,7 @@ export function dispatchNativeEvent( type, payload, options?.category, + options?.isUnique, ); } diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 228509ffd56a..8b5128f0ad14 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -10482,7 +10482,8 @@ interface Spec extends TurboModule { shadowNode: mixed, type: string, payload?: mixed, - category?: NativeEventCategory + category?: NativeEventCategory, + isUnique?: boolean ) => void; getMountingManagerLogs: (surfaceId: number) => Array; flushMessageQueue: () => void; diff --git a/packages/react-native/src/private/specs/modules/NativeFantom.js b/packages/react-native/src/private/specs/modules/NativeFantom.js index d2772110403d..775d0bc243ca 100644 --- a/packages/react-native/src/private/specs/modules/NativeFantom.js +++ b/packages/react-native/src/private/specs/modules/NativeFantom.js @@ -64,6 +64,7 @@ interface Spec extends TurboModule { type: string, payload?: mixed, category?: NativeEventCategory, + isUnique?: boolean, ) => void; getMountingManagerLogs: (surfaceId: number) => Array; flushMessageQueue: () => void;