@buoy-gg/highlight-updates 7.0.41 → 7.0.43
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 +11 -71
- package/lib/commonjs/highlight-updates/HighlightUpdatesOverlay.js +1 -281
- package/lib/commonjs/highlight-updates/components/HighlightFilterView.js +1 -1474
- package/lib/commonjs/highlight-updates/components/HighlightUpdatesModal.js +1 -641
- package/lib/commonjs/highlight-updates/components/IdentifierBadge.js +1 -273
- package/lib/commonjs/highlight-updates/components/IsolatedRenderList.js +1 -188
- package/lib/commonjs/highlight-updates/components/ModalHeaderContent.js +1 -293
- package/lib/commonjs/highlight-updates/components/RenderCauseBadge.js +1 -508
- package/lib/commonjs/highlight-updates/components/RenderDetailView.js +1 -846
- package/lib/commonjs/highlight-updates/components/RenderHistoryViewer.js +1 -915
- package/lib/commonjs/highlight-updates/components/RenderListItem.js +1 -235
- package/lib/commonjs/highlight-updates/components/RendersCopySettingsView.js +1 -469
- package/lib/commonjs/highlight-updates/components/StatsDisplay.js +1 -73
- package/lib/commonjs/highlight-updates/types/copySettings.js +1 -107
- package/lib/commonjs/highlight-updates/utils/CommitProfiler.js +1 -455
- package/lib/commonjs/highlight-updates/utils/HighlightUpdatesController.js +1 -1929
- package/lib/commonjs/highlight-updates/utils/PerformanceLogger.js +26 -359
- package/lib/commonjs/highlight-updates/utils/ProfilerInterceptor.js +1 -371
- package/lib/commonjs/highlight-updates/utils/RenderCauseDetector.js +5 -1840
- package/lib/commonjs/highlight-updates/utils/RenderTracker.js +1 -952
- package/lib/commonjs/highlight-updates/utils/ViewTypeMapper.js +1 -264
- package/lib/commonjs/highlight-updates/utils/copySettingsStorage.js +1 -32
- package/lib/commonjs/highlight-updates/utils/devtoolsComponentNames.js +1 -188
- package/lib/commonjs/highlight-updates/utils/namedComposite.js +1 -41
- package/lib/commonjs/highlight-updates/utils/ownStateChanged.js +1 -103
- package/lib/commonjs/highlight-updates/utils/rawEventEmitter.js +1 -50
- package/lib/commonjs/highlight-updates/utils/rawEventEmitter.web.js +1 -12
- package/lib/commonjs/highlight-updates/utils/renderExportFormatter.js +1 -58
- package/lib/commonjs/highlight-updates/utils/rendersExportFormatter.js +1 -485
- package/lib/commonjs/highlight-updates/utils/screenElements.js +1 -1269
- package/lib/commonjs/highlight-updates/utils/tapMatch.js +1 -83
- package/lib/commonjs/highlight-updates/utils/testIDs.js +1 -68
- package/lib/commonjs/highlight-updates/utils/touchCapture.js +1 -277
- package/lib/commonjs/index.js +1 -429
- package/lib/commonjs/preset.js +1 -278
- package/lib/commonjs/sync/highlightUpdatesSyncAdapter.js +1 -235
- package/lib/module/highlight-updates/HighlightUpdatesOverlay.js +1 -274
- package/lib/module/highlight-updates/components/HighlightFilterView.js +1 -1468
- package/lib/module/highlight-updates/components/HighlightUpdatesModal.js +1 -634
- package/lib/module/highlight-updates/components/IdentifierBadge.js +1 -265
- package/lib/module/highlight-updates/components/IsolatedRenderList.js +1 -183
- package/lib/module/highlight-updates/components/ModalHeaderContent.js +1 -288
- package/lib/module/highlight-updates/components/RenderCauseBadge.js +1 -499
- package/lib/module/highlight-updates/components/RenderDetailView.js +1 -840
- package/lib/module/highlight-updates/components/RenderHistoryViewer.js +1 -908
- package/lib/module/highlight-updates/components/RenderListItem.js +1 -230
- package/lib/module/highlight-updates/components/RendersCopySettingsView.js +1 -465
- package/lib/module/highlight-updates/components/StatsDisplay.js +1 -70
- package/lib/module/highlight-updates/types/copySettings.js +1 -102
- package/lib/module/highlight-updates/utils/CommitProfiler.js +1 -451
- package/lib/module/highlight-updates/utils/HighlightUpdatesController.js +1 -1925
- package/lib/module/highlight-updates/utils/PerformanceLogger.js +26 -353
- package/lib/module/highlight-updates/utils/ProfilerInterceptor.js +1 -358
- package/lib/module/highlight-updates/utils/RenderCauseDetector.js +5 -1830
- package/lib/module/highlight-updates/utils/RenderTracker.js +1 -949
- package/lib/module/highlight-updates/utils/ViewTypeMapper.js +1 -255
- package/lib/module/highlight-updates/utils/copySettingsStorage.js +1 -26
- package/lib/module/highlight-updates/utils/devtoolsComponentNames.js +1 -178
- package/lib/module/highlight-updates/utils/namedComposite.js +1 -36
- package/lib/module/highlight-updates/utils/ownStateChanged.js +1 -98
- package/lib/module/highlight-updates/utils/rawEventEmitter.js +1 -46
- package/lib/module/highlight-updates/utils/rawEventEmitter.web.js +1 -3
- package/lib/module/highlight-updates/utils/renderExportFormatter.js +1 -54
- package/lib/module/highlight-updates/utils/rendersExportFormatter.js +1 -478
- package/lib/module/highlight-updates/utils/screenElements.js +1 -1263
- package/lib/module/highlight-updates/utils/tapMatch.js +1 -76
- package/lib/module/highlight-updates/utils/testIDs.js +1 -60
- package/lib/module/highlight-updates/utils/touchCapture.js +1 -270
- package/lib/module/index.js +1 -130
- package/lib/module/preset.js +1 -272
- package/lib/module/sync/highlightUpdatesSyncAdapter.js +1 -230
- package/lib/web/index.mjs +28 -29
- package/package.json +7 -11
- package/lib/typescript/highlight-updates/HighlightUpdatesOverlay.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/HighlightFilterView.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/HighlightUpdatesModal.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/IdentifierBadge.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/IsolatedRenderList.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/ModalHeaderContent.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/RenderCauseBadge.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/RenderDetailView.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/RenderHistoryViewer.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/RenderListItem.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/RendersCopySettingsView.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/components/StatsDisplay.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/types/copySettings.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/CommitProfiler.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/HighlightUpdatesController.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/PerformanceLogger.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/ProfilerInterceptor.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/RenderCauseDetector.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/RenderTracker.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/ViewTypeMapper.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/copySettingsStorage.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/devtoolsComponentNames.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/namedComposite.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/ownStateChanged.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/rawEventEmitter.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/rawEventEmitter.web.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/renderExportFormatter.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/rendersExportFormatter.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/screenElements.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/tapMatch.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/testIDs.d.ts.map +0 -1
- package/lib/typescript/highlight-updates/utils/touchCapture.d.ts.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/sync/highlightUpdatesSyncAdapter.d.ts.map +0 -1
|
@@ -1,76 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Shared tap-target scoring for describe_screen / tap_element.
|
|
5
|
-
*
|
|
6
|
-
* Ranking used to be substring-on-testID only, so `tap: "ASSETS"` preferred
|
|
7
|
-
* `nav-assets-tool-test` (score 25) over a visible dial icon, and off-screen
|
|
8
|
-
* Expo Router screens (y > 1) stayed in the candidate list.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/** True when the measured center is inside the window (10% slack for home-indicator / portal hosts). */
|
|
12
|
-
export function isOnScreenTap(tap) {
|
|
13
|
-
if (!tap) return false;
|
|
14
|
-
return tap.x >= -0.1 && tap.x <= 1.1 && tap.y >= -0.1 && tap.y <= 1.1;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Point-in-window test in *points* (measureInWindow coords), with slack so
|
|
19
|
-
* the floating menu and rows clipped at the home indicator still count.
|
|
20
|
-
* Previous Expo Router screens typically measure at y > 1.2× window height.
|
|
21
|
-
*/
|
|
22
|
-
export function isRectCenterOnScreen(rect, screenW, screenH) {
|
|
23
|
-
if (!rect || screenW <= 0 || screenH <= 0) return false;
|
|
24
|
-
const cx = rect.x + rect.width / 2;
|
|
25
|
-
const cy = rect.y + rect.height / 2;
|
|
26
|
-
const slackX = screenW * 0.1;
|
|
27
|
-
const slackY = screenH * 0.1;
|
|
28
|
-
return cx >= -slackX && cx <= screenW + slackX && cy >= -slackY && cy <= screenH + slackY;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* The comparable form of a piece of text.
|
|
33
|
-
*
|
|
34
|
-
* "1,450", `1450` and "1,450 Points" are one request as far as a person is
|
|
35
|
-
* concerned. Measured on a live QA run: waits for BOTH "1,450" and 1450 failed
|
|
36
|
-
* against a balance that was on screen, because the thousands separator made
|
|
37
|
-
* every comparison miss. Lowercased, whitespace collapsed, digit-group
|
|
38
|
-
* separators dropped. A number arrives here as a number often enough that the
|
|
39
|
-
* coercion is not optional — `.trim()` on one is a crash.
|
|
40
|
-
*/
|
|
41
|
-
export function looseText(value) {
|
|
42
|
-
return String(value ?? "").toLowerCase().replace(/\s+/g, " ").replace(/(\d)[,\u00a0\u202f](?=\d{3}\b)/g, "$1").trim();
|
|
43
|
-
}
|
|
44
|
-
export function scoreTapMatch(c, params) {
|
|
45
|
-
if (params.nativeTag != null && c.nativeTag === params.nativeTag) return 1000;
|
|
46
|
-
const q = String(params.query ?? params.testID ?? "").trim().toLowerCase();
|
|
47
|
-
if (!q) return 0;
|
|
48
|
-
const fields = [c.testID, c.label, c.text, c.name].filter(Boolean).map(s => s.toLowerCase());
|
|
49
|
-
let best = 0;
|
|
50
|
-
for (const f of fields) {
|
|
51
|
-
if (f === q) best = Math.max(best, 100);else if (f.startsWith(q)) best = Math.max(best, 50);else if (f.includes(q)) best = Math.max(best, 25);
|
|
52
|
-
}
|
|
53
|
-
// Same tiers on the loose form, one notch lower so an exact hit still wins
|
|
54
|
-
// when both match. Skipped when the loose query is empty, or `includes("")`
|
|
55
|
-
// would score every candidate on the screen.
|
|
56
|
-
const looseQuery = looseText(q);
|
|
57
|
-
if (looseQuery) {
|
|
58
|
-
for (const f of fields) {
|
|
59
|
-
const loose = looseText(f);
|
|
60
|
-
if (loose === looseQuery) best = Math.max(best, 90);else if (loose.startsWith(looseQuery)) best = Math.max(best, 45);else if (loose.includes(looseQuery)) best = Math.max(best, 22);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
if (params.testID && c.testID && c.testID.toLowerCase() === params.testID.toLowerCase()) {
|
|
64
|
-
best = Math.max(best, 200);
|
|
65
|
-
}
|
|
66
|
-
if (best === 0) return 0;
|
|
67
|
-
const id = (c.testID ?? "").toLowerCase();
|
|
68
|
-
// Dial icons are the thing agents mean when they tap a tool name. (No
|
|
69
|
-
// penalties for app testID patterns — this ships in the library, and we
|
|
70
|
-
// don't know consumer apps' naming conventions.)
|
|
71
|
-
if (id.startsWith("buoy-dial-")) best += 40;
|
|
72
|
-
if (c.tap) {
|
|
73
|
-
if (isOnScreenTap(c.tap)) best += 20;else best -= 40;
|
|
74
|
-
}
|
|
75
|
-
return best;
|
|
76
|
-
}
|
|
1
|
+
"use strict";export function isOnScreenTap(t){if(!t)return false;return t.x>=-.1&&t.x<=1.1&&t.y>=-.1&&t.y<=1.1}export function isRectCenterOnScreen(t,o,s){if(!t||o<=0||s<=0)return false;const r=t.x+t.width/2;const e=t.y+t.height/2;const i=o*.1;const a=s*.1;return r>=-i&&r<=o+i&&e>=-a&&e<=s+a}export function looseText(t){return String(t??"").toLowerCase().replace(/\s+/g," ").replace(/(\d)[,\u00a0\u202f](?=\d{3}\b)/g,"$1").trim()}export function scoreTapMatch(t,o){if(o.nativeTag!=null&&t.nativeTag===o.nativeTag)return 1e3;const s=String(o.query??o.testID??"").trim().toLowerCase();if(!s)return 0;const r=[t.testID,t.label,t.text,t.name].filter(Boolean).map(n=>n.toLowerCase());let e=0;for(const n of r){if(n===s)e=Math.max(e,100);else if(n.startsWith(s))e=Math.max(e,50);else if(n.includes(s))e=Math.max(e,25)}const i=looseText(s);if(i){for(const n of r){const f=looseText(n);if(f===i)e=Math.max(e,90);else if(f.startsWith(i))e=Math.max(e,45);else if(f.includes(i))e=Math.max(e,22)}}if(o.testID&&t.testID&&t.testID.toLowerCase()===o.testID.toLowerCase()){e=Math.max(e,200)}if(e===0)return 0;const a=(t.testID??"").toLowerCase();if(a.startsWith("buoy-dial-"))e+=40;if(t.tap){if(isOnScreenTap(t.tap))e+=20;else e-=40}return e}
|
|
@@ -1,60 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Stable e2e handles for the Render Highlighter (highlight-updates).
|
|
5
|
-
*
|
|
6
|
-
* This tool's list is the hardest thing in Buoy to address, because the thing
|
|
7
|
-
* it lists is a NATIVE VIEW and the only key it has for one is the fiber's
|
|
8
|
-
* `nativeTag` — a per-session counter that changes on every launch, on every
|
|
9
|
-
* remount, and (on a dynamic screen) between two runs of the same test. A
|
|
10
|
-
* handle built from it would name a different component every time.
|
|
11
|
-
*
|
|
12
|
-
* So rows are addressed by their IDENTIFIER, in exactly the priority the list
|
|
13
|
-
* item itself uses to label them: testID → nativeID → component name →
|
|
14
|
-
* accessibility label → nativeTag. That is the same string the developer sees
|
|
15
|
-
* on the row, it is stable as long as the component is, and it is what a test
|
|
16
|
-
* can name up front. `nativeTag` remains the last resort for an anonymous host
|
|
17
|
-
* view, which no test should be naming anyway.
|
|
18
|
-
*
|
|
19
|
-
* Slug rules are mirrored in `example-dev-build/utils/renderBench.js` so the
|
|
20
|
-
* fixture and the tool agree about what a row is called; the suite's
|
|
21
|
-
* `fixture.js` spot-checks that they still do.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/** Any identifier string → a testID-safe slug. */
|
|
25
|
-
export function identifierSlug(value) {
|
|
26
|
-
return String(value).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "unknown";
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* `buoy-highlight-row-<slug>` for one row of the render list.
|
|
31
|
-
*
|
|
32
|
-
* Sub-handles hang off it: `-name`, `-count`, `-type`, `-cause`, `-identifier`,
|
|
33
|
-
* `-time`. The count is the tool's whole claim, so it gets its own handle
|
|
34
|
-
* rather than living inside the row's merged label.
|
|
35
|
-
*/
|
|
36
|
-
export function renderRowTestID(identifier) {
|
|
37
|
-
return `buoy-highlight-row-${identifierSlug(identifier)}`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* `buoy-highlight-detected-<type>-<slug>` for one chip in DETECTED ITEMS.
|
|
42
|
-
*
|
|
43
|
-
* The type is in the handle because the same string legitimately appears under
|
|
44
|
-
* two categories — a component called `Pressable` and a viewType called
|
|
45
|
-
* `Pressable` are different filters with the same name, and a suite that added
|
|
46
|
-
* the wrong one would still see "a pattern was added".
|
|
47
|
-
*/
|
|
48
|
-
export function detectedItemTestID(type, value) {
|
|
49
|
-
return `buoy-highlight-detected-${identifierSlug(type)}-${identifierSlug(value)}`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** `buoy-highlight-<mode>-chip-<type>-<slug>` for an active filter pattern. */
|
|
53
|
-
export function patternChipTestID(mode, type, value) {
|
|
54
|
-
return `buoy-highlight-${mode}-chip-${identifierSlug(type)}-${identifierSlug(value)}`;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** `buoy-highlight-setting-<key>` for a settings row's control. */
|
|
58
|
-
export function settingTestID(key) {
|
|
59
|
-
return `buoy-highlight-setting-${key}`;
|
|
60
|
-
}
|
|
1
|
+
"use strict";export function identifierSlug(t){return String(t).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"unknown"}export function renderRowTestID(t){return`buoy-highlight-row-${identifierSlug(t)}`}export function detectedItemTestID(t,e){return`buoy-highlight-detected-${identifierSlug(t)}-${identifierSlug(e)}`}export function patternChipTestID(t,e,r){return`buoy-highlight-${t}-chip-${identifierSlug(e)}-${identifierSlug(r)}`}export function settingTestID(t){return`buoy-highlight-setting-${t}`}
|
|
@@ -1,270 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* touchCapture — what a HUMAN is doing to the app, as replayable intents.
|
|
5
|
-
*
|
|
6
|
-
* This is the recording half of the pair whose playback half is `tapElement`:
|
|
7
|
-
* it watches real finger input and names each interaction in exactly the
|
|
8
|
-
* vocabulary `tapElement` searches by, so a recorded macro can be replayed
|
|
9
|
-
* without a second guess about what "that button" meant.
|
|
10
|
-
*
|
|
11
|
-
* Why RawEventEmitter and not the obvious alternatives:
|
|
12
|
-
* - A capture-phase responder on a root View would be the textbook answer, but
|
|
13
|
-
* Buoy mounts as a SIBLING of the app tree, not a parent. There is no root to
|
|
14
|
-
* wrap without changing every host app's integration.
|
|
15
|
-
* - Patching `Pressability`, or rewriting `onPress` props on the fly, breaks the
|
|
16
|
-
* moment a component re-renders (props are rebuilt every render) and misses
|
|
17
|
-
* everything driven by react-native-gesture-handler anyway.
|
|
18
|
-
* - RawEventEmitter mirrors every dispatched event before React's plugins see
|
|
19
|
-
* it, needs zero app instrumentation, and is already proven in-tree by
|
|
20
|
-
* focus-inspector's TV focus observer.
|
|
21
|
-
*
|
|
22
|
-
* Three rules the recorder above depends on:
|
|
23
|
-
*
|
|
24
|
-
* THE TARGET IS RESOLVED AT touchStart, NOT touchEnd. A press handler can
|
|
25
|
-
* navigate synchronously, so resolving after the fact names an element on the
|
|
26
|
-
* screen the app moved TO. We resolve while the finger is still down and emit
|
|
27
|
-
* when it lifts.
|
|
28
|
-
*
|
|
29
|
-
* A DRAG IS NOT A TAP. Scrolling a list produces the same touchStart the
|
|
30
|
-
* button above it does. Movement past a threshold, or an explicit
|
|
31
|
-
* touchCancel when a ScrollView steals the responder, drops the record —
|
|
32
|
-
* otherwise every recording is half scroll noise.
|
|
33
|
-
*
|
|
34
|
-
* KEYSTROKES ARE NOT INTENTS. Typing "SAVE10" fires six change events; a
|
|
35
|
-
* macro step wants the finished string. Consecutive edits to the same input
|
|
36
|
-
* collapse into the latest value as they arrive.
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
import { resolveTouchTarget } from "./screenElements";
|
|
40
|
-
import { resolveRawEventEmitter } from "./rawEventEmitter";
|
|
41
|
-
|
|
42
|
-
/** Points of finger travel past which the gesture stops being a tap. */
|
|
43
|
-
const TAP_SLOP_PT = 14;
|
|
44
|
-
/** Hold time at or past which a tap is recorded as a long-press. */
|
|
45
|
-
const LONG_PRESS_MS = 550;
|
|
46
|
-
/** A tap that outlasts this was a gesture we don't model — drop it. */
|
|
47
|
-
const MAX_TAP_MS = 4_000;
|
|
48
|
-
/** Consecutive edits to the same input within this window are one intent. */
|
|
49
|
-
const TEXT_COALESCE_MS = 8_000;
|
|
50
|
-
/** Ring buffer size. A recording longer than this is not a macro anyway. */
|
|
51
|
-
const MAX_RECORDS = 600;
|
|
52
|
-
let emitter = null;
|
|
53
|
-
let emitterResolved = false;
|
|
54
|
-
let unavailableReason = null;
|
|
55
|
-
let subscriptions = [];
|
|
56
|
-
let status = "idle";
|
|
57
|
-
let records = [];
|
|
58
|
-
let seq = 0;
|
|
59
|
-
let pending = null;
|
|
60
|
-
function getEmitter() {
|
|
61
|
-
if (emitterResolved) return emitter;
|
|
62
|
-
emitterResolved = true;
|
|
63
|
-
const resolution = resolveRawEventEmitter();
|
|
64
|
-
emitter = resolution.emitter;
|
|
65
|
-
unavailableReason = resolution.reason;
|
|
66
|
-
return emitter;
|
|
67
|
-
}
|
|
68
|
-
function num(v) {
|
|
69
|
-
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Fabric puts the touched view on `target`; `tag` is the older shape. */
|
|
73
|
-
function tagOf(event) {
|
|
74
|
-
const native = event?.nativeEvent;
|
|
75
|
-
if (!native) return null;
|
|
76
|
-
return num(native.target) ?? num(native.tag);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Touch coordinates. A touch event carries them at the top level on the
|
|
81
|
-
* synthesized event and inside `touches`/`changedTouches` on the raw one, and
|
|
82
|
-
* which of those is populated differs by platform and architecture — so read
|
|
83
|
-
* whichever answers rather than betting on one.
|
|
84
|
-
*/
|
|
85
|
-
function pointOf(event) {
|
|
86
|
-
const native = event?.nativeEvent;
|
|
87
|
-
if (!native) return null;
|
|
88
|
-
const direct = {
|
|
89
|
-
x: num(native.pageX),
|
|
90
|
-
y: num(native.pageY)
|
|
91
|
-
};
|
|
92
|
-
if (direct.x !== null && direct.y !== null) return {
|
|
93
|
-
x: direct.x,
|
|
94
|
-
y: direct.y
|
|
95
|
-
};
|
|
96
|
-
for (const key of ["changedTouches", "touches"]) {
|
|
97
|
-
const list = native[key];
|
|
98
|
-
if (Array.isArray(list) && list.length) {
|
|
99
|
-
const first = list[0];
|
|
100
|
-
const x = num(first?.pageX);
|
|
101
|
-
const y = num(first?.pageY);
|
|
102
|
-
if (x !== null && y !== null) return {
|
|
103
|
-
x,
|
|
104
|
-
y
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
function push(record) {
|
|
111
|
-
records.push({
|
|
112
|
-
...record,
|
|
113
|
-
seq: ++seq
|
|
114
|
-
});
|
|
115
|
-
if (records.length > MAX_RECORDS) records = records.slice(-MAX_RECORDS);
|
|
116
|
-
}
|
|
117
|
-
function onTouchStart(event) {
|
|
118
|
-
const tag = tagOf(event);
|
|
119
|
-
if (tag === null) return;
|
|
120
|
-
const point = pointOf(event);
|
|
121
|
-
let target = null;
|
|
122
|
-
try {
|
|
123
|
-
target = resolveTouchTarget(tag);
|
|
124
|
-
} catch {
|
|
125
|
-
// A fiber walk that throws must never break the app's touch handling.
|
|
126
|
-
}
|
|
127
|
-
pending = {
|
|
128
|
-
tag,
|
|
129
|
-
x: point?.x ?? 0,
|
|
130
|
-
y: point?.y ?? 0,
|
|
131
|
-
t: Date.now(),
|
|
132
|
-
drift: 0,
|
|
133
|
-
target
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
function onTouchMove(event) {
|
|
137
|
-
if (!pending) return;
|
|
138
|
-
const point = pointOf(event);
|
|
139
|
-
if (!point) return;
|
|
140
|
-
const dx = point.x - pending.x;
|
|
141
|
-
const dy = point.y - pending.y;
|
|
142
|
-
pending.drift = Math.max(pending.drift, Math.sqrt(dx * dx + dy * dy));
|
|
143
|
-
}
|
|
144
|
-
function onTouchEnd(event) {
|
|
145
|
-
const p = pending;
|
|
146
|
-
pending = null;
|
|
147
|
-
if (!p || !p.target) return;
|
|
148
|
-
const point = pointOf(event);
|
|
149
|
-
if (point) {
|
|
150
|
-
const dx = point.x - p.x;
|
|
151
|
-
const dy = point.y - p.y;
|
|
152
|
-
p.drift = Math.max(p.drift, Math.sqrt(dx * dx + dy * dy));
|
|
153
|
-
}
|
|
154
|
-
if (p.drift > TAP_SLOP_PT) return; // a drag, a scroll, a swipe — not a step
|
|
155
|
-
|
|
156
|
-
const held = Date.now() - p.t;
|
|
157
|
-
if (held > MAX_TAP_MS) return;
|
|
158
|
-
|
|
159
|
-
// A text input's tap is just "focus this field"; the intent is the text it
|
|
160
|
-
// ends up with, which arrives separately as a change event. Recording the
|
|
161
|
-
// focus tap too would put a step in every macro that does nothing on replay.
|
|
162
|
-
if (p.target.control === "text") return;
|
|
163
|
-
// Same for a toggle/slider: the tap and the value change are one intent, and
|
|
164
|
-
// the change event is the half that carries what it became.
|
|
165
|
-
if (p.target.control === "toggle" || p.target.control === "slider") return;
|
|
166
|
-
push({
|
|
167
|
-
t: Date.now(),
|
|
168
|
-
kind: held >= LONG_PRESS_MS ? "longPress" : "press",
|
|
169
|
-
target: p.target
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
function onTouchCancel() {
|
|
173
|
-
// A ScrollView (or any ancestor) taking the responder terminates the touch.
|
|
174
|
-
pending = null;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* `topChange` is the shared channel for "this control's value became X" —
|
|
179
|
-
* TextInput sends `text`, Switch sends `value`. Sliders arrive on their own
|
|
180
|
-
* channel. All three are the same idea: a control the user set.
|
|
181
|
-
*/
|
|
182
|
-
function onChange(event) {
|
|
183
|
-
const tag = tagOf(event);
|
|
184
|
-
if (tag === null) return;
|
|
185
|
-
const native = event.nativeEvent;
|
|
186
|
-
let kind;
|
|
187
|
-
let value;
|
|
188
|
-
if (typeof native.text === "string") {
|
|
189
|
-
kind = "text";
|
|
190
|
-
value = native.text;
|
|
191
|
-
} else if (typeof native.value === "boolean") {
|
|
192
|
-
kind = "toggle";
|
|
193
|
-
value = native.value;
|
|
194
|
-
} else if (typeof native.value === "number") {
|
|
195
|
-
kind = "slider";
|
|
196
|
-
value = native.value;
|
|
197
|
-
} else {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
const last = records[records.length - 1];
|
|
201
|
-
if (last && last.kind === kind && last.target.nativeTag === tag && Date.now() - last.t < TEXT_COALESCE_MS) {
|
|
202
|
-
// Same control, still typing/dragging: this IS the previous intent, further
|
|
203
|
-
// along. Replace rather than append, or "SAVE10" becomes six macro steps.
|
|
204
|
-
last.value = value;
|
|
205
|
-
last.t = Date.now();
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
let target = null;
|
|
209
|
-
try {
|
|
210
|
-
target = resolveTouchTarget(tag);
|
|
211
|
-
} catch {
|
|
212
|
-
/* see onTouchStart */
|
|
213
|
-
}
|
|
214
|
-
if (!target) return;
|
|
215
|
-
push({
|
|
216
|
-
t: Date.now(),
|
|
217
|
-
kind,
|
|
218
|
-
target,
|
|
219
|
-
value
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
export function startTouchCapture() {
|
|
223
|
-
if (status === "capturing") return getTouchCaptureStatus();
|
|
224
|
-
const raw = getEmitter();
|
|
225
|
-
if (!raw) {
|
|
226
|
-
status = "unavailable";
|
|
227
|
-
return getTouchCaptureStatus();
|
|
228
|
-
}
|
|
229
|
-
try {
|
|
230
|
-
subscriptions = [raw.addListener("topTouchStart", onTouchStart), raw.addListener("topTouchMove", onTouchMove), raw.addListener("topTouchEnd", onTouchEnd), raw.addListener("topTouchCancel", onTouchCancel), raw.addListener("topChange", onChange), raw.addListener("topValueChange", onChange), raw.addListener("topSlidingComplete", onChange)];
|
|
231
|
-
pending = null;
|
|
232
|
-
status = "capturing";
|
|
233
|
-
} catch (e) {
|
|
234
|
-
subscriptions = [];
|
|
235
|
-
status = "unavailable";
|
|
236
|
-
unavailableReason = e?.message ?? "addListener failed";
|
|
237
|
-
}
|
|
238
|
-
return getTouchCaptureStatus();
|
|
239
|
-
}
|
|
240
|
-
export function stopTouchCapture() {
|
|
241
|
-
subscriptions.forEach(s => {
|
|
242
|
-
try {
|
|
243
|
-
s.remove();
|
|
244
|
-
} catch {
|
|
245
|
-
/* already gone is fine */
|
|
246
|
-
}
|
|
247
|
-
});
|
|
248
|
-
subscriptions = [];
|
|
249
|
-
pending = null;
|
|
250
|
-
if (status === "capturing") status = "idle";
|
|
251
|
-
}
|
|
252
|
-
export function clearTouchCapture() {
|
|
253
|
-
records = [];
|
|
254
|
-
seq = 0;
|
|
255
|
-
}
|
|
256
|
-
export function getTouchCaptureStatus() {
|
|
257
|
-
return {
|
|
258
|
-
status,
|
|
259
|
-
reason: status === "unavailable" ? unavailableReason : null
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/** Everything recorded after `sinceSeq`, plus where the caller now is. */
|
|
264
|
-
export function readTouchCapture(sinceSeq = 0) {
|
|
265
|
-
return {
|
|
266
|
-
...getTouchCaptureStatus(),
|
|
267
|
-
records: records.filter(r => r.seq > sinceSeq),
|
|
268
|
-
seq
|
|
269
|
-
};
|
|
270
|
-
}
|
|
1
|
+
"use strict";import{resolveTouchTarget as v}from"./screenElements";import{resolveRawEventEmitter as S}from"./rawEventEmitter";const L=14;const M=550;const _=4e3;const b=8e3;const T=600;let d=null;let m=false;let p=null;let f=[];let i="idle";let l=[];let g=0;let a=null;function w(){if(m)return d;m=true;const e=S();d=e.emitter;p=e.reason;return d}function s(e){return typeof e==="number"&&Number.isFinite(e)?e:null}function C(e){const t=e?.nativeEvent;if(!t)return null;return s(t.target)??s(t.tag)}function h(e){const t=e?.nativeEvent;if(!t)return null;const n={x:s(t.pageX),y:s(t.pageY)};if(n.x!==null&&n.y!==null)return{x:n.x,y:n.y};for(const r of["changedTouches","touches"]){const o=t[r];if(Array.isArray(o)&&o.length){const u=o[0];const c=s(u?.pageX);const y=s(u?.pageY);if(c!==null&&y!==null)return{x:c,y}}}return null}function E(e){l.push({...e,seq:++g});if(l.length>T)l=l.slice(-T)}function A(e){const t=C(e);if(t===null)return;const n=h(e);let r=null;try{r=v(t)}catch{}a={tag:t,x:n?.x??0,y:n?.y??0,t:Date.now(),drift:0,target:r}}function D(e){if(!a)return;const t=h(e);if(!t)return;const n=t.x-a.x;const r=t.y-a.y;a.drift=Math.max(a.drift,Math.sqrt(n*n+r*r))}function O(e){const t=a;a=null;if(!t||!t.target)return;const n=h(e);if(n){const o=n.x-t.x;const u=n.y-t.y;t.drift=Math.max(t.drift,Math.sqrt(o*o+u*u))}if(t.drift>L)return;const r=Date.now()-t.t;if(r>_)return;if(t.target.control==="text")return;if(t.target.control==="toggle"||t.target.control==="slider")return;E({t:Date.now(),kind:r>=M?"longPress":"press",target:t.target})}function P(){a=null}function x(e){const t=C(e);if(t===null)return;const n=e.nativeEvent;let r;let o;if(typeof n.text==="string"){r="text";o=n.text}else if(typeof n.value==="boolean"){r="toggle";o=n.value}else if(typeof n.value==="number"){r="slider";o=n.value}else{return}const u=l[l.length-1];if(u&&u.kind===r&&u.target.nativeTag===t&&Date.now()-u.t<b){u.value=o;u.t=Date.now();return}let c=null;try{c=v(t)}catch{}if(!c)return;E({t:Date.now(),kind:r,target:c,value:o})}export function startTouchCapture(){if(i==="capturing")return getTouchCaptureStatus();const e=w();if(!e){i="unavailable";return getTouchCaptureStatus()}try{f=[e.addListener("topTouchStart",A),e.addListener("topTouchMove",D),e.addListener("topTouchEnd",O),e.addListener("topTouchCancel",P),e.addListener("topChange",x),e.addListener("topValueChange",x),e.addListener("topSlidingComplete",x)];a=null;i="capturing"}catch(t){f=[];i="unavailable";p=t?.message??"addListener failed"}return getTouchCaptureStatus()}export function stopTouchCapture(){f.forEach(e=>{try{e.remove()}catch{}});f=[];a=null;if(i==="capturing")i="idle"}export function clearTouchCapture(){l=[];g=0}export function getTouchCaptureStatus(){return{status:i,reason:i==="unavailable"?p:null}}export function readTouchCapture(e=0){return{...getTouchCaptureStatus(),records:l.filter(t=>t.seq>e),seq:g}}
|
package/lib/module/index.js
CHANGED
|
@@ -1,130 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @buoy-gg/highlight-updates
|
|
5
|
-
*
|
|
6
|
-
* Standalone implementation of React DevTools' "Highlight updates when components
|
|
7
|
-
* render" feature. Works without requiring DevTools to be connected.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```tsx
|
|
11
|
-
* // Toggle-only preset - tap to enable/disable highlights
|
|
12
|
-
* import { highlightUpdatesPreset } from '@buoy-gg/highlight-updates';
|
|
13
|
-
*
|
|
14
|
-
* <FloatingDevTools apps={[highlightUpdatesPreset]} />
|
|
15
|
-
*
|
|
16
|
-
* // Modal preset - full interface with filters and render list
|
|
17
|
-
* import { highlightUpdatesModalPreset } from '@buoy-gg/highlight-updates';
|
|
18
|
-
*
|
|
19
|
-
* <FloatingDevTools apps={[highlightUpdatesModalPreset]} />
|
|
20
|
-
*
|
|
21
|
-
* // Or use the standalone controller programmatically
|
|
22
|
-
* import { HighlightUpdatesController } from '@buoy-gg/highlight-updates';
|
|
23
|
-
*
|
|
24
|
-
* HighlightUpdatesController.toggle();
|
|
25
|
-
* HighlightUpdatesController.enable();
|
|
26
|
-
* HighlightUpdatesController.disable();
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
// Preset exports for FloatingDevTools integration
|
|
31
|
-
export { highlightUpdatesPreset, createHighlightUpdatesTool, highlightUpdatesModalPreset, createHighlightUpdatesModalTool } from "./preset";
|
|
32
|
-
|
|
33
|
-
// Controller export for standalone usage
|
|
34
|
-
export { default as HighlightUpdatesController } from "./highlight-updates/utils/HighlightUpdatesController";
|
|
35
|
-
|
|
36
|
-
// External sync (adapter for @buoy-gg/external-sync's useExternalSync)
|
|
37
|
-
export { highlightUpdatesSyncAdapter } from "./sync/highlightUpdatesSyncAdapter";
|
|
38
|
-
|
|
39
|
-
// Overlay component - auto-rendered by FloatingDevTools, but exported for manual usage
|
|
40
|
-
export { HighlightUpdatesOverlay } from "./highlight-updates/HighlightUpdatesOverlay";
|
|
41
|
-
|
|
42
|
-
// Profiler interceptor for debugging - captures what DevTools detects
|
|
43
|
-
export { installProfilerInterceptor, uninstallProfilerInterceptor, setComparisonCallback, isInterceptorInstalled, enableProfilerLogging, disableProfilerLogging, isLoggingEnabled } from "./highlight-updates/utils/ProfilerInterceptor";
|
|
44
|
-
|
|
45
|
-
// CommitProfiler — per-component render counts/durations over a capture window
|
|
46
|
-
export { CommitProfiler } from "./highlight-updates/utils/CommitProfiler";
|
|
47
|
-
|
|
48
|
-
// Bench "profile our own tools" mode: lets a dedicated benchmark screen
|
|
49
|
-
// include Buoy's tool UI in render capture (normally pruned wholesale).
|
|
50
|
-
// Highlight/events + perf-monitor components stay excluded regardless.
|
|
51
|
-
export { setCaptureBuoyToolRenders, isCapturingBuoyToolRenders } from "./highlight-updates/utils/devtoolsComponentNames";
|
|
52
|
-
|
|
53
|
-
// Register the render-capture provider so perf-monitor benchmarks can capture
|
|
54
|
-
// renders without depending on this package. Runs at module scope: whenever
|
|
55
|
-
// this package is installed, FloatingDevTools require()s it (including on the
|
|
56
|
-
// fresh realm after a reload-between-cases batch step), and Metro evaluates
|
|
57
|
-
// module side effects regardless of the package.json "sideEffects" hint.
|
|
58
|
-
import { setRenderCaptureProvider } from "@buoy-gg/shared-ui";
|
|
59
|
-
import { CommitProfiler as _commitProfilerForRegistry } from "./highlight-updates/utils/CommitProfiler";
|
|
60
|
-
import _controllerForRegistry from "./highlight-updates/utils/HighlightUpdatesController";
|
|
61
|
-
try {
|
|
62
|
-
setRenderCaptureProvider({
|
|
63
|
-
isSupported: _commitProfilerForRegistry.isSupported,
|
|
64
|
-
start: _commitProfilerForRegistry.startCapture,
|
|
65
|
-
stop: _commitProfilerForRegistry.stopCapture,
|
|
66
|
-
// Real-time bounding boxes (the Render Highlighter visual) for the span
|
|
67
|
-
// of a recording. Saves the user's prior overlay state and hands back a
|
|
68
|
-
// restore fn: previously ON stays ON, silent tracking (events tool) gets
|
|
69
|
-
// re-suppressed, otherwise fully disabled again.
|
|
70
|
-
startLiveHighlights: () => {
|
|
71
|
-
try {
|
|
72
|
-
const wasEnabled = _controllerForRegistry.isEnabled();
|
|
73
|
-
const wasSuppressed = _controllerForRegistry.getHighlightsSuppressed();
|
|
74
|
-
_controllerForRegistry.enable(); // idempotent; clears suppression
|
|
75
|
-
return () => {
|
|
76
|
-
try {
|
|
77
|
-
if (!wasEnabled) {
|
|
78
|
-
_controllerForRegistry.disable(); // respects background tracking
|
|
79
|
-
} else if (wasSuppressed) {
|
|
80
|
-
_controllerForRegistry.setHighlightsSuppressed(true);
|
|
81
|
-
}
|
|
82
|
-
} catch {
|
|
83
|
-
// restoring the overlay must never throw into the recorder
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
} catch {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
} catch {
|
|
92
|
-
// shared-ui too old to have the registry — capture is simply unavailable.
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// RenderTracker singleton for tracking render history
|
|
96
|
-
export { RenderTracker } from "./highlight-updates/utils/RenderTracker";
|
|
97
|
-
// Convenience export for unified events integration
|
|
98
|
-
export const onRenderEvent = callback => {
|
|
99
|
-
const {
|
|
100
|
-
RenderTracker
|
|
101
|
-
} = require("./highlight-updates/utils/RenderTracker");
|
|
102
|
-
return RenderTracker.onRenderEvent(callback);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
// RenderCauseDetector for detecting why components rendered
|
|
106
|
-
export { detectRenderCause, clearRenderCauseState, removeRenderCauseState, getRenderCauseStats,
|
|
107
|
-
// Snapshot capture for render history
|
|
108
|
-
safeCloneForHistory, capturePropsSnapshot, captureStateSnapshot } from "./highlight-updates/utils/RenderCauseDetector";
|
|
109
|
-
|
|
110
|
-
// PerformanceLogger for performance measurement and debugging
|
|
111
|
-
export { PerformanceLogger } from "./highlight-updates/utils/PerformanceLogger";
|
|
112
|
-
// ViewTypeMapper for translating native view names to component names
|
|
113
|
-
export { VIEW_TYPE_MAP, getComponentDisplayName, getNativeViewType, isKnownViewType, getAllNativeViewTypes, getAllComponentNames } from "./highlight-updates/utils/ViewTypeMapper";
|
|
114
|
-
|
|
115
|
-
// Modal components for custom integrations
|
|
116
|
-
// `HighlightToolView` is the same tool rendered inline (header bar + body +
|
|
117
|
-
// footer) instead of inside a JsModal — for hosts that show tools in a panel.
|
|
118
|
-
export { HighlightUpdatesModal, HighlightToolView } from "./highlight-updates/components/HighlightUpdatesModal";
|
|
119
|
-
export { RenderListItem } from "./highlight-updates/components/RenderListItem";
|
|
120
|
-
export { RenderDetailView } from "./highlight-updates/components/RenderDetailView";
|
|
121
|
-
export { HighlightFilterView } from "./highlight-updates/components/HighlightFilterView";
|
|
122
|
-
export { RenderCauseBadge, TwoLevelCauseBadge, CAUSE_CONFIG, COMPONENT_CAUSE_CONFIG } from "./highlight-updates/components/RenderCauseBadge";
|
|
123
|
-
export { RenderHistoryViewer, RenderHistoryFooter } from "./highlight-updates/components/RenderHistoryViewer";
|
|
124
|
-
|
|
125
|
-
// Simple JSON export for renders
|
|
126
|
-
export { generateRendersJson } from "./highlight-updates/utils/renderExportFormatter";
|
|
127
|
-
|
|
128
|
-
// e2e handle builders — exported so the example app's fixture can derive the
|
|
129
|
-
// same row handles the tool renders instead of hardcoding a second copy.
|
|
130
|
-
export { identifierSlug, renderRowTestID, detectedItemTestID, patternChipTestID, settingTestID } from "./highlight-updates/utils/testIDs";
|
|
1
|
+
"use strict";export{highlightUpdatesPreset,createHighlightUpdatesTool,highlightUpdatesModalPreset,createHighlightUpdatesModalTool}from"./preset";export{default as HighlightUpdatesController}from"./highlight-updates/utils/HighlightUpdatesController";export{highlightUpdatesSyncAdapter}from"./sync/highlightUpdatesSyncAdapter";export{HighlightUpdatesOverlay}from"./highlight-updates/HighlightUpdatesOverlay";export{installProfilerInterceptor,uninstallProfilerInterceptor,setComparisonCallback,isInterceptorInstalled,enableProfilerLogging,disableProfilerLogging,isLoggingEnabled}from"./highlight-updates/utils/ProfilerInterceptor";export{CommitProfiler}from"./highlight-updates/utils/CommitProfiler";export{setCaptureBuoyToolRenders,isCapturingBuoyToolRenders}from"./highlight-updates/utils/devtoolsComponentNames";import{setRenderCaptureProvider as i}from"@buoy-gg/shared-ui";import{CommitProfiler as o}from"./highlight-updates/utils/CommitProfiler";import e from"./highlight-updates/utils/HighlightUpdatesController";try{i({isSupported:o.isSupported,start:o.startCapture,stop:o.stopCapture,startLiveHighlights:()=>{try{const r=e.isEnabled();const t=e.getHighlightsSuppressed();e.enable();return()=>{try{if(!r){e.disable()}else if(t){e.setHighlightsSuppressed(true)}}catch{}}}catch{return null}}})}catch{}export{RenderTracker}from"./highlight-updates/utils/RenderTracker";export const onRenderEvent=r=>{const{RenderTracker:t}=require("./highlight-updates/utils/RenderTracker");return t.onRenderEvent(r)};export{detectRenderCause,clearRenderCauseState,removeRenderCauseState,getRenderCauseStats,safeCloneForHistory,capturePropsSnapshot,captureStateSnapshot}from"./highlight-updates/utils/RenderCauseDetector";export{PerformanceLogger}from"./highlight-updates/utils/PerformanceLogger";export{VIEW_TYPE_MAP,getComponentDisplayName,getNativeViewType,isKnownViewType,getAllNativeViewTypes,getAllComponentNames}from"./highlight-updates/utils/ViewTypeMapper";export{HighlightUpdatesModal,HighlightToolView}from"./highlight-updates/components/HighlightUpdatesModal";export{RenderListItem}from"./highlight-updates/components/RenderListItem";export{RenderDetailView}from"./highlight-updates/components/RenderDetailView";export{HighlightFilterView}from"./highlight-updates/components/HighlightFilterView";export{RenderCauseBadge,TwoLevelCauseBadge,CAUSE_CONFIG,COMPONENT_CAUSE_CONFIG}from"./highlight-updates/components/RenderCauseBadge";export{RenderHistoryViewer,RenderHistoryFooter}from"./highlight-updates/components/RenderHistoryViewer";export{generateRendersJson}from"./highlight-updates/utils/renderExportFormatter";export{identifierSlug,renderRowTestID,detectedItemTestID,patternChipTestID,settingTestID}from"./highlight-updates/utils/testIDs";
|