@buoy-gg/highlight-updates 7.0.35 → 7.0.38

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 (107) hide show
  1. package/README.md +28 -6
  2. package/lib/commonjs/highlight-updates/HighlightUpdatesOverlay.js +1 -281
  3. package/lib/commonjs/highlight-updates/components/HighlightFilterView.js +1 -1474
  4. package/lib/commonjs/highlight-updates/components/HighlightUpdatesModal.js +1 -641
  5. package/lib/commonjs/highlight-updates/components/IdentifierBadge.js +1 -273
  6. package/lib/commonjs/highlight-updates/components/IsolatedRenderList.js +1 -188
  7. package/lib/commonjs/highlight-updates/components/ModalHeaderContent.js +1 -293
  8. package/lib/commonjs/highlight-updates/components/RenderCauseBadge.js +1 -508
  9. package/lib/commonjs/highlight-updates/components/RenderDetailView.js +1 -846
  10. package/lib/commonjs/highlight-updates/components/RenderHistoryViewer.js +1 -915
  11. package/lib/commonjs/highlight-updates/components/RenderListItem.js +1 -235
  12. package/lib/commonjs/highlight-updates/components/RendersCopySettingsView.js +1 -466
  13. package/lib/commonjs/highlight-updates/components/StatsDisplay.js +1 -73
  14. package/lib/commonjs/highlight-updates/types/copySettings.js +1 -107
  15. package/lib/commonjs/highlight-updates/utils/CommitProfiler.js +1 -446
  16. package/lib/commonjs/highlight-updates/utils/HighlightUpdatesController.js +1 -1920
  17. package/lib/commonjs/highlight-updates/utils/PerformanceLogger.js +1 -359
  18. package/lib/commonjs/highlight-updates/utils/ProfilerInterceptor.js +1 -371
  19. package/lib/commonjs/highlight-updates/utils/RenderCauseDetector.js +1 -1840
  20. package/lib/commonjs/highlight-updates/utils/RenderTracker.js +1 -952
  21. package/lib/commonjs/highlight-updates/utils/ViewTypeMapper.js +1 -264
  22. package/lib/commonjs/highlight-updates/utils/copySettingsStorage.js +1 -32
  23. package/lib/commonjs/highlight-updates/utils/devtoolsComponentNames.js +1 -188
  24. package/lib/commonjs/highlight-updates/utils/namedComposite.js +1 -41
  25. package/lib/commonjs/highlight-updates/utils/ownStateChanged.js +1 -103
  26. package/lib/commonjs/highlight-updates/utils/rawEventEmitter.js +1 -50
  27. package/lib/commonjs/highlight-updates/utils/renderExportFormatter.js +1 -58
  28. package/lib/commonjs/highlight-updates/utils/rendersExportFormatter.js +1 -485
  29. package/lib/commonjs/highlight-updates/utils/screenElements.js +1 -1046
  30. package/lib/commonjs/highlight-updates/utils/tapMatch.js +1 -58
  31. package/lib/commonjs/highlight-updates/utils/testIDs.js +1 -68
  32. package/lib/commonjs/highlight-updates/utils/touchCapture.js +1 -277
  33. package/lib/commonjs/index.js +1 -429
  34. package/lib/commonjs/preset.js +1 -278
  35. package/lib/commonjs/sync/highlightUpdatesSyncAdapter.js +1 -235
  36. package/lib/module/highlight-updates/HighlightUpdatesOverlay.js +1 -274
  37. package/lib/module/highlight-updates/components/HighlightFilterView.js +1 -1468
  38. package/lib/module/highlight-updates/components/HighlightUpdatesModal.js +1 -634
  39. package/lib/module/highlight-updates/components/IdentifierBadge.js +1 -265
  40. package/lib/module/highlight-updates/components/IsolatedRenderList.js +1 -183
  41. package/lib/module/highlight-updates/components/ModalHeaderContent.js +1 -288
  42. package/lib/module/highlight-updates/components/RenderCauseBadge.js +1 -499
  43. package/lib/module/highlight-updates/components/RenderDetailView.js +1 -840
  44. package/lib/module/highlight-updates/components/RenderHistoryViewer.js +1 -908
  45. package/lib/module/highlight-updates/components/RenderListItem.js +1 -230
  46. package/lib/module/highlight-updates/components/RendersCopySettingsView.js +1 -462
  47. package/lib/module/highlight-updates/components/StatsDisplay.js +1 -70
  48. package/lib/module/highlight-updates/types/copySettings.js +1 -102
  49. package/lib/module/highlight-updates/utils/CommitProfiler.js +1 -442
  50. package/lib/module/highlight-updates/utils/HighlightUpdatesController.js +1 -1916
  51. package/lib/module/highlight-updates/utils/PerformanceLogger.js +1 -353
  52. package/lib/module/highlight-updates/utils/ProfilerInterceptor.js +1 -358
  53. package/lib/module/highlight-updates/utils/RenderCauseDetector.js +1 -1830
  54. package/lib/module/highlight-updates/utils/RenderTracker.js +1 -949
  55. package/lib/module/highlight-updates/utils/ViewTypeMapper.js +1 -255
  56. package/lib/module/highlight-updates/utils/copySettingsStorage.js +1 -26
  57. package/lib/module/highlight-updates/utils/devtoolsComponentNames.js +1 -178
  58. package/lib/module/highlight-updates/utils/namedComposite.js +1 -36
  59. package/lib/module/highlight-updates/utils/ownStateChanged.js +1 -98
  60. package/lib/module/highlight-updates/utils/rawEventEmitter.js +1 -46
  61. package/lib/module/highlight-updates/utils/renderExportFormatter.js +1 -54
  62. package/lib/module/highlight-updates/utils/rendersExportFormatter.js +1 -478
  63. package/lib/module/highlight-updates/utils/screenElements.js +1 -1040
  64. package/lib/module/highlight-updates/utils/tapMatch.js +1 -52
  65. package/lib/module/highlight-updates/utils/testIDs.js +1 -60
  66. package/lib/module/highlight-updates/utils/touchCapture.js +1 -270
  67. package/lib/module/index.js +1 -130
  68. package/lib/module/preset.js +1 -272
  69. package/lib/module/sync/highlightUpdatesSyncAdapter.js +1 -230
  70. package/lib/typescript/highlight-updates/utils/screenElements.d.ts +52 -1
  71. package/lib/typescript/highlight-updates/utils/tapMatch.d.ts +11 -0
  72. package/lib/typescript/sync/highlightUpdatesSyncAdapter.d.ts +1 -1
  73. package/package.json +8 -8
  74. package/lib/typescript/highlight-updates/HighlightUpdatesOverlay.d.ts.map +0 -1
  75. package/lib/typescript/highlight-updates/components/HighlightFilterView.d.ts.map +0 -1
  76. package/lib/typescript/highlight-updates/components/HighlightUpdatesModal.d.ts.map +0 -1
  77. package/lib/typescript/highlight-updates/components/IdentifierBadge.d.ts.map +0 -1
  78. package/lib/typescript/highlight-updates/components/IsolatedRenderList.d.ts.map +0 -1
  79. package/lib/typescript/highlight-updates/components/ModalHeaderContent.d.ts.map +0 -1
  80. package/lib/typescript/highlight-updates/components/RenderCauseBadge.d.ts.map +0 -1
  81. package/lib/typescript/highlight-updates/components/RenderDetailView.d.ts.map +0 -1
  82. package/lib/typescript/highlight-updates/components/RenderHistoryViewer.d.ts.map +0 -1
  83. package/lib/typescript/highlight-updates/components/RenderListItem.d.ts.map +0 -1
  84. package/lib/typescript/highlight-updates/components/RendersCopySettingsView.d.ts.map +0 -1
  85. package/lib/typescript/highlight-updates/components/StatsDisplay.d.ts.map +0 -1
  86. package/lib/typescript/highlight-updates/types/copySettings.d.ts.map +0 -1
  87. package/lib/typescript/highlight-updates/utils/CommitProfiler.d.ts.map +0 -1
  88. package/lib/typescript/highlight-updates/utils/HighlightUpdatesController.d.ts.map +0 -1
  89. package/lib/typescript/highlight-updates/utils/PerformanceLogger.d.ts.map +0 -1
  90. package/lib/typescript/highlight-updates/utils/ProfilerInterceptor.d.ts.map +0 -1
  91. package/lib/typescript/highlight-updates/utils/RenderCauseDetector.d.ts.map +0 -1
  92. package/lib/typescript/highlight-updates/utils/RenderTracker.d.ts.map +0 -1
  93. package/lib/typescript/highlight-updates/utils/ViewTypeMapper.d.ts.map +0 -1
  94. package/lib/typescript/highlight-updates/utils/copySettingsStorage.d.ts.map +0 -1
  95. package/lib/typescript/highlight-updates/utils/devtoolsComponentNames.d.ts.map +0 -1
  96. package/lib/typescript/highlight-updates/utils/namedComposite.d.ts.map +0 -1
  97. package/lib/typescript/highlight-updates/utils/ownStateChanged.d.ts.map +0 -1
  98. package/lib/typescript/highlight-updates/utils/rawEventEmitter.d.ts.map +0 -1
  99. package/lib/typescript/highlight-updates/utils/renderExportFormatter.d.ts.map +0 -1
  100. package/lib/typescript/highlight-updates/utils/rendersExportFormatter.d.ts.map +0 -1
  101. package/lib/typescript/highlight-updates/utils/screenElements.d.ts.map +0 -1
  102. package/lib/typescript/highlight-updates/utils/tapMatch.d.ts.map +0 -1
  103. package/lib/typescript/highlight-updates/utils/testIDs.d.ts.map +0 -1
  104. package/lib/typescript/highlight-updates/utils/touchCapture.d.ts.map +0 -1
  105. package/lib/typescript/index.d.ts.map +0 -1
  106. package/lib/typescript/preset.d.ts.map +0 -1
  107. package/lib/typescript/sync/highlightUpdatesSyncAdapter.d.ts.map +0 -1
@@ -1,272 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Pre-configured highlight updates tool for FloatingDevTools
5
- *
6
- * This preset provides standalone "Highlight updates when components render"
7
- * functionality. Tap the icon to toggle highlights on/off.
8
- *
9
- * The overlay is automatically rendered by FloatingDevTools when the
10
- * @buoy-gg/highlight-updates package is installed.
11
- *
12
- * Two presets available:
13
- * - highlightUpdatesPreset: Quick toggle (no modal)
14
- * - highlightUpdatesModalPreset: Full modal with filters and render list
15
- *
16
- * @example
17
- * ```tsx
18
- * import { highlightUpdatesPreset, highlightUpdatesModalPreset } from '@buoy-gg/highlight-updates';
19
- *
20
- * // Toggle-only: Just tap to enable/disable highlighting
21
- * <FloatingDevTools apps={[highlightUpdatesPreset]} />
22
- *
23
- * // Modal: Opens interface with filters, render list, and controls
24
- * <FloatingDevTools apps={[highlightUpdatesModalPreset]} />
25
- * ```
26
- */
27
-
28
- import React, { useState, useEffect, useCallback } from "react";
29
- import { HighlighterIcon, HighlightIcon as HighlightIconBase } from "@buoy-gg/floating-tools-core";
30
- import HighlightUpdatesController from "./highlight-updates/utils/HighlightUpdatesController";
31
- import { HighlightUpdatesModal } from "./highlight-updates/components/HighlightUpdatesModal";
32
-
33
- /**
34
- * Icon component that changes color based on enabled state.
35
- *
36
- * ⚠️ IMPORTANT - DO NOT MODIFY THIS COMPONENT ⚠️
37
- * This component MUST use useState and useEffect hooks to subscribe to the controller.
38
- * It is rendered as a JSX component (<IconComponent />) in FloatingMenu and DialIcon,
39
- * which allows hooks to work properly.
40
- *
41
- * If you remove the hooks or change this to read isEnabled() directly,
42
- * the icon color will NOT update when the toggle is pressed.
43
- */
44
- import { jsx as _jsx } from "react/jsx-runtime";
45
- function HighlightIcon({
46
- size
47
- }) {
48
- const [enabled, setEnabled] = useState(() => HighlightUpdatesController.isEnabled());
49
- useEffect(() => {
50
- const unsubscribe = HighlightUpdatesController.subscribe(isEnabled => {
51
- setEnabled(isEnabled);
52
- });
53
- return unsubscribe;
54
- }, []);
55
- return /*#__PURE__*/_jsx(HighlightIconBase, {
56
- size: size,
57
- color: enabled ? "#10b981" : "#6b7280"
58
- });
59
- }
60
-
61
- /**
62
- * Empty component for toggle-only tools (no modal needed)
63
- * The actual overlay is rendered by FloatingDevTools automatically
64
- */
65
- function EmptyComponent() {
66
- return null;
67
- }
68
-
69
- /**
70
- * Wrapper component for the modal that handles badge press navigation.
71
- * Registers a callback with the controller to receive badge press events
72
- * and passes the target nativeTag to the modal for deep linking.
73
- */
74
- function HighlightUpdatesModalWithBadgeNavigation(props) {
75
- const [targetNativeTag, setTargetNativeTag] = useState(null);
76
-
77
- // Register badge press callback when modal is visible
78
- useEffect(() => {
79
- if (props.visible) {
80
- // Register callback to handle badge presses
81
- HighlightUpdatesController.setBadgePressCallback(nativeTag => {
82
- setTargetNativeTag(nativeTag);
83
- });
84
- }
85
- return () => {
86
- // Clear callback when modal is closed or unmounted
87
- if (!props.visible) {
88
- HighlightUpdatesController.setBadgePressCallback(null);
89
- }
90
- };
91
- }, [props.visible]);
92
-
93
- // Clear the target after it's been handled
94
- const handleInitialNativeTagHandled = useCallback(() => {
95
- setTargetNativeTag(null);
96
- }, []);
97
- return /*#__PURE__*/_jsx(HighlightUpdatesModal, {
98
- ...props,
99
- initialNativeTag: targetNativeTag,
100
- onInitialNativeTagHandled: handleInitialNativeTagHandled
101
- });
102
- }
103
-
104
- /**
105
- * Pre-configured highlight updates tool for FloatingDevTools.
106
- * Tap the icon to toggle component render highlighting on/off.
107
- *
108
- * Features:
109
- * - Standalone implementation - no DevTools connection required
110
- * - Simple direct toggle (no modal)
111
- * - Icon changes color: gray when off, green when on
112
- * - Overlay auto-rendered by FloatingDevTools
113
- */
114
- export const highlightUpdatesPreset = {
115
- id: "highlight-updates",
116
- name: "TOGGLE HIGHLIGHT",
117
- description: "Toggle component render highlights",
118
- slot: "row",
119
- icon: HighlightIcon,
120
- component: EmptyComponent,
121
- props: {},
122
- launchMode: "toggle-only",
123
- onPress: () => {
124
- // Initialize on first press if not already initialized
125
- if (!HighlightUpdatesController.isInitialized()) {
126
- HighlightUpdatesController.initialize();
127
- }
128
- HighlightUpdatesController.toggle();
129
- // Icon updates automatically via subscription in HighlightIcon component
130
- }
131
- };
132
-
133
- /**
134
- * Create a custom highlight updates tool configuration.
135
- * Use this if you want to override default settings.
136
- *
137
- * @example
138
- * ```tsx
139
- * import { createHighlightUpdatesTool } from '@buoy-gg/highlight-updates';
140
- *
141
- * const myHighlightTool = createHighlightUpdatesTool({
142
- * name: "RENDERS",
143
- * enabledColor: "#ec4899",
144
- * disabledColor: "#9ca3af",
145
- * autoInitialize: true,
146
- * });
147
- * ```
148
- */
149
- export function createHighlightUpdatesTool(options) {
150
- const enabledColor = options?.enabledColor || "#10b981";
151
- const disabledColor = options?.disabledColor || "#6b7280";
152
-
153
- // Auto-initialize if requested
154
- if (options?.autoInitialize) {
155
- // Delay to allow DevTools to connect
156
- setTimeout(() => {
157
- HighlightUpdatesController.initialize();
158
- }, 1000);
159
- }
160
-
161
- /**
162
- * Custom icon component with hooks - rendered as JSX component.
163
- *
164
- * ⚠️ IMPORTANT - DO NOT MODIFY THIS COMPONENT ⚠️
165
- * This component MUST use useState and useEffect hooks to subscribe to the controller.
166
- * See the comment on HighlightIcon above for full explanation.
167
- */
168
- const CustomHighlightIcon = ({
169
- size
170
- }) => {
171
- const [enabled, setEnabled] = useState(() => HighlightUpdatesController.isEnabled());
172
- useEffect(() => {
173
- const unsubscribe = HighlightUpdatesController.subscribe(isEnabled => {
174
- setEnabled(isEnabled);
175
- });
176
- return unsubscribe;
177
- }, []);
178
- return /*#__PURE__*/_jsx(HighlightIconBase, {
179
- size: size,
180
- color: enabled ? enabledColor : disabledColor
181
- });
182
- };
183
- return {
184
- id: options?.id || "highlight-updates",
185
- name: options?.name || "TOGGLE HIGHLIGHT",
186
- description: options?.description || "Toggle component render highlights",
187
- slot: "row",
188
- icon: CustomHighlightIcon,
189
- component: EmptyComponent,
190
- props: {},
191
- launchMode: "toggle-only",
192
- onPress: () => {
193
- // Initialize on first press if not already initialized
194
- if (!HighlightUpdatesController.isInitialized()) {
195
- HighlightUpdatesController.initialize();
196
- }
197
- HighlightUpdatesController.toggle();
198
- // Icon updates automatically via subscription
199
- }
200
- };
201
- }
202
-
203
- /**
204
- * Modal preset for highlight updates tool.
205
- * Opens a full modal interface with:
206
- * - List of tracked component renders
207
- * - Start/Stop and Pause/Resume controls
208
- * - Clear button to reset render counts
209
- * - Search bar in navbar (expandable)
210
- * - Filter by viewType, testID, nativeID, componentName
211
- * - Tap overlay badge to jump to component detail view
212
- *
213
- * Use this preset when you want detailed render tracking and filtering.
214
- */
215
- export const highlightUpdatesModalPreset = {
216
- id: "highlight-updates-modal",
217
- name: "HIGHLIGHT",
218
- description: "View component render tracking modal",
219
- slot: "both",
220
- icon: ({
221
- size
222
- }) => /*#__PURE__*/_jsx(HighlighterIcon, {
223
- size: size
224
- }),
225
- component: HighlightUpdatesModalWithBadgeNavigation,
226
- props: {
227
- enableSharedModalDimensions: false
228
- }
229
- };
230
-
231
- /**
232
- * Create a custom highlight updates modal tool configuration.
233
- * Use this if you want to override default settings for the modal version.
234
- *
235
- * @example
236
- * ```tsx
237
- * import { createHighlightUpdatesModalTool } from '@buoy-gg/highlight-updates';
238
- *
239
- * const myRendersTool = createHighlightUpdatesModalTool({
240
- * name: "PROFILER",
241
- * enabledColor: "#8b5cf6",
242
- * disabledColor: "#9ca3af",
243
- * });
244
- * ```
245
- */
246
- export function createHighlightUpdatesModalTool(options) {
247
- const enabledColor = options?.enabledColor || "#10b981";
248
- const disabledColor = options?.disabledColor || "#6b7280";
249
-
250
- // Auto-initialize if requested
251
- if (options?.autoInitialize) {
252
- setTimeout(() => {
253
- HighlightUpdatesController.initialize();
254
- }, 1000);
255
- }
256
- return {
257
- id: options?.id || "highlight-updates-modal",
258
- name: options?.name || "HIGHLIGHT",
259
- description: options?.description || "View component render tracking modal",
260
- slot: "both",
261
- icon: ({
262
- size
263
- }) => /*#__PURE__*/_jsx(HighlighterIcon, {
264
- size: size,
265
- color: enabledColor
266
- }),
267
- component: HighlightUpdatesModalWithBadgeNavigation,
268
- props: {
269
- enableSharedModalDimensions: false
270
- }
271
- };
272
- }
1
+ "use strict";import React,{useState,useEffect,useCallback}from"react";import{HighlighterIcon,HighlightIcon as HighlightIconBase}from"@buoy-gg/floating-tools-core";import HighlightUpdatesController from"./highlight-updates/utils/HighlightUpdatesController";import{HighlightUpdatesModal}from"./highlight-updates/components/HighlightUpdatesModal";import{jsx as _jsx}from"react/jsx-runtime";function HighlightIcon({size:t}){const[i,e]=useState(()=>HighlightUpdatesController.isEnabled());return useEffect(()=>HighlightUpdatesController.subscribe(t=>{e(t)}),[]),_jsx(HighlightIconBase,{size:t,color:i?"#10b981":"#6b7280"})}function EmptyComponent(){return null}function HighlightUpdatesModalWithBadgeNavigation(t){const[i,e]=useState(null);useEffect(()=>(t.visible&&HighlightUpdatesController.setBadgePressCallback(t=>{e(t)}),()=>{t.visible||HighlightUpdatesController.setBadgePressCallback(null)}),[t.visible]);const o=useCallback(()=>{e(null)},[]);return _jsx(HighlightUpdatesModal,{...t,initialNativeTag:i,onInitialNativeTagHandled:o})}export const highlightUpdatesPreset={id:"highlight-updates",name:"TOGGLE HIGHLIGHT",description:"Toggle component render highlights",slot:"row",icon:HighlightIcon,component:EmptyComponent,props:{},launchMode:"toggle-only",onPress:()=>{HighlightUpdatesController.isInitialized()||HighlightUpdatesController.initialize(),HighlightUpdatesController.toggle()}};export function createHighlightUpdatesTool(t){const i=t?.enabledColor||"#10b981",e=t?.disabledColor||"#6b7280";return t?.autoInitialize&&setTimeout(()=>{HighlightUpdatesController.initialize()},1e3),{id:t?.id||"highlight-updates",name:t?.name||"TOGGLE HIGHLIGHT",description:t?.description||"Toggle component render highlights",slot:"row",icon:({size:t})=>{const[o,l]=useState(()=>HighlightUpdatesController.isEnabled());return useEffect(()=>HighlightUpdatesController.subscribe(t=>{l(t)}),[]),_jsx(HighlightIconBase,{size:t,color:o?i:e})},component:EmptyComponent,props:{},launchMode:"toggle-only",onPress:()=>{HighlightUpdatesController.isInitialized()||HighlightUpdatesController.initialize(),HighlightUpdatesController.toggle()}}}export const highlightUpdatesModalPreset={id:"highlight-updates-modal",name:"HIGHLIGHT",description:"View component render tracking modal",slot:"both",icon:({size:t})=>_jsx(HighlighterIcon,{size:t}),component:HighlightUpdatesModalWithBadgeNavigation,props:{enableSharedModalDimensions:!1}};export function createHighlightUpdatesModalTool(t){const i=t?.enabledColor||"#10b981";return t?.autoInitialize&&setTimeout(()=>{HighlightUpdatesController.initialize()},1e3),{id:t?.id||"highlight-updates-modal",name:t?.name||"HIGHLIGHT",description:t?.description||"View component render tracking modal",slot:"both",icon:({size:t})=>_jsx(HighlighterIcon,{size:t,color:i}),component:HighlightUpdatesModalWithBadgeNavigation,props:{enableSharedModalDimensions:!1}}}
@@ -1,230 +1 @@
1
- "use strict";
2
-
3
- import HighlightUpdatesController from "../highlight-updates/utils/HighlightUpdatesController";
4
- import { RenderTracker } from "../highlight-updates/utils/RenderTracker";
5
- import { describeScreen, tapElement, waitFor } from "../highlight-updates/utils/screenElements";
6
- import { clearTouchCapture, getTouchCaptureStatus, readTouchCapture, startTouchCapture, stopTouchCapture } from "../highlight-updates/utils/touchCapture";
7
- import { CommitProfiler } from "../highlight-updates/utils/CommitProfiler";
8
- function ensureInitialized() {
9
- if (!HighlightUpdatesController.isInitialized()) {
10
- HighlightUpdatesController.initialize();
11
- }
12
- }
13
- function toWireCause(cause) {
14
- if (!cause) return undefined;
15
- const {
16
- hookChanges: _hookChanges,
17
- ...rest
18
- } = cause;
19
- return rest;
20
- }
21
-
22
- /**
23
- * Wire-form render: keep identity + counts + last cause type, drop the
24
- * per-component history buffer (up to 20 events, and hook/prop snapshots
25
- * when those settings are on). Dashboards fetch history via getRenderDetail.
26
- */
27
- function toWireRender(render) {
28
- const {
29
- renderHistory,
30
- lastRenderCause,
31
- ...rest
32
- } = render;
33
- return {
34
- ...rest,
35
- lastRenderCause: toWireCause(lastRenderCause),
36
- historyCount: renderHistory?.length ?? 0
37
- };
38
- }
39
-
40
- /**
41
- * Deliberately serializes to test serializability, unlike the snapshot guards
42
- * elsewhere. This runs once per `getRenderDetail` — a user clicking one row —
43
- * not on the ~5x/sec snapshot, so there is no unbounded per-tick cost to
44
- * avoid. Probing with a size walk first would just traverse the whole render
45
- * before doing this anyway.
46
- */
47
- function jsonSafeRender(render) {
48
- try {
49
- JSON.stringify(render);
50
- return render;
51
- } catch {
52
- return {
53
- ...render,
54
- lastRenderCause: toWireCause(render.lastRenderCause),
55
- renderHistory: render.renderHistory?.map(event => ({
56
- ...event,
57
- capturedProps: undefined,
58
- capturedState: undefined,
59
- cause: toWireCause(event.cause) ?? event.cause
60
- }))
61
- };
62
- }
63
- }
64
-
65
- /**
66
- * Measurement window for automated callers (MCP `measure_renders`).
67
- *
68
- * Backed by CommitProfiler, NOT the RenderTracker that feeds the overlay, and
69
- * the difference is the whole point. RenderTracker tracks HOST VIEWS: ask it
70
- * why `DealRow` re-rendered and it answers about the native `View` inside it —
71
- * "props changed: accessibilityState, accessibilityValue" — which is true and
72
- * useless. CommitProfiler walks COMPOSITE fibers, so it answers about the
73
- * component you named: which of ITS props changed, whether they changed by
74
- * value or only by identity, and which parent dragged it along.
75
- *
76
- * It also touches none of the user's overlay state — no enabling, no clearing
77
- * counters someone was collecting, nothing drawn on screen. A measurement is
78
- * invisible.
79
- */
80
- function beginMeasurement() {
81
- if (!CommitProfiler.isSupported()) {
82
- return {
83
- ok: false,
84
- reason: "render capture needs a dev build with the React DevTools hook available"
85
- };
86
- }
87
- CommitProfiler.startCapture({
88
- detail: true
89
- });
90
- return {
91
- ok: true
92
- };
93
- }
94
- function endMeasurement() {
95
- return {
96
- summary: CommitProfiler.stopCapture()
97
- };
98
- }
99
-
100
- /**
101
- * Sync adapter for the highlight-updates tool, consumed by
102
- * @buoy-gg/external-sync's `useExternalSync` (structurally matches its
103
- * ToolSyncAdapter interface so this package doesn't need a dependency on it).
104
- *
105
- * The visual highlights draw on the DEVICE's UI, but the render-tracking
106
- * data (component list, render counts, causes, history) is plain data — the
107
- * snapshot carries it so the dashboard renders the real HighlightUpdatesModal
108
- * as a mirror. Mutations (toggle, freeze, clear, spotlight) come back as
109
- * actions and run on the device; spotlight even highlights the component on
110
- * the phone screen while browsing details from the desktop.
111
- *
112
- * v2: per-component `renderHistory` (and hook-change values on lastRenderCause)
113
- * stay on the device. Dashboards fetch them via `getRenderDetail`.
114
- */
115
- export const highlightUpdatesSyncAdapter = {
116
- // v3: beginMeasurement / endMeasurement — a CommitProfiler capture window
117
- // for automated callers, with per-component causes. Invisible to the user.
118
- version: 3,
119
- getSnapshot: () => ({
120
- enabled: HighlightUpdatesController.isEnabled(),
121
- frozen: HighlightUpdatesController.getFrozen(),
122
- // True while tracking but the visual boxes are hidden (screenshot tool).
123
- highlightsSuppressed: HighlightUpdatesController.getHighlightsSuppressed(),
124
- renders: RenderTracker.getRenders().map(toWireRender),
125
- trackerState: RenderTracker.getState()
126
- }),
127
- subscribe: onChange => {
128
- const unsubscribeEnabled = HighlightUpdatesController.subscribe(onChange);
129
- const unsubscribeFreeze = HighlightUpdatesController.subscribeToFreeze(onChange);
130
- const unsubscribeRenders = RenderTracker.subscribe(onChange);
131
- const unsubscribeTrackerState = RenderTracker.subscribeToState(onChange);
132
- return () => {
133
- unsubscribeEnabled();
134
- unsubscribeFreeze();
135
- unsubscribeRenders();
136
- unsubscribeTrackerState();
137
- };
138
- },
139
- actions: {
140
- // Capture window for automated callers (MCP `measure_renders`). Pairs:
141
- // begin -> drive the UI -> end. `end` always restores.
142
- beginMeasurement: () => beginMeasurement(),
143
- endMeasurement: () => endMeasurement(),
144
- /**
145
- * On-demand detail: one component's real renderHistory + lastRenderCause
146
- * (including hookChanges). Wire-form snapshots omit those.
147
- */
148
- getRenderDetail: params => {
149
- const {
150
- nativeTag
151
- } = params ?? {};
152
- if (nativeTag == null) {
153
- return {
154
- found: false,
155
- reason: "missing nativeTag"
156
- };
157
- }
158
- const render = RenderTracker.getRender(String(nativeTag));
159
- if (!render) return {
160
- found: false,
161
- reason: "unknown nativeTag"
162
- };
163
- return {
164
- found: true,
165
- nativeTag,
166
- render: jsonSafeRender(render)
167
- };
168
- },
169
- toggle: () => {
170
- ensureInitialized();
171
- HighlightUpdatesController.toggle();
172
- },
173
- setEnabled: params => {
174
- ensureInitialized();
175
- HighlightUpdatesController.setEnabled(params.enabled);
176
- },
177
- toggleFreeze: () => {
178
- HighlightUpdatesController.toggleFreeze();
179
- },
180
- clearRenderCounts: () => {
181
- HighlightUpdatesController.clearRenderCounts();
182
- },
183
- setSpotlight: params => {
184
- HighlightUpdatesController.setSpotlight(params.nativeTag);
185
- },
186
- // Resolve a component (by testID/nativeID/name/nativeTag) to a fresh
187
- // on-screen rectangle — best-effort scrolling it into view first — so the
188
- // desktop can crop a simulator screenshot to exactly that component. The
189
- // returned value (rect + scale + screen) flows back as the action result.
190
- locateComponent: params => {
191
- ensureInitialized();
192
- return HighlightUpdatesController.locateComponent(params ?? {});
193
- },
194
- // Track + measure components WITHOUT drawing the highlight boxes, so the
195
- // desktop screenshot tool can locate components with no on-device overlay.
196
- setSilentTracking: params => {
197
- ensureInitialized();
198
- HighlightUpdatesController.setSilentTracking(params.enabled ?? false);
199
- },
200
- // Walk the live fiber tree and return the current screen's meaningful /
201
- // interactive elements, each with normalized tap coordinates. Powers the
202
- // MCP `describe_screen` reader — no screenshot, no silent-tracking needed.
203
- describeScreen: () => describeScreen(),
204
- // Tap an element purely in JS: resolve it (by nativeTag / testID / query),
205
- // find the nearest onPress up its fiber chain, and invoke it with a
206
- // synthetic press event. Powers the MCP `tap_element` action.
207
- tapElement: params => tapElement(params ?? {}),
208
- // Block until an element is on screen (or gone), so a driver can act on a
209
- // screen that has finished loading instead of the skeleton that was there
210
- // when `navigate` returned. Same matcher `tapElement` ranks by.
211
- waitFor: params => waitFor(params ?? {}),
212
- // ── Touch capture: the recording half of tapElement ──────────────────
213
- // Observe what a HUMAN taps, named in the same vocabulary tapElement
214
- // searches by, so the Scenarios recorder can turn a real session into a
215
- // replayable macro. Lives here because this tool already owns the fiber
216
- // walk both halves need.
217
- startTouchCapture: () => startTouchCapture(),
218
- stopTouchCapture: () => {
219
- stopTouchCapture();
220
- return getTouchCaptureStatus();
221
- },
222
- clearTouchCapture: () => {
223
- clearTouchCapture();
224
- return {
225
- ok: true
226
- };
227
- },
228
- readTouchCapture: params => readTouchCapture(params?.sinceSeq ?? 0)
229
- }
230
- };
1
+ "use strict";import HighlightUpdatesController from"../highlight-updates/utils/HighlightUpdatesController";import{RenderTracker}from"../highlight-updates/utils/RenderTracker";import{describeScreen,tapElement,waitFor}from"../highlight-updates/utils/screenElements";import{clearTouchCapture,getTouchCaptureStatus,readTouchCapture,startTouchCapture,stopTouchCapture}from"../highlight-updates/utils/touchCapture";import{CommitProfiler}from"../highlight-updates/utils/CommitProfiler";function ensureInitialized(){HighlightUpdatesController.isInitialized()||HighlightUpdatesController.initialize()}function toWireCause(e){if(!e)return;const{hookChanges:t,...r}=e;return r}function toWireRender(e){const{renderHistory:t,lastRenderCause:r,...i}=e;return{...i,lastRenderCause:toWireCause(r),historyCount:t?.length??0}}function jsonSafeRender(e){try{return JSON.stringify(e),e}catch{return{...e,lastRenderCause:toWireCause(e.lastRenderCause),renderHistory:e.renderHistory?.map(e=>({...e,capturedProps:void 0,capturedState:void 0,cause:toWireCause(e.cause)??e.cause}))}}}function beginMeasurement(){return CommitProfiler.isSupported()?(CommitProfiler.startCapture({detail:!0}),{ok:!0}):{ok:!1,reason:"render capture needs a dev build with the React DevTools hook available"}}function endMeasurement(){return{summary:CommitProfiler.stopCapture()}}export const highlightUpdatesSyncAdapter={version:3,getSnapshot:()=>({enabled:HighlightUpdatesController.isEnabled(),frozen:HighlightUpdatesController.getFrozen(),highlightsSuppressed:HighlightUpdatesController.getHighlightsSuppressed(),renders:RenderTracker.getRenders().map(toWireRender),trackerState:RenderTracker.getState()}),subscribe:e=>{const t=HighlightUpdatesController.subscribe(e),r=HighlightUpdatesController.subscribeToFreeze(e),i=RenderTracker.subscribe(e),n=RenderTracker.subscribeToState(e);return()=>{t(),r(),i(),n()}},actions:{beginMeasurement:()=>beginMeasurement(),endMeasurement:()=>endMeasurement(),getRenderDetail:e=>{const{nativeTag:t}=e??{};if(null==t)return{found:!1,reason:"missing nativeTag"};const r=RenderTracker.getRender(String(t));return r?{found:!0,nativeTag:t,render:jsonSafeRender(r)}:{found:!1,reason:"unknown nativeTag"}},toggle:()=>{ensureInitialized(),HighlightUpdatesController.toggle()},setEnabled:e=>{ensureInitialized(),HighlightUpdatesController.setEnabled(e.enabled)},toggleFreeze:()=>{HighlightUpdatesController.toggleFreeze()},clearRenderCounts:()=>{HighlightUpdatesController.clearRenderCounts()},setSpotlight:e=>{HighlightUpdatesController.setSpotlight(e.nativeTag)},locateComponent:e=>(ensureInitialized(),HighlightUpdatesController.locateComponent(e??{})),setSilentTracking:e=>{ensureInitialized(),HighlightUpdatesController.setSilentTracking(e.enabled??!1)},describeScreen:e=>describeScreen(e??{}),tapElement:e=>tapElement(e??{}),waitFor:e=>waitFor(e??{}),startTouchCapture:()=>startTouchCapture(),stopTouchCapture:()=>(stopTouchCapture(),getTouchCaptureStatus()),clearTouchCapture:()=>(clearTouchCapture(),{ok:!0}),readTouchCapture:e=>readTouchCapture(e?.sinceSeq??0)}};
@@ -49,6 +49,14 @@ export interface ScreenElement {
49
49
  height: number;
50
50
  };
51
51
  }
52
+ export interface DescribeScreenParams {
53
+ /**
54
+ * Also list Buoy's own overlay — the dial, tool sheets, Ask Buoy's chat.
55
+ * Off by default: the screen being described is the app's, and Buoy's
56
+ * chrome echoing the caller's own words back is how taps went astray.
57
+ */
58
+ includeBuoy?: boolean;
59
+ }
52
60
  export interface DescribeScreenResult {
53
61
  screen: {
54
62
  width: number;
@@ -56,11 +64,15 @@ export interface DescribeScreenResult {
56
64
  };
57
65
  count: number;
58
66
  elements: ScreenElement[];
67
+ /** Elements under Buoy's own overlay that were left out (pass includeBuoy to see them). */
68
+ hiddenBuoy?: number;
59
69
  }
60
70
  export interface TapElementParams {
61
71
  nativeTag?: number;
62
72
  testID?: string;
63
73
  query?: string;
74
+ /** Let a fuzzy `query` match Buoy's own overlay. Exact nativeTag/testID always may. */
75
+ includeBuoy?: boolean;
64
76
  /** Scroll the target into view first if it's off-screen. Default true. */
65
77
  scrollIntoView?: boolean;
66
78
  /** Invoke the element's onLongPress instead of onPress. Fails if it has none. */
@@ -88,6 +100,26 @@ export interface TapElementResult {
88
100
  /** New value set, for toggle/slider/text controls. */
89
101
  value?: number | boolean | string;
90
102
  };
103
+ /**
104
+ * What the app did after the handler ran. `commits` is the number of React
105
+ * commits inside the settle window; 0 means the handler fired and nothing
106
+ * re-rendered — an occluded button, a no-op press, a guard that bailed.
107
+ */
108
+ effect?: {
109
+ commits: number;
110
+ observedMs: number;
111
+ };
112
+ /** Other interactive elements that matched equally well. Non-empty means the choice was a coin toss. */
113
+ alsoMatched?: Array<{
114
+ nativeTag: number | null;
115
+ name: string;
116
+ testID?: string;
117
+ text?: string;
118
+ tap?: {
119
+ x: number;
120
+ y: number;
121
+ };
122
+ }>;
91
123
  candidates?: Array<{
92
124
  nativeTag: number | null;
93
125
  name: string;
@@ -95,12 +127,14 @@ export interface TapElementResult {
95
127
  text?: string;
96
128
  }>;
97
129
  }
98
- export declare function describeScreen(): Promise<DescribeScreenResult>;
130
+ export declare function describeScreen(params?: DescribeScreenParams): Promise<DescribeScreenResult>;
99
131
  export declare function tapElement(params: TapElementParams): Promise<TapElementResult>;
100
132
  export interface WaitForParams {
101
133
  nativeTag?: number;
102
134
  testID?: string;
103
135
  query?: string;
136
+ /** Let a fuzzy `query` match Buoy's own overlay. Exact nativeTag/testID always may. */
137
+ includeBuoy?: boolean;
104
138
  /** Wait for the element to be GONE instead of present. Default false. */
105
139
  gone?: boolean;
106
140
  /** Give up after this long. Default 5000ms, capped at 30000. */
@@ -122,6 +156,23 @@ export interface WaitForResult {
122
156
  text?: string;
123
157
  interactive: boolean;
124
158
  };
159
+ /**
160
+ * What DID rank for this query on the last scan, when the wait failed.
161
+ *
162
+ * A failed wait used to say only "not on screen" — so a caller could not tell
163
+ * "nothing is called that" from "it is there but scrolled off", and the
164
+ * cheapest next move looked like another wait with different words. Measured
165
+ * on a live QA run: five consecutive waits, 99 seconds, against text that was
166
+ * on screen the whole time. Naming the near misses ends that loop in one
167
+ * result instead of five calls.
168
+ */
169
+ closest?: {
170
+ name: string;
171
+ testID?: string;
172
+ text?: string;
173
+ /** False means it matched but its measured centre is outside the window. */
174
+ onScreen: boolean;
175
+ }[];
125
176
  }
126
177
  /**
127
178
  * Block until an element appears (or disappears), then report how long it took.
@@ -38,5 +38,16 @@ export declare function isRectCenterOnScreen(rect: {
38
38
  width: number;
39
39
  height: number;
40
40
  } | null, screenW: number, screenH: number): boolean;
41
+ /**
42
+ * The comparable form of a piece of text.
43
+ *
44
+ * "1,450", `1450` and "1,450 Points" are one request as far as a person is
45
+ * concerned. Measured on a live QA run: waits for BOTH "1,450" and 1450 failed
46
+ * against a balance that was on screen, because the thousands separator made
47
+ * every comparison miss. Lowercased, whitespace collapsed, digit-group
48
+ * separators dropped. A number arrives here as a number often enough that the
49
+ * coercion is not optional — `.trim()` on one is a crash.
50
+ */
51
+ export declare function looseText(value: unknown): string;
41
52
  export declare function scoreTapMatch(c: TapMatchFields, params: TapMatchQuery): number;
42
53
  //# sourceMappingURL=tapMatch.d.ts.map
@@ -58,7 +58,7 @@ export declare const highlightUpdatesSyncAdapter: {
58
58
  setSpotlight: (params?: unknown) => void;
59
59
  locateComponent: (params?: unknown) => Promise<import("../highlight-updates/utils/HighlightUpdatesController").LocateComponentResult>;
60
60
  setSilentTracking: (params?: unknown) => void;
61
- describeScreen: () => Promise<import("../highlight-updates/utils/screenElements").DescribeScreenResult>;
61
+ describeScreen: (params?: unknown) => Promise<import("../highlight-updates/utils/screenElements").DescribeScreenResult>;
62
62
  tapElement: (params?: unknown) => Promise<import("../highlight-updates/utils/screenElements").TapElementResult>;
63
63
  waitFor: (params?: unknown) => Promise<import("../highlight-updates/utils/screenElements").WaitForResult>;
64
64
  startTouchCapture: () => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@buoy-gg/highlight-updates",
3
- "version": "7.0.35",
4
- "description": "Render highlighter for React Native — see every render with its cause: mount, state, props, or parent. Part of Buoy devtools.",
3
+ "version": "7.0.38",
4
+ "description": "Highlight observed React Native renders and inspect available render diagnostics.",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
7
7
  "types": "lib/typescript/index.d.ts",
@@ -26,14 +26,14 @@
26
26
  ],
27
27
  "sideEffects": false,
28
28
  "dependencies": {
29
- "@buoy-gg/shared-ui": "^7.0.35",
30
- "@buoy-gg/floating-tools-core": "^7.0.35"
29
+ "@buoy-gg/shared-ui": "^7.0.38",
30
+ "@buoy-gg/floating-tools-core": "^7.0.38"
31
31
  },
32
32
  "peerDependencies": {
33
- "@buoy-gg/license": "7.0.35",
33
+ "@buoy-gg/license": "7.0.38",
34
34
  "react": "*",
35
35
  "react-native": "*",
36
- "@buoy-gg/core": "^7.0.35"
36
+ "@buoy-gg/core": "^7.0.38"
37
37
  },
38
38
  "peerDependenciesMeta": {
39
39
  "@buoy-gg/core": {
@@ -44,8 +44,8 @@
44
44
  "@types/react": "^19.1.0",
45
45
  "@types/react-native": "^0.73.0",
46
46
  "typescript": "~5.8.3",
47
- "@buoy-gg/license": "^7.0.35",
48
- "@buoy-gg/core": "^7.0.35"
47
+ "@buoy-gg/core": "^7.0.38",
48
+ "@buoy-gg/license": "^7.0.38"
49
49
  },
50
50
  "react-native-builder-bob": {
51
51
  "source": "src",
@@ -1 +0,0 @@
1
- {"version":3,"file":"HighlightUpdatesOverlay.d.ts","sourceRoot":"","sources":["../../../src/highlight-updates/HighlightUpdatesOverlay.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAMN,MAAM,OAAO,CAAC;AA2Bf,UAAU,4BAA4B;IACpC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C;AAED,wBAAgB,uBAAuB,CAAC,EACtC,YAAY,GACb,GAAE,4BAAiC,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAwP/D;AA2DD,eAAe,uBAAuB,CAAC"}