From 9cd7de1b5e6379bf476be81c98e4fce2967ed9c7 Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin Date: Mon, 4 Dec 2023 14:11:03 +0000 Subject: [PATCH] feat[Fabric/Paper]: support getIsOneInstanceAncestorOfAnother api method --- .../react-native-renderer/src/ReactFabric.js | 3 ++ .../src/ReactNativePublicCompat.js | 44 +++++++++++++++++++ .../src/ReactNativeRenderer.js | 3 ++ scripts/flow/react-native-host-hooks.js | 3 ++ 4 files changed, 53 insertions(+) diff --git a/packages/react-native-renderer/src/ReactFabric.js b/packages/react-native-renderer/src/ReactFabric.js index 8e6b99ce83a78..084310de03fb2 100644 --- a/packages/react-native-renderer/src/ReactFabric.js +++ b/packages/react-native-renderer/src/ReactFabric.js @@ -39,6 +39,7 @@ import { dispatchCommand, sendAccessibilityEvent, getNodeFromInternalInstanceHandle, + getIsOneInstanceAncestorOfAnother, } from './ReactNativePublicCompat'; import {getPublicInstanceFromInternalInstanceHandle} from './ReactFiberConfigFabric'; @@ -128,6 +129,8 @@ export { // instance handles we use to dispatch events. This provides a way to access // the public instances we created from them (potentially created lazily). getPublicInstanceFromInternalInstanceHandle, + // DEV-only: + getIsOneInstanceAncestorOfAnother, }; injectIntoDevTools({ diff --git a/packages/react-native-renderer/src/ReactNativePublicCompat.js b/packages/react-native-renderer/src/ReactNativePublicCompat.js index 88377dc75e527..3690ab5f2b381 100644 --- a/packages/react-native-renderer/src/ReactNativePublicCompat.js +++ b/packages/react-native-renderer/src/ReactNativePublicCompat.js @@ -16,15 +16,20 @@ import { legacySendAccessibilityEvent, getNodeFromPublicInstance, getNativeTagFromPublicInstance, + getInternalInstanceHandleFromPublicInstance, } from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'; import { findHostInstance, findHostInstanceWithWarning, } from 'react-reconciler/src/ReactFiberReconciler'; +import {doesFiberContain} from 'react-reconciler/src/ReactFiberTreeReflection'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import getComponentNameFromType from 'shared/getComponentNameFromType'; +import {PublicInstance as FabricPublicInstance} from './ReactFiberConfigFabric'; +import {PublicInstance as PaperPublicInstance} from './ReactFiberConfigNative'; + const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; export function findHostInstance_DEPRECATED( @@ -218,3 +223,42 @@ export function getNodeFromInternalInstanceHandle( internalInstanceHandle.stateNode.node ); } + +// Remove this once Paper is no longer supported and DOM Node API are enabled by default in RN. +export function getIsOneInstanceAncestorOfAnother( + parentInstance: FabricPublicInstance | PaperPublicInstance, + childInstance: FabricPublicInstance | PaperPublicInstance, +): boolean { + if (__DEV__) { + const parentInternalInstanceHandle = + getInternalInstanceHandleFromPublicInstance(parentInstance); + const childInternalInstanceHandle = + getInternalInstanceHandleFromPublicInstance(childInstance); + + // Fabric + if ( + parentInternalInstanceHandle != null && + childInternalInstanceHandle != null + ) { + return doesFiberContain( + parentInternalInstanceHandle, + childInternalInstanceHandle, + ); + } + + // Paper + if ( + parentInstance._internalFiberInstanceHandleDEV != null && + childInstance._internalFiberInstanceHandleDEV != null + ) { + return doesFiberContain( + parentInstance._internalFiberInstanceHandleDEV, + childInstance._internalFiberInstanceHandleDEV, + ); + } + + return false; + } else { + throw new Error('getIs() is not available in production.'); + } +} diff --git a/packages/react-native-renderer/src/ReactNativeRenderer.js b/packages/react-native-renderer/src/ReactNativeRenderer.js index bdc09843950cf..4774eec917e68 100644 --- a/packages/react-native-renderer/src/ReactNativeRenderer.js +++ b/packages/react-native-renderer/src/ReactNativeRenderer.js @@ -44,6 +44,7 @@ import { findNodeHandle, dispatchCommand, sendAccessibilityEvent, + getIsOneInstanceAncestorOfAnother, } from './ReactNativePublicCompat'; // $FlowFixMe[missing-local-annot] @@ -137,6 +138,8 @@ export { // This export is typically undefined in production builds. // See the "enableGetInspectorDataForInstanceInProduction" flag. getInspectorDataForInstance, + // DEV-only: + getIsOneInstanceAncestorOfAnother, }; injectIntoDevTools({ diff --git a/scripts/flow/react-native-host-hooks.js b/scripts/flow/react-native-host-hooks.js index 7f53e5199439e..fa9cd42c72ff0 100644 --- a/scripts/flow/react-native-host-hooks.js +++ b/scripts/flow/react-native-host-hooks.js @@ -159,6 +159,9 @@ declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface' declare export function createPublicTextInstance( internalInstanceHandle: mixed, ): PublicTextInstance; + declare export function getInternalInstanceHandleFromPublicInstance( + publicInstance: PublicInstance, + ): mixed; } declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore' {