Skip to content

Commit aa57608

Browse files
sammy-SCfacebook-github-bot
authored andcommitted
introduce Fantom.scrollTo (#48907)
Summary: Pull Request resolved: #48907 changelog: [internal] Introduce new function `Fantom.scrollTo`, which will fake a scroll to particular position. Calling the method will call onScroll event using codepath that iOS uses. It will also set C++ state so the new scroll position is observable from JavaScript. Reviewed By: javache Differential Revision: D68554703 fbshipit-source-id: 2fc71e96836a03ec343053ceed85764c4bc2f5c7
1 parent 84b8e6a commit aa57608

File tree

4 files changed

+131
-0
lines changed

4 files changed

+131
-0
lines changed

packages/react-native-fantom/src/__tests__/Fantom-itest.js

+104
Original file line numberDiff line numberDiff line change
@@ -473,4 +473,108 @@ describe('Fantom', () => {
473473
y: 2,
474474
});
475475
});
476+
477+
describe('scrollTo', () => {
478+
it('throws error if called on node that is not scroll view', () => {
479+
const root = Fantom.createRoot();
480+
let maybeNode;
481+
482+
Fantom.runTask(() => {
483+
root.render(
484+
<View
485+
ref={node => {
486+
maybeNode = node;
487+
}}
488+
/>,
489+
);
490+
});
491+
492+
const element = ensureInstance(maybeNode, ReactNativeElement);
493+
494+
expect(() => {
495+
Fantom.runOnUIThread(() => {
496+
Fantom.scrollTo(element, {
497+
x: 0,
498+
y: 1,
499+
});
500+
});
501+
}).toThrow(
502+
'Exception in HostFunction: scrollTo() can only be called on <ScrollView />',
503+
);
504+
});
505+
506+
it('delivers onScroll event and affects position of elements on screen', () => {
507+
const root = Fantom.createRoot();
508+
let maybeScrollViewNode;
509+
let maybeNode;
510+
const onScroll = jest.fn();
511+
512+
Fantom.runTask(() => {
513+
root.render(
514+
<ScrollView
515+
onScroll={event => {
516+
onScroll(event.nativeEvent);
517+
}}
518+
ref={node => {
519+
maybeScrollViewNode = node;
520+
}}>
521+
<View
522+
style={{width: 1, height: 2, top: 3}}
523+
ref={node => {
524+
maybeNode = node;
525+
}}
526+
/>
527+
</ScrollView>,
528+
);
529+
});
530+
531+
const scrollViewElement = ensureInstance(
532+
maybeScrollViewNode,
533+
ReactNativeElement,
534+
);
535+
536+
Fantom.runOnUIThread(() => {
537+
Fantom.scrollTo(scrollViewElement, {
538+
x: 0,
539+
y: 1,
540+
});
541+
});
542+
543+
Fantom.runWorkLoop();
544+
545+
expect(onScroll).toHaveBeenCalledTimes(1);
546+
547+
const viewElement = ensureInstance(maybeNode, ReactNativeElement);
548+
549+
let rect;
550+
551+
viewElement.measure((x, y, width, height, pageX, pageY) => {
552+
rect = {
553+
x,
554+
y,
555+
width,
556+
height,
557+
pageX,
558+
pageY,
559+
};
560+
});
561+
562+
expect(rect).toEqual({
563+
x: 0,
564+
y: 3,
565+
width: 1,
566+
height: 2,
567+
pageY: 2,
568+
pageX: 0,
569+
});
570+
571+
const boundingClientRect = viewElement.getBoundingClientRect();
572+
expect(boundingClientRect.x).toBe(0);
573+
expect(boundingClientRect.y).toBe(2);
574+
expect(boundingClientRect.width).toBe(1);
575+
expect(boundingClientRect.height).toBe(2);
576+
577+
root.destroy();
578+
});
579+
});
476580
});

packages/react-native-fantom/src/index.js

+11
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,16 @@ function dispatchNativeEvent(
167167
);
168168
}
169169

170+
function scrollTo(
171+
node: ReactNativeElement,
172+
options: {x: number, y: number, zoomScale?: number},
173+
) {
174+
const shadowNode = getShadowNode(node);
175+
NativeFantom.scrollTo(shadowNode, options);
176+
}
177+
178+
export const unstable_benchmark = Benchmark;
179+
170180
type FantomConstants = $ReadOnly<{
171181
isRunningFromCI: boolean,
172182
}>;
@@ -255,4 +265,5 @@ export default {
255265
createRoot,
256266
dispatchNativeEvent,
257267
unstable_benchmark: Benchmark,
268+
scrollTo,
258269
};

packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap

+6
Original file line numberDiff line numberDiff line change
@@ -10465,6 +10465,11 @@ export enum NativeEventCategory {
1046510465
Discrete = 3,
1046610466
Continuous = 4,
1046710467
}
10468+
export type ScrollOptions = {
10469+
x: number,
10470+
y: number,
10471+
zoomScale?: number,
10472+
};
1046810473
interface Spec extends TurboModule {
1046910474
startSurface: (
1047010475
surfaceId: number,
@@ -10480,6 +10485,7 @@ interface Spec extends TurboModule {
1048010485
category?: NativeEventCategory,
1048110486
isUnique?: boolean
1048210487
) => void;
10488+
scrollTo: (shadowNode: mixed, options: ScrollOptions) => void;
1048310489
getMountingManagerLogs: (surfaceId: number) => Array<string>;
1048410490
flushMessageQueue: () => void;
1048510491
flushEventQueue: () => void;

packages/react-native/src/private/specs/modules/NativeFantom.js

+10
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ export enum NativeEventCategory {
5151
Continuous = 4,
5252
}
5353

54+
export type ScrollOptions = {
55+
x: number,
56+
y: number,
57+
zoomScale?: number,
58+
};
59+
5460
interface Spec extends TurboModule {
5561
startSurface: (
5662
surfaceId: number,
@@ -66,6 +72,10 @@ interface Spec extends TurboModule {
6672
category?: NativeEventCategory,
6773
isUnique?: boolean,
6874
) => void;
75+
scrollTo: (
76+
shadowNode: mixed /* ShadowNode */,
77+
options: ScrollOptions,
78+
) => void;
6979
getMountingManagerLogs: (surfaceId: number) => Array<string>;
7080
flushMessageQueue: () => void;
7181
flushEventQueue: () => void;

0 commit comments

Comments
 (0)