@buoy-gg/js-top 7.0.41 → 7.0.42

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 (118) hide show
  1. package/README.md +12 -71
  2. package/lib/commonjs/index.js +1 -99
  3. package/lib/commonjs/js-top/components/BusySparkline.js +1 -56
  4. package/lib/commonjs/js-top/components/JsTopHudOverlay.js +1 -79
  5. package/lib/commonjs/js-top/components/JsTopModal.js +1 -349
  6. package/lib/commonjs/js-top/components/TaskDetailView.js +1 -330
  7. package/lib/commonjs/js-top/components/TaskTable.js +1 -360
  8. package/lib/commonjs/js-top/engine/JsTopController.js +1 -350
  9. package/lib/commonjs/js-top/engine/aggregator.js +1 -148
  10. package/lib/commonjs/js-top/engine/busyProbe.js +1 -101
  11. package/lib/commonjs/js-top/engine/frameStack.js +1 -133
  12. package/lib/commonjs/js-top/engine/longtasks.js +1 -141
  13. package/lib/commonjs/js-top/engine/now.js +1 -38
  14. package/lib/commonjs/js-top/engine/originRegistry.js +1 -402
  15. package/lib/commonjs/js-top/engine/patches/bridge.js +1 -60
  16. package/lib/commonjs/js-top/engine/patches/microtasks.js +1 -27
  17. package/lib/commonjs/js-top/engine/patches/promises.js +1 -65
  18. package/lib/commonjs/js-top/engine/patches/timers.js +1 -66
  19. package/lib/commonjs/js-top/engine/state.js +1 -63
  20. package/lib/commonjs/js-top/engine/symbolicate.js +1 -95
  21. package/lib/commonjs/js-top/sync/jsTopSyncAdapter.js +1 -74
  22. package/lib/commonjs/js-top/types/index.js +1 -46
  23. package/lib/commonjs/js-top/utils/preferences.js +1 -31
  24. package/lib/commonjs/preset.js +1 -75
  25. package/lib/module/index.js +1 -49
  26. package/lib/module/js-top/components/BusySparkline.js +1 -52
  27. package/lib/module/js-top/components/JsTopHudOverlay.js +1 -75
  28. package/lib/module/js-top/components/JsTopModal.js +1 -345
  29. package/lib/module/js-top/components/TaskDetailView.js +1 -326
  30. package/lib/module/js-top/components/TaskTable.js +1 -353
  31. package/lib/module/js-top/engine/JsTopController.js +1 -347
  32. package/lib/module/js-top/engine/aggregator.js +1 -136
  33. package/lib/module/js-top/engine/busyProbe.js +1 -94
  34. package/lib/module/js-top/engine/frameStack.js +1 -126
  35. package/lib/module/js-top/engine/longtasks.js +1 -133
  36. package/lib/module/js-top/engine/now.js +1 -33
  37. package/lib/module/js-top/engine/originRegistry.js +1 -388
  38. package/lib/module/js-top/engine/patches/bridge.js +1 -56
  39. package/lib/module/js-top/engine/patches/microtasks.js +1 -23
  40. package/lib/module/js-top/engine/patches/promises.js +1 -62
  41. package/lib/module/js-top/engine/patches/timers.js +1 -62
  42. package/lib/module/js-top/engine/state.js +1 -54
  43. package/lib/module/js-top/engine/symbolicate.js +1 -91
  44. package/lib/module/js-top/sync/jsTopSyncAdapter.js +1 -70
  45. package/lib/module/js-top/types/index.js +1 -42
  46. package/lib/module/js-top/utils/preferences.js +1 -26
  47. package/lib/module/preset.js +1 -71
  48. package/lib/web/index.mjs +2 -3
  49. package/package.json +2 -2
  50. package/lib/commonjs/index.js.map +0 -1
  51. package/lib/commonjs/js-top/components/BusySparkline.js.map +0 -1
  52. package/lib/commonjs/js-top/components/JsTopHudOverlay.js.map +0 -1
  53. package/lib/commonjs/js-top/components/JsTopModal.js.map +0 -1
  54. package/lib/commonjs/js-top/components/TaskDetailView.js.map +0 -1
  55. package/lib/commonjs/js-top/components/TaskTable.js.map +0 -1
  56. package/lib/commonjs/js-top/engine/JsTopController.js.map +0 -1
  57. package/lib/commonjs/js-top/engine/aggregator.js.map +0 -1
  58. package/lib/commonjs/js-top/engine/busyProbe.js.map +0 -1
  59. package/lib/commonjs/js-top/engine/frameStack.js.map +0 -1
  60. package/lib/commonjs/js-top/engine/longtasks.js.map +0 -1
  61. package/lib/commonjs/js-top/engine/now.js.map +0 -1
  62. package/lib/commonjs/js-top/engine/originRegistry.js.map +0 -1
  63. package/lib/commonjs/js-top/engine/patches/bridge.js.map +0 -1
  64. package/lib/commonjs/js-top/engine/patches/microtasks.js.map +0 -1
  65. package/lib/commonjs/js-top/engine/patches/promises.js.map +0 -1
  66. package/lib/commonjs/js-top/engine/patches/timers.js.map +0 -1
  67. package/lib/commonjs/js-top/engine/state.js.map +0 -1
  68. package/lib/commonjs/js-top/engine/symbolicate.js.map +0 -1
  69. package/lib/commonjs/js-top/sync/jsTopSyncAdapter.js.map +0 -1
  70. package/lib/commonjs/js-top/types/index.js.map +0 -1
  71. package/lib/commonjs/js-top/utils/preferences.js.map +0 -1
  72. package/lib/commonjs/preset.js.map +0 -1
  73. package/lib/module/index.js.map +0 -1
  74. package/lib/module/js-top/components/BusySparkline.js.map +0 -1
  75. package/lib/module/js-top/components/JsTopHudOverlay.js.map +0 -1
  76. package/lib/module/js-top/components/JsTopModal.js.map +0 -1
  77. package/lib/module/js-top/components/TaskDetailView.js.map +0 -1
  78. package/lib/module/js-top/components/TaskTable.js.map +0 -1
  79. package/lib/module/js-top/engine/JsTopController.js.map +0 -1
  80. package/lib/module/js-top/engine/aggregator.js.map +0 -1
  81. package/lib/module/js-top/engine/busyProbe.js.map +0 -1
  82. package/lib/module/js-top/engine/frameStack.js.map +0 -1
  83. package/lib/module/js-top/engine/longtasks.js.map +0 -1
  84. package/lib/module/js-top/engine/now.js.map +0 -1
  85. package/lib/module/js-top/engine/originRegistry.js.map +0 -1
  86. package/lib/module/js-top/engine/patches/bridge.js.map +0 -1
  87. package/lib/module/js-top/engine/patches/microtasks.js.map +0 -1
  88. package/lib/module/js-top/engine/patches/promises.js.map +0 -1
  89. package/lib/module/js-top/engine/patches/timers.js.map +0 -1
  90. package/lib/module/js-top/engine/state.js.map +0 -1
  91. package/lib/module/js-top/engine/symbolicate.js.map +0 -1
  92. package/lib/module/js-top/sync/jsTopSyncAdapter.js.map +0 -1
  93. package/lib/module/js-top/types/index.js.map +0 -1
  94. package/lib/module/js-top/utils/preferences.js.map +0 -1
  95. package/lib/module/preset.js.map +0 -1
  96. package/lib/typescript/index.d.ts.map +0 -1
  97. package/lib/typescript/js-top/components/BusySparkline.d.ts.map +0 -1
  98. package/lib/typescript/js-top/components/JsTopHudOverlay.d.ts.map +0 -1
  99. package/lib/typescript/js-top/components/JsTopModal.d.ts.map +0 -1
  100. package/lib/typescript/js-top/components/TaskDetailView.d.ts.map +0 -1
  101. package/lib/typescript/js-top/components/TaskTable.d.ts.map +0 -1
  102. package/lib/typescript/js-top/engine/JsTopController.d.ts.map +0 -1
  103. package/lib/typescript/js-top/engine/aggregator.d.ts.map +0 -1
  104. package/lib/typescript/js-top/engine/busyProbe.d.ts.map +0 -1
  105. package/lib/typescript/js-top/engine/frameStack.d.ts.map +0 -1
  106. package/lib/typescript/js-top/engine/longtasks.d.ts.map +0 -1
  107. package/lib/typescript/js-top/engine/now.d.ts.map +0 -1
  108. package/lib/typescript/js-top/engine/originRegistry.d.ts.map +0 -1
  109. package/lib/typescript/js-top/engine/patches/bridge.d.ts.map +0 -1
  110. package/lib/typescript/js-top/engine/patches/microtasks.d.ts.map +0 -1
  111. package/lib/typescript/js-top/engine/patches/promises.d.ts.map +0 -1
  112. package/lib/typescript/js-top/engine/patches/timers.d.ts.map +0 -1
  113. package/lib/typescript/js-top/engine/state.d.ts.map +0 -1
  114. package/lib/typescript/js-top/engine/symbolicate.d.ts.map +0 -1
  115. package/lib/typescript/js-top/sync/jsTopSyncAdapter.d.ts.map +0 -1
  116. package/lib/typescript/js-top/types/index.d.ts.map +0 -1
  117. package/lib/typescript/js-top/utils/preferences.d.ts.map +0 -1
  118. package/lib/typescript/preset.d.ts.map +0 -1
@@ -1,349 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.JsTopModal = JsTopModal;
7
- var _react = require("react");
8
- var _reactNative = require("react-native");
9
- var _sharedUi = require("@buoy-gg/shared-ui");
10
- var _JsTopController = require("../engine/JsTopController");
11
- var _BusySparkline = require("./BusySparkline");
12
- var _TaskTable = require("./TaskTable");
13
- var _TaskDetailView = require("./TaskDetailView");
14
- var _jsxRuntime = require("react/jsx-runtime");
15
- /**
16
- * JS TOP modal — the Task Manager window.
17
- *
18
- * Layout: header (busy% pill + pause/clear controls) → busy sparkline →
19
- * coverage banner (when bridge tier is unavailable) → ranked task table →
20
- * blocking-task list.
21
- *
22
- * Data source is the local JsTopController by default. The desktop
23
- * dashboard mounts this same component via react-native-web and injects the
24
- * synced device snapshot + remote actions through `remoteSnapshot` /
25
- * `remoteActions` — the modal never samples the Electron renderer.
26
- */
27
-
28
- function busyColor(pct) {
29
- if (pct >= 80) return _sharedUi.macOSColors.semantic.error;
30
- if (pct >= 40) return _sharedUi.macOSColors.semantic.warning;
31
- return _sharedUi.macOSColors.semantic.success;
32
- }
33
-
34
- /** ≥100ms is a dropped-tap-level freeze — escalate to red. */
35
- function freezeColor(worstMs) {
36
- return worstMs >= 100 ? _sharedUi.macOSColors.semantic.error : _sharedUi.macOSColors.semantic.warning;
37
- }
38
-
39
- /**
40
- * The one-line answer to "what should I look at?" — rendered above the
41
- * table so triage never requires reading it. Priority: a named culprit >
42
- * freezes > saturated-by-UI-work > healthy.
43
- */
44
- function diagnose(s) {
45
- const culprit = s.rows.find(r => r.api !== "unattributed" && r.api !== "other");
46
- if (culprit && culprit.pctOfBusy >= 25 && s.busyPct >= 15) {
47
- return {
48
- color: culprit.pctOfBusy >= 50 ? _sharedUi.macOSColors.semantic.error : _sharedUi.macOSColors.semantic.warning,
49
- icon: "▲",
50
- text: `${culprit.label} is eating ${Math.round(culprit.pctOfBusy)}% of thread time — start there.`
51
- };
52
- }
53
- if (s.freezeSummary.count > 0) {
54
- return {
55
- color: freezeColor(s.freezeSummary.worstMs),
56
- icon: "▲",
57
- text: `${s.freezeSummary.count} freeze${s.freezeSummary.count === 1 ? "" : "s"} in the last 60s (worst ${s.freezeSummary.worstMs}ms) — check rows marked ⚠.`
58
- };
59
- }
60
- if (s.busyPct >= 80) {
61
- return {
62
- color: _sharedUi.macOSColors.semantic.warning,
63
- icon: "▲",
64
- text: "Thread saturated by UI/React work — open Highlight Updates to find re-renders."
65
- };
66
- }
67
- return {
68
- color: _sharedUi.macOSColors.semantic.success,
69
- icon: "●",
70
- text: `Thread healthy at ${Math.round(s.busyPct)}% load — nothing worth chasing.`
71
- };
72
- }
73
- function JsTopModal({
74
- visible,
75
- onClose,
76
- onBack,
77
- onMinimize,
78
- initialModalState,
79
- minimizeTargetPosition,
80
- remoteSnapshot,
81
- remoteActions,
82
- embedded = false
83
- }) {
84
- const isRemote = remoteSnapshot !== undefined;
85
- const [localSnapshot, setLocalSnapshot] = (0, _react.useState)(null);
86
-
87
- // Local mode: subscribing is what starts the engine (and unsubscribing on
88
- // close is what stops it — zero overhead when the window isn't open).
89
- (0, _react.useEffect)(() => {
90
- if (isRemote || !visible) return;
91
- return _JsTopController.JsTopController.subscribe(setLocalSnapshot);
92
- }, [isRemote, visible]);
93
- const snapshot = isRemote ? remoteSnapshot : localSnapshot;
94
- const actions = (0, _react.useMemo)(() => remoteActions ?? {
95
- pause: () => _JsTopController.JsTopController.pause(),
96
- resume: () => _JsTopController.JsTopController.resume(),
97
- clear: () => _JsTopController.JsTopController.clear()
98
- }, [remoteActions]);
99
- const paused = snapshot?.paused ?? false;
100
- const hasData = (snapshot?.rows.length ?? 0) > 0;
101
-
102
- // Tap-through detail. Local mode re-pulls the detail on every snapshot
103
- // tick (this component re-renders), so the detail view stays live.
104
- // Remote mode (desktop) has no local engine — rows aren't tappable there.
105
- const [detailKey, setDetailKey] = (0, _react.useState)(null);
106
- const onSelectRow = (0, _react.useCallback)(row => setDetailKey(row.key), []);
107
- const detail = !isRemote && detailKey ? _JsTopController.JsTopController.getOriginDetail(detailKey) : null;
108
- const inDetail = detailKey !== null;
109
-
110
- // Shared ModalHeader compound — same structure as Network/Events/Console:
111
- // Content (brand icon + title + live busy pill) and 32px icon Actions.
112
- // In the detail view the chevron pops back to the table.
113
- const headerContent = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
114
- children: [inDetail ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
115
- onBack: () => setDetailKey(null)
116
- }) : onBack ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
117
- onBack: onBack
118
- }) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
119
- title: "",
120
- noMargin: true,
121
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
122
- style: styles.titleRow,
123
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Activity, {
124
- size: 14,
125
- color: "#34D399"
126
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
127
- style: styles.title,
128
- children: "JS Top"
129
- }), snapshot && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
130
- style: [styles.busyPill, {
131
- borderColor: busyColor(snapshot.busyPct)
132
- }],
133
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
134
- style: [styles.busyText, {
135
- color: busyColor(snapshot.busyPct)
136
- }],
137
- children: [snapshot.busyPct.toFixed(0), "% BUSY"]
138
- })
139
- }), snapshot && snapshot.freezeSummary.count > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
140
- style: [styles.busyPill, {
141
- borderColor: freezeColor(snapshot.freezeSummary.worstMs)
142
- }],
143
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
144
- style: [styles.busyText, {
145
- color: freezeColor(snapshot.freezeSummary.worstMs)
146
- }],
147
- children: ["\u26A0 ", snapshot.freezeSummary.count, " \xB7", " ", snapshot.freezeSummary.worstMs, "ms"]
148
- })
149
- })]
150
- })
151
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions, {
152
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
153
- onPress: paused ? actions.resume : actions.pause,
154
- style: [styles.actionBtn, paused && styles.actionBtnActive],
155
- accessibilityLabel: paused ? "Resume sampling" : "Pause sampling",
156
- children: paused ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Play, {
157
- size: 14,
158
- color: _sharedUi.night.color.accent
159
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Pause, {
160
- size: 14,
161
- color: _sharedUi.night.color.textSecondary
162
- })
163
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
164
- onPress: actions.clear,
165
- disabled: !hasData,
166
- style: [styles.actionBtn, !hasData && styles.actionBtnDisabled],
167
- accessibilityLabel: "Clear stats",
168
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Trash2, {
169
- size: 14,
170
- color: hasData ? _sharedUi.night.color.textTertiary : _sharedUi.night.color.textTertiary
171
- })
172
- })]
173
- })]
174
- });
175
- const body = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
176
- style: styles.body,
177
- children: inDetail ? detail ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_TaskDetailView.TaskDetailView, {
178
- detail: detail
179
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
180
- style: styles.waiting,
181
- children: "This origin is no longer tracked (cleared or evicted)."
182
- }) : snapshot ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
183
- children: [(() => {
184
- const d = diagnose(snapshot);
185
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
186
- style: [styles.diagnosis, {
187
- borderLeftColor: d.color
188
- }],
189
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
190
- style: [styles.diagnosisIcon, {
191
- color: d.color
192
- }],
193
- children: d.icon
194
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
195
- style: styles.diagnosisText,
196
- children: d.text
197
- })]
198
- });
199
- })(), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
200
- style: styles.sparklineRow,
201
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
202
- style: styles.sparklineCaption,
203
- children: "JS THREAD LOAD \xB7 LAST 30s"
204
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_BusySparkline.BusySparkline, {
205
- history: snapshot.busyHistory
206
- })]
207
- }), !snapshot.tiers.bridge && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
208
- style: styles.tierBanner,
209
- children: "\u201CSystem\u201D rows are UI/React/native work pure JS can\u2019t name \u2014 timers, rAF and Promise chains are fully attributed."
210
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_TaskTable.TaskTable, {
211
- rows: snapshot.rows,
212
- onSelectRow: isRemote ? undefined : onSelectRow
213
- })]
214
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
215
- style: styles.waiting,
216
- children: isRemote ? "Waiting for device…" : "Starting engine…"
217
- })
218
- });
219
- if (embedded) {
220
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
221
- style: styles.embeddedRoot,
222
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
223
- style: styles.embeddedHeader,
224
- children: headerContent
225
- }), body]
226
- });
227
- }
228
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.JsModal, {
229
- visible: visible,
230
- onClose: onClose,
231
- onMinimize: onMinimize,
232
- minimizeTargetPosition: minimizeTargetPosition,
233
- initialModalState: initialModalState,
234
- header: {
235
- showToggleButton: true,
236
- customContent: headerContent
237
- },
238
- persistenceKey: "buoy-js-top-modal",
239
- enablePersistence: true,
240
- initialMode: "bottomSheet",
241
- disableScrollWrapper: true,
242
- children: body
243
- });
244
- }
245
- const styles = _reactNative.StyleSheet.create({
246
- titleRow: {
247
- flexDirection: "row",
248
- alignItems: "center",
249
- gap: 8
250
- },
251
- title: {
252
- color: _sharedUi.night.color.text,
253
- fontSize: 14,
254
- fontWeight: "500"
255
- },
256
- busyPill: {
257
- borderWidth: 1,
258
- borderRadius: 4,
259
- paddingHorizontal: 6,
260
- paddingVertical: 2
261
- },
262
- busyText: {
263
- fontSize: 10,
264
- fontWeight: "700",
265
- fontVariant: ["tabular-nums"]
266
- },
267
- actionBtn: {
268
- width: 32,
269
- height: 32,
270
- borderRadius: 8,
271
- backgroundColor: _sharedUi.night.color.buttonSurface,
272
- borderWidth: 1,
273
- borderColor: _sharedUi.night.color.border,
274
- alignItems: "center",
275
- justifyContent: "center"
276
- },
277
- actionBtnActive: {
278
- backgroundColor: _sharedUi.night.color.accentSoft,
279
- borderColor: _sharedUi.night.color.accentBorderStrong
280
- },
281
- actionBtnDisabled: {
282
- opacity: 0.55
283
- },
284
- body: {
285
- flex: 1,
286
- minHeight: 0,
287
- // Transparent so JsModal's ToolBackground shows through (the modal paints
288
- // opaque base beneath it). The embedded path keeps `embeddedRoot`'s base fill.
289
- backgroundColor: "transparent"
290
- },
291
- diagnosis: {
292
- flexDirection: "row",
293
- alignItems: "center",
294
- gap: 8,
295
- marginHorizontal: 10,
296
- marginTop: 8,
297
- paddingHorizontal: 10,
298
- paddingVertical: 8,
299
- backgroundColor: _sharedUi.night.color.surface,
300
- borderRadius: 6,
301
- borderLeftWidth: 3
302
- },
303
- diagnosisIcon: {
304
- fontSize: 11,
305
- fontWeight: "700"
306
- },
307
- diagnosisText: {
308
- flex: 1,
309
- color: _sharedUi.night.color.text,
310
- fontSize: 12,
311
- lineHeight: 16
312
- },
313
- sparklineRow: {
314
- paddingHorizontal: 10,
315
- paddingVertical: 8,
316
- gap: 4
317
- },
318
- sparklineCaption: {
319
- color: _sharedUi.night.color.textTertiary,
320
- fontSize: 8,
321
- fontWeight: "700",
322
- letterSpacing: 0.5
323
- },
324
- tierBanner: {
325
- color: _sharedUi.night.color.textTertiary,
326
- fontSize: 10,
327
- paddingHorizontal: 10,
328
- paddingBottom: 6
329
- },
330
- waiting: {
331
- color: _sharedUi.night.color.textTertiary,
332
- fontSize: 12,
333
- textAlign: "center",
334
- paddingVertical: 32
335
- },
336
- embeddedRoot: {
337
- position: "absolute",
338
- top: 0,
339
- left: 0,
340
- right: 0,
341
- bottom: 0,
342
- backgroundColor: _sharedUi.macOSColors.background.base
343
- },
344
- embeddedHeader: {
345
- borderBottomWidth: 1,
346
- borderBottomColor: _sharedUi.macOSColors.border.default
347
- }
348
- });
349
- //# sourceMappingURL=JsTopModal.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.JsTopModal=JsTopModal;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _JsTopController=require("../engine/JsTopController");var _BusySparkline=require("./BusySparkline");var _TaskTable=require("./TaskTable");var _TaskDetailView=require("./TaskDetailView");var _jsxRuntime=require("react/jsx-runtime");function busyColor(e){if(e>=80)return _sharedUi.macOSColors.semantic.error;if(e>=40)return _sharedUi.macOSColors.semantic.warning;return _sharedUi.macOSColors.semantic.success}function freezeColor(e){return e>=100?_sharedUi.macOSColors.semantic.error:_sharedUi.macOSColors.semantic.warning}function diagnose(e){const r=e.rows.find(n=>n.api!=="unattributed"&&n.api!=="other");if(r&&r.pctOfBusy>=25&&e.busyPct>=15){return{color:r.pctOfBusy>=50?_sharedUi.macOSColors.semantic.error:_sharedUi.macOSColors.semantic.warning,icon:"\u25B2",text:`${r.label} is eating ${Math.round(r.pctOfBusy)}% of thread time \u2014 start there.`}}if(e.freezeSummary.count>0){return{color:freezeColor(e.freezeSummary.worstMs),icon:"\u25B2",text:`${e.freezeSummary.count} freeze${e.freezeSummary.count===1?"":"s"} in the last 60s (worst ${e.freezeSummary.worstMs}ms) \u2014 check rows marked \u26A0.`}}if(e.busyPct>=80){return{color:_sharedUi.macOSColors.semantic.warning,icon:"\u25B2",text:"Thread saturated by UI/React work \u2014 open Highlight Updates to find re-renders."}}return{color:_sharedUi.macOSColors.semantic.success,icon:"\u25CF",text:`Thread healthy at ${Math.round(e.busyPct)}% load \u2014 nothing worth chasing.`}}function JsTopModal({visible:e,onClose:r,onBack:n,onMinimize:x,initialModalState:p,minimizeTargetPosition:f,remoteSnapshot:d,remoteActions:u,embedded:S=false}){const o=d!==void 0;const[T,w]=(0,_react.useState)(null);(0,_react.useEffect)(()=>{if(o||!e)return;return _JsTopController.JsTopController.subscribe(w)},[o,e]);const t=o?d:T;const a=(0,_react.useMemo)(()=>u??{pause:()=>_JsTopController.JsTopController.pause(),resume:()=>_JsTopController.JsTopController.resume(),clear:()=>_JsTopController.JsTopController.clear()},[u]);const s=t?.paused??false;const l=(t?.rows.length??0)>0;const[c,g]=(0,_react.useState)(null);const C=(0,_react.useCallback)(i=>g(i.key),[]);const h=!o&&c?_JsTopController.JsTopController.getOriginDetail(c):null;const y=c!==null;const m=(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader,{children:[y?(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:()=>g(null)}):n?(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation,{onBack:n}):null,(0,_jsxRuntime.jsx)(_sharedUi.ModalHeader.Content,{title:"",noMargin:true,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.titleRow,children:[(0,_jsxRuntime.jsx)(_sharedUi.Activity,{size:14,color:"#34D399"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,children:"JS Top"}),t&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.busyPill,{borderColor:busyColor(t.busyPct)}],children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:[styles.busyText,{color:busyColor(t.busyPct)}],children:[t.busyPct.toFixed(0),"% BUSY"]})}),t&&t.freezeSummary.count>0&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.busyPill,{borderColor:freezeColor(t.freezeSummary.worstMs)}],children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:[styles.busyText,{color:freezeColor(t.freezeSummary.worstMs)}],children:["\u26A0 ",t.freezeSummary.count," \xB7"," ",t.freezeSummary.worstMs,"ms"]})})]})}),(0,_jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions,{children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:s?a.resume:a.pause,style:[styles.actionBtn,s&&styles.actionBtnActive],accessibilityLabel:s?"Resume sampling":"Pause sampling",children:s?(0,_jsxRuntime.jsx)(_sharedUi.Play,{size:14,color:_sharedUi.night.color.accent}):(0,_jsxRuntime.jsx)(_sharedUi.Pause,{size:14,color:_sharedUi.night.color.textSecondary})}),(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:a.clear,disabled:!l,style:[styles.actionBtn,!l&&styles.actionBtnDisabled],accessibilityLabel:"Clear stats",children:(0,_jsxRuntime.jsx)(_sharedUi.Trash2,{size:14,color:l?_sharedUi.night.color.textTertiary:_sharedUi.night.color.textTertiary})})]})]});const b=(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.body,children:y?h?(0,_jsxRuntime.jsx)(_TaskDetailView.TaskDetailView,{detail:h}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.waiting,children:"This origin is no longer tracked (cleared or evicted)."}):t?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(()=>{const i=diagnose(t);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.diagnosis,{borderLeftColor:i.color}],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.diagnosisIcon,{color:i.color}],children:i.icon}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.diagnosisText,children:i.text})]})})(),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.sparklineRow,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.sparklineCaption,children:"JS THREAD LOAD \xB7 LAST 30s"}),(0,_jsxRuntime.jsx)(_BusySparkline.BusySparkline,{history:t.busyHistory})]}),!t.tiers.bridge&&(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.tierBanner,children:"\u201CSystem\u201D rows are UI/React/native work pure JS can\u2019t name \u2014 timers, rAF and Promise chains are fully attributed."}),(0,_jsxRuntime.jsx)(_TaskTable.TaskTable,{rows:t.rows,onSelectRow:o?void 0:C})]}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.waiting,children:o?"Waiting for device\u2026":"Starting engine\u2026"})});if(S){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.embeddedRoot,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.embeddedHeader,children:m}),b]})}return(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{visible:e,onClose:r,onMinimize:x,minimizeTargetPosition:f,initialModalState:p,header:{showToggleButton:true,customContent:m},persistenceKey:"buoy-js-top-modal",enablePersistence:true,initialMode:"bottomSheet",disableScrollWrapper:true,children:b})}const styles=_reactNative.StyleSheet.create({titleRow:{flexDirection:"row",alignItems:"center",gap:8},title:{color:_sharedUi.night.color.text,fontSize:14,fontWeight:"500"},busyPill:{borderWidth:1,borderRadius:4,paddingHorizontal:6,paddingVertical:2},busyText:{fontSize:10,fontWeight:"700",fontVariant:["tabular-nums"]},actionBtn:{width:32,height:32,borderRadius:8,backgroundColor:_sharedUi.night.color.buttonSurface,borderWidth:1,borderColor:_sharedUi.night.color.border,alignItems:"center",justifyContent:"center"},actionBtnActive:{backgroundColor:_sharedUi.night.color.accentSoft,borderColor:_sharedUi.night.color.accentBorderStrong},actionBtnDisabled:{opacity:.55},body:{flex:1,minHeight:0,backgroundColor:"transparent"},diagnosis:{flexDirection:"row",alignItems:"center",gap:8,marginHorizontal:10,marginTop:8,paddingHorizontal:10,paddingVertical:8,backgroundColor:_sharedUi.night.color.surface,borderRadius:6,borderLeftWidth:3},diagnosisIcon:{fontSize:11,fontWeight:"700"},diagnosisText:{flex:1,color:_sharedUi.night.color.text,fontSize:12,lineHeight:16},sparklineRow:{paddingHorizontal:10,paddingVertical:8,gap:4},sparklineCaption:{color:_sharedUi.night.color.textTertiary,fontSize:8,fontWeight:"700",letterSpacing:.5},tierBanner:{color:_sharedUi.night.color.textTertiary,fontSize:10,paddingHorizontal:10,paddingBottom:6},waiting:{color:_sharedUi.night.color.textTertiary,fontSize:12,textAlign:"center",paddingVertical:32},embeddedRoot:{position:"absolute",top:0,left:0,right:0,bottom:0,backgroundColor:_sharedUi.macOSColors.background.base},embeddedHeader:{borderBottomWidth:1,borderBottomColor:_sharedUi.macOSColors.border.default}});