Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dd7e5e4

Browse files
authored
Add getInspectorDataForViewAtPoint (take two) (facebook#18388)
* Add getInspectorDataForViewAtPoint (take two) * Updates from review * Add DEV to dev-only variable * Missed this rename
1 parent d7382b6 commit dd7e5e4

13 files changed

+260
-24
lines changed

packages/react-dom/src/client/ReactDOMHostConfig.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ export type UpdatePayload = Array<mixed>;
145145
export type ChildSet = void; // Unused
146146
export type TimeoutHandle = TimeoutID;
147147
export type NoTimeout = -1;
148+
export type RendererInspectionConfig = $ReadOnly<{||}>;
148149

149150
type SelectionInformation = {|
150151
activeElementDetached: null | HTMLElement,

packages/react-native-renderer/src/ReactFabric.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ import ReactVersion from 'shared/ReactVersion';
3434
import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
3535

3636
import {getClosestInstanceFromNode} from './ReactFabricComponentTree';
37-
import {getInspectorDataForViewTag} from './ReactNativeFiberInspector';
38-
37+
import {
38+
getInspectorDataForViewTag,
39+
getInspectorDataForViewAtPoint,
40+
} from './ReactNativeFiberInspector';
3941
import {LegacyRoot} from 'react-reconciler/src/ReactRootTags';
4042
import ReactSharedInternals from 'shared/ReactSharedInternals';
4143
import getComponentName from 'shared/getComponentName';
@@ -232,8 +234,14 @@ export {
232234

233235
injectIntoDevTools({
234236
findFiberByHostInstance: getClosestInstanceFromNode,
235-
getInspectorDataForViewTag: getInspectorDataForViewTag,
236237
bundleType: __DEV__ ? 1 : 0,
237238
version: ReactVersion,
238239
rendererPackageName: 'react-native-renderer',
240+
rendererConfig: {
241+
getInspectorDataForViewTag: getInspectorDataForViewTag,
242+
getInspectorDataForViewAtPoint: getInspectorDataForViewAtPoint.bind(
243+
null,
244+
findNodeHandle,
245+
),
246+
},
239247
});

packages/react-native-renderer/src/ReactFabricHostConfig.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {
1515
MeasureOnSuccessCallback,
1616
NativeMethods,
1717
ReactNativeBaseComponentViewConfig,
18+
TouchedViewDataAtPoint,
1819
} from './ReactNativeTypes';
1920

2021
import {mountSafeCallback_NOT_REALLY_SAFE} from './NativeMethodsMixinUtils';
@@ -80,6 +81,17 @@ export type ReactListenerEvent = Object;
8081
export type ReactListenerMap = Object;
8182
export type ReactListener = Object;
8283

84+
export type RendererInspectionConfig = $ReadOnly<{|
85+
// Deprecated. Replaced with getInspectorDataForViewAtPoint.
86+
getInspectorDataForViewTag?: (tag: number) => Object,
87+
getInspectorDataForViewAtPoint?: (
88+
inspectedView: Object,
89+
locationX: number,
90+
locationY: number,
91+
callback: (viewData: TouchedViewDataAtPoint) => mixed,
92+
) => void,
93+
|}>;
94+
8395
// TODO: Remove this conditional once all changes have propagated.
8496
if (registerEventHandler) {
8597
/**

packages/react-native-renderer/src/ReactNativeFiberHostComponent.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,20 @@ import {
3333
class ReactNativeFiberHostComponent {
3434
_children: Array<Instance | number>;
3535
_nativeTag: number;
36+
_internalFiberInstanceHandleDEV: Object;
3637
viewConfig: ReactNativeBaseComponentViewConfig<>;
3738

38-
constructor(tag: number, viewConfig: ReactNativeBaseComponentViewConfig<>) {
39+
constructor(
40+
tag: number,
41+
viewConfig: ReactNativeBaseComponentViewConfig<>,
42+
internalInstanceHandleDEV: Object,
43+
) {
3944
this._nativeTag = tag;
4045
this._children = [];
4146
this.viewConfig = viewConfig;
47+
if (__DEV__) {
48+
this._internalFiberInstanceHandleDEV = internalInstanceHandleDEV;
49+
}
4250
}
4351

4452
blur() {

packages/react-native-renderer/src/ReactNativeFiberInspector.js

Lines changed: 133 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
import type {Fiber} from 'react-reconciler/src/ReactFiber';
11+
import type {TouchedViewDataAtPoint, InspectorData} from './ReactNativeTypes';
1112

1213
import {
1314
findCurrentHostFiber,
@@ -27,6 +28,7 @@ if (__DEV__) {
2728
}
2829

2930
let getInspectorDataForViewTag;
31+
let getInspectorDataForViewAtPoint;
3032

3133
if (__DEV__) {
3234
const traverseOwnerTreeUp = function(hierarchy, instance: any) {
@@ -80,15 +82,59 @@ if (__DEV__) {
8082
const createHierarchy = function(fiberHierarchy) {
8183
return fiberHierarchy.map(fiber => ({
8284
name: getComponentName(fiber.type),
83-
getInspectorData: findNodeHandle => ({
84-
measure: callback =>
85-
UIManager.measure(getHostNode(fiber, findNodeHandle), callback),
86-
props: getHostProps(fiber),
87-
source: fiber._debugSource,
88-
}),
85+
getInspectorData: findNodeHandle => {
86+
return {
87+
props: getHostProps(fiber),
88+
source: fiber._debugSource,
89+
measure: callback => {
90+
// If this is Fabric, we'll find a ShadowNode and use that to measure.
91+
const hostFiber = findCurrentHostFiber(fiber);
92+
const shadowNode =
93+
hostFiber != null &&
94+
hostFiber.stateNode !== null &&
95+
hostFiber.stateNode.node;
96+
97+
if (shadowNode) {
98+
nativeFabricUIManager.measure(shadowNode, callback);
99+
} else {
100+
return UIManager.measure(
101+
getHostNode(fiber, findNodeHandle),
102+
callback,
103+
);
104+
}
105+
},
106+
};
107+
},
89108
}));
90109
};
91110

111+
const getInspectorDataForInstance = function(closestInstance): InspectorData {
112+
// Handle case where user clicks outside of ReactNative
113+
if (!closestInstance) {
114+
return {
115+
hierarchy: [],
116+
props: emptyObject,
117+
selectedIndex: null,
118+
source: null,
119+
};
120+
}
121+
122+
const fiber = findCurrentFiberUsingSlowPath(closestInstance);
123+
const fiberHierarchy = getOwnerHierarchy(fiber);
124+
const instance = lastNonHostInstance(fiberHierarchy);
125+
const hierarchy = createHierarchy(fiberHierarchy);
126+
const props = getHostProps(instance);
127+
const source = instance._debugSource;
128+
const selectedIndex = fiberHierarchy.indexOf(instance);
129+
130+
return {
131+
hierarchy,
132+
props,
133+
selectedIndex,
134+
source,
135+
};
136+
};
137+
92138
getInspectorDataForViewTag = function(viewTag: number): Object {
93139
const closestInstance = getClosestInstanceFromNode(viewTag);
94140

@@ -97,7 +143,7 @@ if (__DEV__) {
97143
return {
98144
hierarchy: [],
99145
props: emptyObject,
100-
selection: null,
146+
selectedIndex: null,
101147
source: null,
102148
};
103149
}
@@ -108,22 +154,99 @@ if (__DEV__) {
108154
const hierarchy = createHierarchy(fiberHierarchy);
109155
const props = getHostProps(instance);
110156
const source = instance._debugSource;
111-
const selection = fiberHierarchy.indexOf(instance);
157+
const selectedIndex = fiberHierarchy.indexOf(instance);
112158

113159
return {
114160
hierarchy,
115161
props,
116-
selection,
162+
selectedIndex,
117163
source,
118164
};
119165
};
166+
167+
getInspectorDataForViewAtPoint = function(
168+
findNodeHandle: (componentOrHandle: any) => ?number,
169+
inspectedView: Object,
170+
locationX: number,
171+
locationY: number,
172+
callback: (viewData: TouchedViewDataAtPoint) => mixed,
173+
): void {
174+
let closestInstance = null;
175+
176+
if (inspectedView._internalInstanceHandle != null) {
177+
// For Fabric we can look up the instance handle directly and measure it.
178+
nativeFabricUIManager.findNodeAtPoint(
179+
inspectedView._internalInstanceHandle.stateNode.node,
180+
locationX,
181+
locationY,
182+
internalInstanceHandle => {
183+
if (internalInstanceHandle == null) {
184+
callback({
185+
pointerY: locationY,
186+
frame: {left: 0, top: 0, width: 0, height: 0},
187+
...getInspectorDataForInstance(closestInstance),
188+
});
189+
}
190+
191+
closestInstance =
192+
internalInstanceHandle.stateNode.canonical._internalInstanceHandle;
193+
nativeFabricUIManager.measure(
194+
internalInstanceHandle.stateNode.node,
195+
(x, y, width, height, pageX, pageY) => {
196+
callback({
197+
pointerY: locationY,
198+
frame: {left: pageX, top: pageY, width, height},
199+
...getInspectorDataForInstance(closestInstance),
200+
});
201+
},
202+
);
203+
},
204+
);
205+
} else if (inspectedView._internalFiberInstanceHandleDEV != null) {
206+
// For Paper we fall back to the old strategy using the React tag.
207+
UIManager.findSubviewIn(
208+
findNodeHandle(inspectedView),
209+
[locationX, locationY],
210+
(nativeViewTag, left, top, width, height) => {
211+
const inspectorData = getInspectorDataForInstance(
212+
getClosestInstanceFromNode(nativeViewTag),
213+
);
214+
callback({
215+
...inspectorData,
216+
pointerY: locationY,
217+
frame: {left, top, width, height},
218+
touchedViewTag: nativeViewTag,
219+
});
220+
},
221+
);
222+
} else {
223+
console.error(
224+
'getInspectorDataForViewAtPoint expects to receieve a host component',
225+
);
226+
227+
return;
228+
}
229+
};
120230
} else {
121231
getInspectorDataForViewTag = () => {
122232
invariant(
123233
false,
124234
'getInspectorDataForViewTag() is not available in production',
125235
);
126236
};
237+
238+
getInspectorDataForViewAtPoint = (
239+
findNodeHandle: (componentOrHandle: any) => ?number,
240+
inspectedView: Object,
241+
locationX: number,
242+
locationY: number,
243+
callback: (viewData: TouchedViewDataAtPoint) => mixed,
244+
): void => {
245+
invariant(
246+
false,
247+
'getInspectorDataForViewAtPoint() is not available in production.',
248+
);
249+
};
127250
}
128251

129-
export {getInspectorDataForViewTag};
252+
export {getInspectorDataForViewAtPoint, getInspectorDataForViewTag};

packages/react-native-renderer/src/ReactNativeHostConfig.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* @flow
88
*/
99

10+
import type {TouchedViewDataAtPoint} from './ReactNativeTypes';
11+
1012
import invariant from 'shared/invariant';
1113

1214
// Modules provided by RN:
@@ -46,6 +48,17 @@ export type ChildSet = void; // Unused
4648
export type TimeoutHandle = TimeoutID;
4749
export type NoTimeout = -1;
4850

51+
export type RendererInspectionConfig = $ReadOnly<{|
52+
// Deprecated. Replaced with getInspectorDataForViewAtPoint.
53+
getInspectorDataForViewTag?: (tag: number) => Object,
54+
getInspectorDataForViewAtPoint?: (
55+
inspectedView: Object,
56+
locationX: number,
57+
locationY: number,
58+
callback: (viewData: TouchedViewDataAtPoint) => mixed,
59+
) => void,
60+
|}>;
61+
4962
const UPDATE_SIGNAL = {};
5063
if (__DEV__) {
5164
Object.freeze(UPDATE_SIGNAL);
@@ -112,7 +125,11 @@ export function createInstance(
112125
updatePayload, // props
113126
);
114127

115-
const component = new ReactNativeFiberHostComponent(tag, viewConfig);
128+
const component = new ReactNativeFiberHostComponent(
129+
tag,
130+
viewConfig,
131+
internalInstanceHandle,
132+
);
116133

117134
precacheFiberNode(internalInstanceHandle, tag);
118135
updateFiberProps(tag, props);

packages/react-native-renderer/src/ReactNativeRenderer.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@ import ReactVersion from 'shared/ReactVersion';
3636
import {UIManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
3737

3838
import {getClosestInstanceFromNode} from './ReactNativeComponentTree';
39-
import {getInspectorDataForViewTag} from './ReactNativeFiberInspector';
40-
39+
import {
40+
getInspectorDataForViewTag,
41+
getInspectorDataForViewAtPoint,
42+
} from './ReactNativeFiberInspector';
4143
import {LegacyRoot} from 'react-reconciler/src/ReactRootTags';
4244
import ReactSharedInternals from 'shared/ReactSharedInternals';
4345
import getComponentName from 'shared/getComponentName';
@@ -246,8 +248,14 @@ export {
246248

247249
injectIntoDevTools({
248250
findFiberByHostInstance: getClosestInstanceFromNode,
249-
getInspectorDataForViewTag: getInspectorDataForViewTag,
250251
bundleType: __DEV__ ? 1 : 0,
251252
version: ReactVersion,
252253
rendererPackageName: 'react-native-renderer',
254+
rendererConfig: {
255+
getInspectorDataForViewTag: getInspectorDataForViewTag,
256+
getInspectorDataForViewAtPoint: getInspectorDataForViewAtPoint.bind(
257+
null,
258+
findNodeHandle,
259+
),
260+
},
253261
});

packages/react-native-renderer/src/ReactNativeTypes.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,46 @@ type SecretInternalsType = {
100100
...
101101
};
102102

103+
type InspectorDataProps = $ReadOnly<{
104+
[propName: string]: string,
105+
...,
106+
}>;
107+
108+
type InspectorDataSource = $ReadOnly<{|
109+
fileName?: string,
110+
lineNumber?: number,
111+
|}>;
112+
113+
type InspectorDataGetter = (
114+
(componentOrHandle: any) => ?number,
115+
) => $ReadOnly<{|
116+
measure: Function,
117+
props: InspectorDataProps,
118+
source: InspectorDataSource,
119+
|}>;
120+
121+
export type InspectorData = $ReadOnly<{|
122+
hierarchy: Array<{|
123+
name: ?string,
124+
getInspectorData: InspectorDataGetter,
125+
|}>,
126+
selectedIndex: ?number,
127+
props: InspectorDataProps,
128+
source: ?InspectorDataSource,
129+
|}>;
130+
131+
export type TouchedViewDataAtPoint = $ReadOnly<{|
132+
pointerY: number,
133+
touchedViewTag?: number,
134+
frame: $ReadOnly<{|
135+
top: number,
136+
left: number,
137+
width: number,
138+
height: number,
139+
|}>,
140+
...InspectorData,
141+
|}>;
142+
103143
/**
104144
* Flat ReactNative renderer bundles are too big for Flow to parse efficiently.
105145
* Provide minimal Flow typing for the high-level RN API and call it a day.

0 commit comments

Comments
 (0)