Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions src/utilities/findNodeHandle.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,50 @@ import {
findNodeHandle as _findNodeHandle,
} from 'react-native';

/**
* Type bridge for accessing undocumented React Native scroll component internals.
* These properties exist at runtime but aren't exposed in RN's public type definitions.
*
* @see https://github.com/facebook/react-native/blob/main/packages/virtualized-lists/Lists/VirtualizedList.js#L1252
*/
interface ScrollComponentInternals {
/** Available on ScrollView, FlatList, etc. to get the underlying native scroll ref */
getNativeScrollRef?: () => NodeHandle | null;
/** Internal property on VirtualizedList storing the scroll ref */
_scrollRef?: NodeHandle | null;
}

export function findNodeHandle(
componentOrHandle: Parameters<typeof _findNodeHandle>['0']
) {
let nodeHandle: NodeHandle | null;
): NodeHandle | null | typeof componentOrHandle {
// Early return for null/undefined (React 19 fix)
if (componentOrHandle == null) {
return null;
}

let nodeHandle: NodeHandle | null = null;

try {
nodeHandle = _findNodeHandle(componentOrHandle);
if (nodeHandle) {
return nodeHandle;
}
} catch {}

// Type bridge: componentOrHandle may have scroll internals at runtime
const scrollable = componentOrHandle as unknown as ScrollComponentInternals;

try {
// @ts-ignore
nodeHandle = componentOrHandle.getNativeScrollRef();
if (nodeHandle) {
return nodeHandle;
if (typeof scrollable.getNativeScrollRef === 'function') {
nodeHandle = scrollable.getNativeScrollRef();
if (nodeHandle) {
return nodeHandle;
}
}
} catch {}

// @ts-ignore https://github.com/facebook/react-native/blob/a314e34d6ee875830d36e4df1789a897c7262056/packages/virtualized-lists/Lists/VirtualizedList.js#L1252
nodeHandle = componentOrHandle._scrollRef;
if (nodeHandle) {
return nodeHandle;
if (scrollable._scrollRef != null) {
return scrollable._scrollRef;
}

console.warn('could not find scrollable ref!');
Expand Down