@buoy-gg/debug-borders 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +334 -0
- package/lib/commonjs/debug-borders/components/DebugBordersModal.js +234 -0
- package/lib/commonjs/debug-borders/components/DebugBordersStandaloneOverlay.js +436 -0
- package/lib/commonjs/debug-borders/index.js +51 -0
- package/lib/commonjs/debug-borders/types.js +1 -0
- package/lib/commonjs/debug-borders/utils/DebugBordersManager.js +119 -0
- package/lib/commonjs/debug-borders/utils/ViewTypeMapper.js +264 -0
- package/lib/commonjs/debug-borders/utils/colorGeneration.js +76 -0
- package/lib/commonjs/debug-borders/utils/componentInfo.js +183 -0
- package/lib/commonjs/debug-borders/utils/componentMeasurement.js +111 -0
- package/lib/commonjs/debug-borders/utils/fiberTreeTraversal.js +309 -0
- package/lib/commonjs/debug-borders/utils/labelPositioning.js +202 -0
- package/lib/commonjs/index.js +34 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/preset.js +178 -0
- package/lib/module/debug-borders/components/DebugBordersModal.js +229 -0
- package/lib/module/debug-borders/components/DebugBordersStandaloneOverlay.js +432 -0
- package/lib/module/debug-borders/index.js +15 -0
- package/lib/module/debug-borders/types.js +1 -0
- package/lib/module/debug-borders/utils/DebugBordersManager.js +119 -0
- package/lib/module/debug-borders/utils/ViewTypeMapper.js +255 -0
- package/lib/module/debug-borders/utils/colorGeneration.js +76 -0
- package/lib/module/debug-borders/utils/componentInfo.js +183 -0
- package/lib/module/debug-borders/utils/componentMeasurement.js +111 -0
- package/lib/module/debug-borders/utils/fiberTreeTraversal.js +309 -0
- package/lib/module/debug-borders/utils/labelPositioning.js +202 -0
- package/lib/module/index.js +7 -0
- package/lib/module/preset.js +166 -0
- package/lib/typescript/debug-borders/components/DebugBordersModal.d.ts +11 -0
- package/lib/typescript/debug-borders/components/DebugBordersModal.d.ts.map +1 -0
- package/lib/typescript/debug-borders/components/DebugBordersStandaloneOverlay.d.ts +15 -0
- package/lib/typescript/debug-borders/components/DebugBordersStandaloneOverlay.d.ts.map +1 -0
- package/lib/typescript/debug-borders/index.d.ts +8 -0
- package/lib/typescript/debug-borders/index.d.ts.map +1 -0
- package/lib/typescript/debug-borders/types.d.ts +45 -0
- package/lib/typescript/debug-borders/types.d.ts.map +1 -0
- package/lib/typescript/debug-borders/utils/ViewTypeMapper.d.ts +66 -0
- package/lib/typescript/debug-borders/utils/ViewTypeMapper.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +3 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts +108 -0
- package/lib/typescript/preset.d.ts.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ViewTypeMapper
|
|
3
|
+
*
|
|
4
|
+
* Maps native view class names (e.g., "RCTView", "RCTText") to their
|
|
5
|
+
* developer-friendly React Native component names (e.g., "View", "Text").
|
|
6
|
+
*
|
|
7
|
+
* This makes the render tracking UI more understandable since developers
|
|
8
|
+
* work with component names, not native class names.
|
|
9
|
+
*
|
|
10
|
+
* Sources:
|
|
11
|
+
* - React Native core: packages/react-native/Libraries/Components/*
|
|
12
|
+
* - React Native Android: ReactAndroid/src/main/java/com/facebook/react/views/*
|
|
13
|
+
* - FabricNameComponentMapping.kt
|
|
14
|
+
* - Common third-party libraries (react-native-svg, gesture-handler, etc.)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
"use strict";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Mapping from native view class names to React component names.
|
|
21
|
+
*
|
|
22
|
+
* Format: { "NativeClassName": "ComponentName" }
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", {
|
|
25
|
+
value: true
|
|
26
|
+
});
|
|
27
|
+
exports.default = exports.VIEW_TYPE_MAP = void 0;
|
|
28
|
+
exports.getAllComponentNames = getAllComponentNames;
|
|
29
|
+
exports.getAllNativeViewTypes = getAllNativeViewTypes;
|
|
30
|
+
exports.getComponentDisplayName = getComponentDisplayName;
|
|
31
|
+
exports.getNativeViewType = getNativeViewType;
|
|
32
|
+
exports.isKnownViewType = isKnownViewType;
|
|
33
|
+
const VIEW_TYPE_MAP = exports.VIEW_TYPE_MAP = {
|
|
34
|
+
// ==========================================================================
|
|
35
|
+
// REACT NATIVE CORE - Views
|
|
36
|
+
// ==========================================================================
|
|
37
|
+
RCTView: "View",
|
|
38
|
+
RCTSafeAreaView: "SafeAreaView",
|
|
39
|
+
RCTModalHostView: "Modal",
|
|
40
|
+
// ==========================================================================
|
|
41
|
+
// REACT NATIVE CORE - Text
|
|
42
|
+
// ==========================================================================
|
|
43
|
+
RCTText: "Text",
|
|
44
|
+
RCTRawText: "RawText",
|
|
45
|
+
RCTVirtualText: "VirtualText",
|
|
46
|
+
RCTTextInlineImage: "TextInlineImage",
|
|
47
|
+
// ==========================================================================
|
|
48
|
+
// REACT NATIVE CORE - Images
|
|
49
|
+
// ==========================================================================
|
|
50
|
+
RCTImageView: "Image",
|
|
51
|
+
RCTImage: "Image",
|
|
52
|
+
// ==========================================================================
|
|
53
|
+
// REACT NATIVE CORE - ScrollView
|
|
54
|
+
// ==========================================================================
|
|
55
|
+
RCTScrollView: "ScrollView",
|
|
56
|
+
RCTScrollContentView: "ScrollContentView",
|
|
57
|
+
AndroidHorizontalScrollView: "HorizontalScrollView",
|
|
58
|
+
AndroidHorizontalScrollContentView: "HorizontalScrollContentView",
|
|
59
|
+
// ==========================================================================
|
|
60
|
+
// REACT NATIVE CORE - TextInput
|
|
61
|
+
// ==========================================================================
|
|
62
|
+
RCTSinglelineTextInputView: "TextInput",
|
|
63
|
+
RCTMultilineTextInputView: "TextInput (Multiline)",
|
|
64
|
+
AndroidTextInput: "TextInput",
|
|
65
|
+
RCTInputAccessoryView: "InputAccessoryView",
|
|
66
|
+
// ==========================================================================
|
|
67
|
+
// REACT NATIVE CORE - Lists (FlatList/SectionList internals)
|
|
68
|
+
// ==========================================================================
|
|
69
|
+
RCTRefreshControl: "RefreshControl",
|
|
70
|
+
AndroidSwipeRefreshLayout: "RefreshControl",
|
|
71
|
+
PullToRefreshView: "RefreshControl",
|
|
72
|
+
// ==========================================================================
|
|
73
|
+
// REACT NATIVE CORE - Buttons & Touchables
|
|
74
|
+
// ==========================================================================
|
|
75
|
+
RCTSwitch: "Switch",
|
|
76
|
+
AndroidSwitch: "Switch",
|
|
77
|
+
RCTSlider: "Slider",
|
|
78
|
+
// ==========================================================================
|
|
79
|
+
// REACT NATIVE CORE - Activity Indicators
|
|
80
|
+
// ==========================================================================
|
|
81
|
+
RCTActivityIndicatorView: "ActivityIndicator",
|
|
82
|
+
AndroidProgressBar: "ActivityIndicator",
|
|
83
|
+
// ==========================================================================
|
|
84
|
+
// REACT NATIVE CORE - Android-specific
|
|
85
|
+
// ==========================================================================
|
|
86
|
+
AndroidDrawerLayout: "DrawerLayout",
|
|
87
|
+
VirtualView: "VirtualView",
|
|
88
|
+
VirtualViewExperimental: "VirtualView",
|
|
89
|
+
// ==========================================================================
|
|
90
|
+
// REACT NATIVE CORE - Debugging & Internal
|
|
91
|
+
// ==========================================================================
|
|
92
|
+
DebuggingOverlay: "DebuggingOverlay",
|
|
93
|
+
LayoutConformance: "LayoutConformance",
|
|
94
|
+
UnimplementedNativeView: "UnimplementedView",
|
|
95
|
+
// ==========================================================================
|
|
96
|
+
// REACT NATIVE CORE - Legacy/Deprecated
|
|
97
|
+
// ==========================================================================
|
|
98
|
+
RKShimmeringView: "ShimmeringView",
|
|
99
|
+
RCTTemplateView: "TemplateView",
|
|
100
|
+
RCTAxialGradientView: "AxialGradientView",
|
|
101
|
+
// "RCTVideo": "Video",
|
|
102
|
+
RCTMap: "Map",
|
|
103
|
+
RCTWebView: "WebView",
|
|
104
|
+
RCTKeyframes: "Keyframes",
|
|
105
|
+
RCTImpressionTrackingView: "ImpressionTrackingView",
|
|
106
|
+
// ==========================================================================
|
|
107
|
+
// REACT-NATIVE-SVG
|
|
108
|
+
// ==========================================================================
|
|
109
|
+
RNSVGSvgView: "Svg",
|
|
110
|
+
RNSVGGroup: "G",
|
|
111
|
+
RNSVGPath: "Path",
|
|
112
|
+
RNSVGText: "SvgText",
|
|
113
|
+
RNSVGTSpan: "TSpan",
|
|
114
|
+
RNSVGTextPath: "TextPath",
|
|
115
|
+
RNSVGImage: "SvgImage",
|
|
116
|
+
RNSVGCircle: "Circle",
|
|
117
|
+
RNSVGEllipse: "Ellipse",
|
|
118
|
+
RNSVGLine: "Line",
|
|
119
|
+
RNSVGRect: "Rect",
|
|
120
|
+
RNSVGClipPath: "ClipPath",
|
|
121
|
+
RNSVGDefs: "Defs",
|
|
122
|
+
RNSVGUse: "Use",
|
|
123
|
+
RNSVGSymbol: "Symbol",
|
|
124
|
+
RNSVGPattern: "Pattern",
|
|
125
|
+
RNSVGMask: "Mask",
|
|
126
|
+
RNSVGForeignObject: "ForeignObject",
|
|
127
|
+
RNSVGMarker: "Marker",
|
|
128
|
+
RNSVGLinearGradient: "LinearGradient",
|
|
129
|
+
RNSVGRadialGradient: "RadialGradient",
|
|
130
|
+
RNSVGFilter: "Filter",
|
|
131
|
+
RNSVGFeBlend: "FeBlend",
|
|
132
|
+
RNSVGFeColorMatrix: "FeColorMatrix",
|
|
133
|
+
RNSVGFeComposite: "FeComposite",
|
|
134
|
+
RNSVGFeFlood: "FeFlood",
|
|
135
|
+
RNSVGFeGaussianBlur: "FeGaussianBlur",
|
|
136
|
+
RNSVGFeMerge: "FeMerge",
|
|
137
|
+
RNSVGFeOffset: "FeOffset",
|
|
138
|
+
RNSVGPolygon: "Polygon",
|
|
139
|
+
RNSVGPolyline: "Polyline",
|
|
140
|
+
RNSVGStop: "Stop",
|
|
141
|
+
// ==========================================================================
|
|
142
|
+
// REACT-NATIVE-GESTURE-HANDLER
|
|
143
|
+
// ==========================================================================
|
|
144
|
+
RNGestureHandlerRootView: "GestureHandlerRootView",
|
|
145
|
+
RNGestureHandlerButton: "GestureHandlerButton",
|
|
146
|
+
// ==========================================================================
|
|
147
|
+
// REACT-NATIVE-SAFE-AREA-CONTEXT
|
|
148
|
+
// ==========================================================================
|
|
149
|
+
RNCSafeAreaProvider: "SafeAreaProvider",
|
|
150
|
+
RNCSafeAreaView: "SafeAreaView",
|
|
151
|
+
// ==========================================================================
|
|
152
|
+
// REACT-NATIVE-SCREENS (React Navigation)
|
|
153
|
+
// ==========================================================================
|
|
154
|
+
RNSScreen: "Screen",
|
|
155
|
+
RNSScreenContainer: "ScreenContainer",
|
|
156
|
+
RNSScreenStack: "ScreenStack",
|
|
157
|
+
RNSScreenStackHeaderConfig: "ScreenStackHeaderConfig",
|
|
158
|
+
RNSScreenStackHeaderSubview: "ScreenStackHeaderSubview",
|
|
159
|
+
RNSSearchBar: "SearchBar",
|
|
160
|
+
RNSFullWindowOverlay: "FullWindowOverlay",
|
|
161
|
+
RNSModalScreen: "ModalScreen",
|
|
162
|
+
// ==========================================================================
|
|
163
|
+
// REACT-NATIVE-REANIMATED
|
|
164
|
+
// ==========================================================================
|
|
165
|
+
ReanimatedView: "Animated.View",
|
|
166
|
+
// ==========================================================================
|
|
167
|
+
// EXPO MODULES
|
|
168
|
+
// ==========================================================================
|
|
169
|
+
ExpoView: "ExpoView",
|
|
170
|
+
ExpoBlurView: "BlurView",
|
|
171
|
+
ExpoLinearGradient: "LinearGradient",
|
|
172
|
+
ExpoImage: "ExpoImage",
|
|
173
|
+
ExpoVideoView: "VideoView",
|
|
174
|
+
ExpoCamera: "Camera",
|
|
175
|
+
ExpoBarCodeScannerView: "BarCodeScanner",
|
|
176
|
+
// ==========================================================================
|
|
177
|
+
// REACT-NATIVE-WEBVIEW
|
|
178
|
+
// ==========================================================================
|
|
179
|
+
RNCWebView: "WebView",
|
|
180
|
+
// ==========================================================================
|
|
181
|
+
// REACT-NATIVE-MAPS
|
|
182
|
+
// ==========================================================================
|
|
183
|
+
AIRMap: "MapView",
|
|
184
|
+
AIRMapMarker: "Marker",
|
|
185
|
+
AIRMapPolyline: "Polyline",
|
|
186
|
+
AIRMapPolygon: "Polygon",
|
|
187
|
+
AIRMapCircle: "Circle",
|
|
188
|
+
AIRMapCallout: "Callout",
|
|
189
|
+
// ==========================================================================
|
|
190
|
+
// REACT-NATIVE-VIDEO
|
|
191
|
+
// ==========================================================================
|
|
192
|
+
RCTVideo: "Video",
|
|
193
|
+
// ==========================================================================
|
|
194
|
+
// LOTTIE-REACT-NATIVE
|
|
195
|
+
// ==========================================================================
|
|
196
|
+
LottieAnimationView: "LottieView",
|
|
197
|
+
// ==========================================================================
|
|
198
|
+
// REACT-NATIVE-FAST-IMAGE
|
|
199
|
+
// ==========================================================================
|
|
200
|
+
FastImageView: "FastImage"
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Get the developer-friendly component name for a native view type.
|
|
205
|
+
* Returns the original viewType if no mapping exists.
|
|
206
|
+
*
|
|
207
|
+
* @param viewType - The native view class name (e.g., "RCTView")
|
|
208
|
+
* @returns The component name (e.g., "View")
|
|
209
|
+
*/
|
|
210
|
+
function getComponentDisplayName(viewType) {
|
|
211
|
+
return VIEW_TYPE_MAP[viewType] || viewType;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get the native view class name for a component name (reverse lookup).
|
|
216
|
+
* Returns null if no mapping exists.
|
|
217
|
+
*
|
|
218
|
+
* @param componentName - The component name (e.g., "View")
|
|
219
|
+
* @returns The native view class name (e.g., "RCTView") or null
|
|
220
|
+
*/
|
|
221
|
+
function getNativeViewType(componentName) {
|
|
222
|
+
for (const [native, display] of Object.entries(VIEW_TYPE_MAP)) {
|
|
223
|
+
if (display === componentName) {
|
|
224
|
+
return native;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Check if a view type is a known native component.
|
|
232
|
+
*
|
|
233
|
+
* @param viewType - The native view class name
|
|
234
|
+
* @returns true if it's a known component
|
|
235
|
+
*/
|
|
236
|
+
function isKnownViewType(viewType) {
|
|
237
|
+
return viewType in VIEW_TYPE_MAP;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Get all known view types (useful for autocomplete/suggestions).
|
|
242
|
+
*
|
|
243
|
+
* @returns Array of all native view class names
|
|
244
|
+
*/
|
|
245
|
+
function getAllNativeViewTypes() {
|
|
246
|
+
return Object.keys(VIEW_TYPE_MAP);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get all known component names (useful for autocomplete/suggestions).
|
|
251
|
+
*
|
|
252
|
+
* @returns Array of all component display names
|
|
253
|
+
*/
|
|
254
|
+
function getAllComponentNames() {
|
|
255
|
+
return [...new Set(Object.values(VIEW_TYPE_MAP))];
|
|
256
|
+
}
|
|
257
|
+
var _default = exports.default = {
|
|
258
|
+
VIEW_TYPE_MAP,
|
|
259
|
+
getComponentDisplayName,
|
|
260
|
+
getNativeViewType,
|
|
261
|
+
isKnownViewType,
|
|
262
|
+
getAllNativeViewTypes,
|
|
263
|
+
getAllComponentNames
|
|
264
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const GOLDEN_ANGLE = 137.508;
|
|
4
|
+
const HUE_START = 0;
|
|
5
|
+
const SATURATION = 70;
|
|
6
|
+
const LIGHTNESS = 50;
|
|
7
|
+
function hslToHex(h, s, l) {
|
|
8
|
+
const hNorm = h / 360;
|
|
9
|
+
const sNorm = s / 100;
|
|
10
|
+
const lNorm = l / 100;
|
|
11
|
+
let r, g, b;
|
|
12
|
+
if (sNorm === 0) {
|
|
13
|
+
r = g = b = lNorm;
|
|
14
|
+
} else {
|
|
15
|
+
const hue2rgb = (p, q, t) => {
|
|
16
|
+
if (t < 0) t += 1;
|
|
17
|
+
if (t > 1) t -= 1;
|
|
18
|
+
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
|
19
|
+
if (t < 1 / 2) return q;
|
|
20
|
+
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
|
21
|
+
return p;
|
|
22
|
+
};
|
|
23
|
+
const q = lNorm < 0.5 ? lNorm * (1 + sNorm) : lNorm + sNorm - lNorm * sNorm;
|
|
24
|
+
const p = 2 * lNorm - q;
|
|
25
|
+
r = hue2rgb(p, q, hNorm + 1 / 3);
|
|
26
|
+
g = hue2rgb(p, q, hNorm);
|
|
27
|
+
b = hue2rgb(p, q, hNorm - 1 / 3);
|
|
28
|
+
}
|
|
29
|
+
const toHex = x => {
|
|
30
|
+
const hex = Math.round(x * 255).toString(16);
|
|
31
|
+
return hex.length === 1 ? '0' + hex : hex;
|
|
32
|
+
};
|
|
33
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
34
|
+
}
|
|
35
|
+
function getColorForDepth(depth) {
|
|
36
|
+
const hue = (HUE_START + depth * GOLDEN_ANGLE) % 360;
|
|
37
|
+
return hslToHex(hue, SATURATION, LIGHTNESS);
|
|
38
|
+
}
|
|
39
|
+
function getRandomColor() {
|
|
40
|
+
const hue = Math.random() * 360;
|
|
41
|
+
return hslToHex(hue, SATURATION, LIGHTNESS);
|
|
42
|
+
}
|
|
43
|
+
function generateColorPalette(count) {
|
|
44
|
+
const colors = [];
|
|
45
|
+
for (let i = 0; i < count; i++) {
|
|
46
|
+
colors.push(getColorForDepth(i));
|
|
47
|
+
}
|
|
48
|
+
return colors;
|
|
49
|
+
}
|
|
50
|
+
const PREDEFINED_PALETTE = ['#FF5733', '#33FF57', '#3357FF', '#FF33F5', '#F5FF33', '#33FFF5', '#FF8333', '#8333FF', '#33FF83', '#FF3383'];
|
|
51
|
+
function getColorFromPalette(depth) {
|
|
52
|
+
return PREDEFINED_PALETTE[depth % PREDEFINED_PALETTE.length];
|
|
53
|
+
}
|
|
54
|
+
function hexToRgba(hex, alpha = 1) {
|
|
55
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
56
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
57
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
58
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
59
|
+
}
|
|
60
|
+
function hexToProcessColor(hex) {
|
|
61
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
62
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
63
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
64
|
+
const a = 255;
|
|
65
|
+
return a << 24 | r << 16 | g << 8 | b;
|
|
66
|
+
}
|
|
67
|
+
module.exports = {
|
|
68
|
+
getColorForDepth,
|
|
69
|
+
getRandomColor,
|
|
70
|
+
generateColorPalette,
|
|
71
|
+
getColorFromPalette,
|
|
72
|
+
hslToHex,
|
|
73
|
+
hexToRgba,
|
|
74
|
+
hexToProcessColor,
|
|
75
|
+
PREDEFINED_PALETTE
|
|
76
|
+
};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Info Extraction
|
|
3
|
+
*
|
|
4
|
+
* Extracts identifying information from React fiber nodes for display labels.
|
|
5
|
+
* Uses a priority order similar to highlight-updates:
|
|
6
|
+
* 1. testID (green)
|
|
7
|
+
* 2. nativeID (amber)
|
|
8
|
+
* 3. componentName (purple) - React component name from fiber
|
|
9
|
+
* 4. accessibilityLabel (pink)
|
|
10
|
+
* 5. displayName - Friendly name from ViewTypeMapper
|
|
11
|
+
* 6. viewType - Native class name fallback
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
"use strict";
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
getComponentDisplayName
|
|
18
|
+
} = require("./ViewTypeMapper");
|
|
19
|
+
const {
|
|
20
|
+
getNativeViewClassName,
|
|
21
|
+
getComponentName
|
|
22
|
+
} = require("./fiberTreeTraversal");
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Identifier types with their display configuration
|
|
26
|
+
*/
|
|
27
|
+
const IDENTIFIER_CONFIG = {
|
|
28
|
+
testID: {
|
|
29
|
+
label: "test",
|
|
30
|
+
color: "#10b981" // Green
|
|
31
|
+
},
|
|
32
|
+
nativeID: {
|
|
33
|
+
label: "native",
|
|
34
|
+
color: "#f59e0b" // Amber
|
|
35
|
+
},
|
|
36
|
+
component: {
|
|
37
|
+
label: "comp",
|
|
38
|
+
color: "#a855f7" // Purple
|
|
39
|
+
},
|
|
40
|
+
accessibilityLabel: {
|
|
41
|
+
label: "a11y",
|
|
42
|
+
color: "#ec4899" // Pink
|
|
43
|
+
},
|
|
44
|
+
viewType: {
|
|
45
|
+
label: "view",
|
|
46
|
+
color: "#6b7280" // Gray (fallback)
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Extracts component information from a fiber node
|
|
52
|
+
*
|
|
53
|
+
* @param {Object} fiber - The fiber node
|
|
54
|
+
* @param {Object} stateNode - The fiber's stateNode (public instance)
|
|
55
|
+
* @returns {Object} - Component info with label, type, and color
|
|
56
|
+
*/
|
|
57
|
+
function extractComponentInfo(fiber, stateNode) {
|
|
58
|
+
const props = fiber.memoizedProps || fiber.pendingProps || {};
|
|
59
|
+
|
|
60
|
+
// Get native view class name (e.g., "RCTView", "RCTText")
|
|
61
|
+
const viewType = getNativeViewClassName(stateNode) || "Unknown";
|
|
62
|
+
|
|
63
|
+
// Get friendly display name (e.g., "View", "Text")
|
|
64
|
+
const displayName = getComponentDisplayName(viewType);
|
|
65
|
+
|
|
66
|
+
// Get React component name from fiber (walks up tree to find user component)
|
|
67
|
+
const componentName = getComponentName(fiber);
|
|
68
|
+
|
|
69
|
+
// Extract identifiers from props
|
|
70
|
+
const testID = props.testID || null;
|
|
71
|
+
const nativeID = props.nativeID || null;
|
|
72
|
+
const accessibilityLabel = props.accessibilityLabel || props.accessible?.label || null;
|
|
73
|
+
|
|
74
|
+
// Extract additional accessibility props
|
|
75
|
+
const accessibilityRole = props.accessibilityRole || props.role || null;
|
|
76
|
+
const accessibilityHint = props.accessibilityHint || null;
|
|
77
|
+
const accessibilityState = props.accessibilityState || null;
|
|
78
|
+
|
|
79
|
+
// Extract style info (flatten if array)
|
|
80
|
+
let styleInfo = null;
|
|
81
|
+
if (props.style) {
|
|
82
|
+
try {
|
|
83
|
+
const flatStyle = Array.isArray(props.style) ? Object.assign({}, ...props.style.filter(Boolean)) : props.style;
|
|
84
|
+
styleInfo = flatStyle;
|
|
85
|
+
} catch (e) {
|
|
86
|
+
styleInfo = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Get fiber debug info
|
|
91
|
+
const fiberTag = fiber.tag;
|
|
92
|
+
const fiberKey = fiber.key;
|
|
93
|
+
|
|
94
|
+
// Get parent component name
|
|
95
|
+
let parentComponentName = null;
|
|
96
|
+
let parentFiber = fiber.return;
|
|
97
|
+
while (parentFiber) {
|
|
98
|
+
if (parentFiber.type && typeof parentFiber.type === "function") {
|
|
99
|
+
parentComponentName = parentFiber.type.displayName || parentFiber.type.name || null;
|
|
100
|
+
if (parentComponentName) break;
|
|
101
|
+
}
|
|
102
|
+
parentFiber = parentFiber.return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Build the info object
|
|
106
|
+
const info = {
|
|
107
|
+
viewType,
|
|
108
|
+
displayName,
|
|
109
|
+
componentName,
|
|
110
|
+
parentComponentName,
|
|
111
|
+
testID,
|
|
112
|
+
nativeID,
|
|
113
|
+
accessibilityLabel,
|
|
114
|
+
accessibilityRole,
|
|
115
|
+
accessibilityHint,
|
|
116
|
+
accessibilityState,
|
|
117
|
+
fiberTag,
|
|
118
|
+
fiberKey,
|
|
119
|
+
styleInfo,
|
|
120
|
+
// Primary identifier (following priority order)
|
|
121
|
+
primaryLabel: null,
|
|
122
|
+
primaryType: null,
|
|
123
|
+
primaryColor: null
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Determine primary label following priority order
|
|
127
|
+
// 1. testID (most specific)
|
|
128
|
+
// 2. accessibilityLabel (user-facing identifier)
|
|
129
|
+
// 3. everything else (componentName, nativeID, viewType)
|
|
130
|
+
if (testID) {
|
|
131
|
+
info.primaryLabel = testID;
|
|
132
|
+
info.primaryType = "testID";
|
|
133
|
+
info.primaryColor = IDENTIFIER_CONFIG.testID.color;
|
|
134
|
+
} else if (accessibilityLabel) {
|
|
135
|
+
info.primaryLabel = accessibilityLabel;
|
|
136
|
+
info.primaryType = "accessibilityLabel";
|
|
137
|
+
info.primaryColor = IDENTIFIER_CONFIG.accessibilityLabel.color;
|
|
138
|
+
} else if (componentName) {
|
|
139
|
+
info.primaryLabel = componentName;
|
|
140
|
+
info.primaryType = "component";
|
|
141
|
+
info.primaryColor = IDENTIFIER_CONFIG.component.color;
|
|
142
|
+
} else if (nativeID) {
|
|
143
|
+
info.primaryLabel = nativeID;
|
|
144
|
+
info.primaryType = "nativeID";
|
|
145
|
+
info.primaryColor = IDENTIFIER_CONFIG.nativeID.color;
|
|
146
|
+
} else {
|
|
147
|
+
// Fallback to display name
|
|
148
|
+
info.primaryLabel = displayName;
|
|
149
|
+
info.primaryType = "viewType";
|
|
150
|
+
info.primaryColor = IDENTIFIER_CONFIG.viewType.color;
|
|
151
|
+
}
|
|
152
|
+
return info;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Gets a short label for display (truncates long values)
|
|
157
|
+
*
|
|
158
|
+
* @param {string} label - The full label
|
|
159
|
+
* @param {number} maxLength - Maximum length (default 20)
|
|
160
|
+
* @returns {string} - Truncated label
|
|
161
|
+
*/
|
|
162
|
+
function getShortLabel(label, maxLength = 20) {
|
|
163
|
+
if (!label) return "";
|
|
164
|
+
if (label.length <= maxLength) return label;
|
|
165
|
+
return label.substring(0, maxLength - 1) + "…";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Gets the type prefix for a label (e.g., "test:", "a11y:")
|
|
170
|
+
*
|
|
171
|
+
* @param {string} type - The identifier type
|
|
172
|
+
* @returns {string} - The prefix
|
|
173
|
+
*/
|
|
174
|
+
function getLabelPrefix(type) {
|
|
175
|
+
const config = IDENTIFIER_CONFIG[type];
|
|
176
|
+
return config ? config.label + ":" : "";
|
|
177
|
+
}
|
|
178
|
+
module.exports = {
|
|
179
|
+
extractComponentInfo,
|
|
180
|
+
getShortLabel,
|
|
181
|
+
getLabelPrefix,
|
|
182
|
+
IDENTIFIER_CONFIG
|
|
183
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
let addLog = null;
|
|
4
|
+
try {
|
|
5
|
+
const debugInfo = require("./DebugInfo");
|
|
6
|
+
addLog = debugInfo.addLog;
|
|
7
|
+
} catch (e) {}
|
|
8
|
+
function measureInstance(instance) {
|
|
9
|
+
return new Promise(resolve => {
|
|
10
|
+
try {
|
|
11
|
+
let publicInstance = instance;
|
|
12
|
+
if (instance.canonical) {
|
|
13
|
+
if (instance.canonical.publicInstance) {
|
|
14
|
+
publicInstance = instance.canonical.publicInstance;
|
|
15
|
+
} else {
|
|
16
|
+
publicInstance = instance.canonical;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (typeof publicInstance.getBoundingClientRect === "function") {
|
|
20
|
+
const rect = publicInstance.getBoundingClientRect();
|
|
21
|
+
if (rect && typeof rect.x === "number" && typeof rect.y === "number" && typeof rect.width === "number" && typeof rect.height === "number" && rect.width >= 0 && rect.height >= 0) {
|
|
22
|
+
resolve({
|
|
23
|
+
x: rect.x,
|
|
24
|
+
y: rect.y,
|
|
25
|
+
width: rect.width,
|
|
26
|
+
height: rect.height
|
|
27
|
+
});
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (typeof publicInstance.measure === "function") {
|
|
32
|
+
const timeout = setTimeout(() => {
|
|
33
|
+
resolve(null);
|
|
34
|
+
}, 100);
|
|
35
|
+
publicInstance.measure((x, y, width, height, pageX, pageY) => {
|
|
36
|
+
clearTimeout(timeout);
|
|
37
|
+
if (pageX != null && pageY != null && width != null && height != null && width >= 0 && height >= 0) {
|
|
38
|
+
resolve({
|
|
39
|
+
x: pageX,
|
|
40
|
+
y: pageY,
|
|
41
|
+
width: width,
|
|
42
|
+
height: height
|
|
43
|
+
});
|
|
44
|
+
} else {
|
|
45
|
+
resolve(null);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
resolve(null);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
resolve(null);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const {
|
|
57
|
+
extractComponentInfo
|
|
58
|
+
} = require("./componentInfo");
|
|
59
|
+
async function measureInstances(instances) {
|
|
60
|
+
const measurements = await Promise.all(instances.map(async ({
|
|
61
|
+
instance,
|
|
62
|
+
fiber,
|
|
63
|
+
depth
|
|
64
|
+
}) => {
|
|
65
|
+
const rect = await measureInstance(instance);
|
|
66
|
+
if (rect) {
|
|
67
|
+
const componentInfo = extractComponentInfo(fiber, instance);
|
|
68
|
+
return {
|
|
69
|
+
...rect,
|
|
70
|
+
depth: depth,
|
|
71
|
+
componentInfo: componentInfo
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}));
|
|
76
|
+
const validMeasurements = measurements.filter(m => m != null);
|
|
77
|
+
return validMeasurements;
|
|
78
|
+
}
|
|
79
|
+
function getMeasurementCapabilities(instance) {
|
|
80
|
+
return {
|
|
81
|
+
hasFabricBoundingRect: typeof instance.getBoundingClientRect === "function",
|
|
82
|
+
hasPaperMeasure: typeof instance.measure === "function",
|
|
83
|
+
hasNode: instance.node != null
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function getMeasurementStats(instances) {
|
|
87
|
+
const stats = {
|
|
88
|
+
fabric: 0,
|
|
89
|
+
paper: 0,
|
|
90
|
+
none: 0
|
|
91
|
+
};
|
|
92
|
+
instances.forEach(({
|
|
93
|
+
instance
|
|
94
|
+
}) => {
|
|
95
|
+
const caps = getMeasurementCapabilities(instance);
|
|
96
|
+
if (caps.hasFabricBoundingRect) {
|
|
97
|
+
stats.fabric++;
|
|
98
|
+
} else if (caps.hasPaperMeasure) {
|
|
99
|
+
stats.paper++;
|
|
100
|
+
} else {
|
|
101
|
+
stats.none++;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return stats;
|
|
105
|
+
}
|
|
106
|
+
module.exports = {
|
|
107
|
+
measureInstance,
|
|
108
|
+
measureInstances,
|
|
109
|
+
getMeasurementCapabilities,
|
|
110
|
+
getMeasurementStats
|
|
111
|
+
};
|