feat[Fabric/Paper]: support isChildPublicInstance api method (#27783)
Adds `isChildPublicInstance` method to both renderers (Fabric and Paper), which will receive 2 public instances and return if first argument is an ancestor of the second, based on fibers. This will be used as a fallback when DOM node APIs are not available: for Paper renderer or for Fabric without DOM node APIs. How it is going to be used: to determine which `AppContainer` component in RN is responsible for highlighting an inspected element on the screen.
Ruslan Lesiutin committed
Dec 4, 2023 at 17:22 UTC
1729b499ed8cd456ef3d8bccd413cdecd9931abc
4 files changed
+62
packages/react-native-renderer/src/ReactFabric.js
+3
@@ -39,6 +39,7 @@ import {
39
dispatchCommand,
40
sendAccessibilityEvent,
41
getNodeFromInternalInstanceHandle,
42
+ isChildPublicInstance,
43
} from './ReactNativePublicCompat';
44
import {getPublicInstanceFromInternalInstanceHandle} from './ReactFiberConfigFabric';
45
@@ -128,6 +129,8 @@ export {
129
// instance handles we use to dispatch events. This provides a way to access
130
// the public instances we created from them (potentially created lazily).
131
getPublicInstanceFromInternalInstanceHandle,
132
+ // DEV-only:
133
+ isChildPublicInstance,
134
};
135
136
injectIntoDevTools({
packages/react-native-renderer/src/ReactNativePublicCompat.js
+53
@@ -8,6 +8,8 @@
8
*/
9
10
import type {Node, HostComponent} from './ReactNativeTypes';
11
+import type {PublicInstance as FabricPublicInstance} from './ReactFiberConfigFabric';
12
+import type {PublicInstance as PaperPublicInstance} from './ReactFiberConfigNative';
13
import type {ElementRef, ElementType} from 'react';
14
15
// Modules provided by RN:
@@ -16,15 +18,19 @@ import {
18
legacySendAccessibilityEvent,
19
getNodeFromPublicInstance,
20
getNativeTagFromPublicInstance,
21
+ getInternalInstanceHandleFromPublicInstance,
22
} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
23
24
import {
25
findHostInstance,
26
findHostInstanceWithWarning,
27
} from 'react-reconciler/src/ReactFiberReconciler';
28
+import {doesFiberContain} from 'react-reconciler/src/ReactFiberTreeReflection';
29
import ReactSharedInternals from 'shared/ReactSharedInternals';
30
import getComponentNameFromType from 'shared/getComponentNameFromType';
31
32
+import ReactNativeFiberHostComponent from './ReactNativeFiberHostComponent';
33
+
34
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
35
36
export function findHostInstance_DEPRECATED<TElementType: ElementType>(
@@ -218,3 +224,50 @@ export function getNodeFromInternalInstanceHandle(
224
internalInstanceHandle.stateNode.node
225
);
226
}
227
+
228
+// Remove this once Paper is no longer supported and DOM Node API are enabled by default in RN.
229
+export function isChildPublicInstance(
230
+ parentInstance: FabricPublicInstance | PaperPublicInstance,
231
+ childInstance: FabricPublicInstance | PaperPublicInstance,
232
+): boolean {
233
+ if (__DEV__) {
234
+ // Paper
235
+ if (
236
+ parentInstance instanceof ReactNativeFiberHostComponent ||
237
+ childInstance instanceof ReactNativeFiberHostComponent
238
+ ) {
239
+ if (
240
+ parentInstance instanceof ReactNativeFiberHostComponent &&
241
+ childInstance instanceof ReactNativeFiberHostComponent
242
+ ) {
243
+ return doesFiberContain(
244
+ parentInstance._internalFiberInstanceHandleDEV,
245
+ childInstance._internalFiberInstanceHandleDEV,
246
+ );
247
+ }
248
+
249
+ // Means that one instance is from Fabric and other is from Paper.
250
+ return false;
251
+ }
252
+
253
+ const parentInternalInstanceHandle =
254
+ getInternalInstanceHandleFromPublicInstance(parentInstance);
255
+ const childInternalInstanceHandle =
256
+ getInternalInstanceHandleFromPublicInstance(childInstance);
257
+
258
+ // Fabric
259
+ if (
260
+ parentInternalInstanceHandle != null &&
261
+ childInternalInstanceHandle != null
262
+ ) {
263
+ return doesFiberContain(
264
+ parentInternalInstanceHandle,
265
+ childInternalInstanceHandle,
266
+ );
267
+ }
268
+
269
+ return false;
270
+ } else {
271
+ throw new Error('isChildPublicInstance() is not available in production.');
272
+ }
273
+}
packages/react-native-renderer/src/ReactNativeRenderer.js
+3
@@ -44,6 +44,7 @@ import {
44
findNodeHandle,
45
dispatchCommand,
46
sendAccessibilityEvent,
47
+ isChildPublicInstance,
48
} from './ReactNativePublicCompat';
49
50
// $FlowFixMe[missing-local-annot]
@@ -137,6 +138,8 @@ export {
138
// This export is typically undefined in production builds.
139
// See the "enableGetInspectorDataForInstanceInProduction" flag.
140
getInspectorDataForInstance,
141
+ // DEV-only:
142
+ isChildPublicInstance,
143
};
144
145
injectIntoDevTools({
scripts/flow/react-native-host-hooks.js
+3
@@ -159,6 +159,9 @@ declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'
159
declare export function createPublicTextInstance(
160
internalInstanceHandle: mixed,
161
): PublicTextInstance;
162
+ declare export function getInternalInstanceHandleFromPublicInstance(
163
+ publicInstance: PublicInstance,
164
+ ): ?Object;
165
}
166
167
declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInitializeCore' {