@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.
Files changed (43) hide show
  1. package/README.md +334 -0
  2. package/lib/commonjs/debug-borders/components/DebugBordersModal.js +234 -0
  3. package/lib/commonjs/debug-borders/components/DebugBordersStandaloneOverlay.js +436 -0
  4. package/lib/commonjs/debug-borders/index.js +51 -0
  5. package/lib/commonjs/debug-borders/types.js +1 -0
  6. package/lib/commonjs/debug-borders/utils/DebugBordersManager.js +119 -0
  7. package/lib/commonjs/debug-borders/utils/ViewTypeMapper.js +264 -0
  8. package/lib/commonjs/debug-borders/utils/colorGeneration.js +76 -0
  9. package/lib/commonjs/debug-borders/utils/componentInfo.js +183 -0
  10. package/lib/commonjs/debug-borders/utils/componentMeasurement.js +111 -0
  11. package/lib/commonjs/debug-borders/utils/fiberTreeTraversal.js +309 -0
  12. package/lib/commonjs/debug-borders/utils/labelPositioning.js +202 -0
  13. package/lib/commonjs/index.js +34 -0
  14. package/lib/commonjs/package.json +1 -0
  15. package/lib/commonjs/preset.js +178 -0
  16. package/lib/module/debug-borders/components/DebugBordersModal.js +229 -0
  17. package/lib/module/debug-borders/components/DebugBordersStandaloneOverlay.js +432 -0
  18. package/lib/module/debug-borders/index.js +15 -0
  19. package/lib/module/debug-borders/types.js +1 -0
  20. package/lib/module/debug-borders/utils/DebugBordersManager.js +119 -0
  21. package/lib/module/debug-borders/utils/ViewTypeMapper.js +255 -0
  22. package/lib/module/debug-borders/utils/colorGeneration.js +76 -0
  23. package/lib/module/debug-borders/utils/componentInfo.js +183 -0
  24. package/lib/module/debug-borders/utils/componentMeasurement.js +111 -0
  25. package/lib/module/debug-borders/utils/fiberTreeTraversal.js +309 -0
  26. package/lib/module/debug-borders/utils/labelPositioning.js +202 -0
  27. package/lib/module/index.js +7 -0
  28. package/lib/module/preset.js +166 -0
  29. package/lib/typescript/debug-borders/components/DebugBordersModal.d.ts +11 -0
  30. package/lib/typescript/debug-borders/components/DebugBordersModal.d.ts.map +1 -0
  31. package/lib/typescript/debug-borders/components/DebugBordersStandaloneOverlay.d.ts +15 -0
  32. package/lib/typescript/debug-borders/components/DebugBordersStandaloneOverlay.d.ts.map +1 -0
  33. package/lib/typescript/debug-borders/index.d.ts +8 -0
  34. package/lib/typescript/debug-borders/index.d.ts.map +1 -0
  35. package/lib/typescript/debug-borders/types.d.ts +45 -0
  36. package/lib/typescript/debug-borders/types.d.ts.map +1 -0
  37. package/lib/typescript/debug-borders/utils/ViewTypeMapper.d.ts +66 -0
  38. package/lib/typescript/debug-borders/utils/ViewTypeMapper.d.ts.map +1 -0
  39. package/lib/typescript/index.d.ts +3 -0
  40. package/lib/typescript/index.d.ts.map +1 -0
  41. package/lib/typescript/preset.d.ts +108 -0
  42. package/lib/typescript/preset.d.ts.map +1 -0
  43. 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
+ };