@buoy-gg/highlight-updates 7.0.36 → 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 (104) 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 -1248
  30. package/lib/commonjs/highlight-updates/utils/tapMatch.js +1 -83
  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 -1242
  64. package/lib/module/highlight-updates/utils/tapMatch.js +1 -76
  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/package.json +8 -8
  71. package/lib/typescript/highlight-updates/HighlightUpdatesOverlay.d.ts.map +0 -1
  72. package/lib/typescript/highlight-updates/components/HighlightFilterView.d.ts.map +0 -1
  73. package/lib/typescript/highlight-updates/components/HighlightUpdatesModal.d.ts.map +0 -1
  74. package/lib/typescript/highlight-updates/components/IdentifierBadge.d.ts.map +0 -1
  75. package/lib/typescript/highlight-updates/components/IsolatedRenderList.d.ts.map +0 -1
  76. package/lib/typescript/highlight-updates/components/ModalHeaderContent.d.ts.map +0 -1
  77. package/lib/typescript/highlight-updates/components/RenderCauseBadge.d.ts.map +0 -1
  78. package/lib/typescript/highlight-updates/components/RenderDetailView.d.ts.map +0 -1
  79. package/lib/typescript/highlight-updates/components/RenderHistoryViewer.d.ts.map +0 -1
  80. package/lib/typescript/highlight-updates/components/RenderListItem.d.ts.map +0 -1
  81. package/lib/typescript/highlight-updates/components/RendersCopySettingsView.d.ts.map +0 -1
  82. package/lib/typescript/highlight-updates/components/StatsDisplay.d.ts.map +0 -1
  83. package/lib/typescript/highlight-updates/types/copySettings.d.ts.map +0 -1
  84. package/lib/typescript/highlight-updates/utils/CommitProfiler.d.ts.map +0 -1
  85. package/lib/typescript/highlight-updates/utils/HighlightUpdatesController.d.ts.map +0 -1
  86. package/lib/typescript/highlight-updates/utils/PerformanceLogger.d.ts.map +0 -1
  87. package/lib/typescript/highlight-updates/utils/ProfilerInterceptor.d.ts.map +0 -1
  88. package/lib/typescript/highlight-updates/utils/RenderCauseDetector.d.ts.map +0 -1
  89. package/lib/typescript/highlight-updates/utils/RenderTracker.d.ts.map +0 -1
  90. package/lib/typescript/highlight-updates/utils/ViewTypeMapper.d.ts.map +0 -1
  91. package/lib/typescript/highlight-updates/utils/copySettingsStorage.d.ts.map +0 -1
  92. package/lib/typescript/highlight-updates/utils/devtoolsComponentNames.d.ts.map +0 -1
  93. package/lib/typescript/highlight-updates/utils/namedComposite.d.ts.map +0 -1
  94. package/lib/typescript/highlight-updates/utils/ownStateChanged.d.ts.map +0 -1
  95. package/lib/typescript/highlight-updates/utils/rawEventEmitter.d.ts.map +0 -1
  96. package/lib/typescript/highlight-updates/utils/renderExportFormatter.d.ts.map +0 -1
  97. package/lib/typescript/highlight-updates/utils/rendersExportFormatter.d.ts.map +0 -1
  98. package/lib/typescript/highlight-updates/utils/screenElements.d.ts.map +0 -1
  99. package/lib/typescript/highlight-updates/utils/tapMatch.d.ts.map +0 -1
  100. package/lib/typescript/highlight-updates/utils/testIDs.d.ts.map +0 -1
  101. package/lib/typescript/highlight-updates/utils/touchCapture.d.ts.map +0 -1
  102. package/lib/typescript/index.d.ts.map +0 -1
  103. package/lib/typescript/preset.d.ts.map +0 -1
  104. package/lib/typescript/sync/highlightUpdatesSyncAdapter.d.ts.map +0 -1
@@ -1,908 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * RenderHistoryViewer
5
- *
6
- * Displays render history for a component with event stepping.
7
- * Allows navigating through render events chronologically.
8
- * Shows current state view or diff view between renders.
9
- */
10
-
11
- import React, { useState, useCallback, useMemo } from "react";
12
- import { View, Text, TouchableOpacity, ScrollView, StyleSheet } from "react-native";
13
- import { Clock, GitBranch, Database, Lock, formatRelativeTime, SectionHeader, EventStepperFooter, buoyColors, night, useLimit, ToolEmptyState, monoFont } from "@buoy-gg/shared-ui";
14
- import { TreeDiffViewer } from "@buoy-gg/shared-ui/dataViewer";
15
- import { RenderTracker } from "../utils/RenderTracker";
16
- import { EnhancedCauseDisplay, CAUSE_CONFIG } from "./RenderCauseBadge";
17
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
18
- /**
19
- * `HH:MM:SS.mmm` — the same shape Redux, Zustand and Jotai print for the same
20
- * job, and for the same reason: the milliseconds are the point.
21
- *
22
- * Built by hand rather than from `toLocaleTimeString`, which appends the day
23
- * period on a 12-hour locale — so concatenating the milliseconds to the end of
24
- * it produced "8:21:44 AM.351", with the fraction attached to the wrong part
25
- * of the time. It also made the string depend on the hour of day, which is a
26
- * fine way to have a test that only passes after 10am.
27
- */
28
- function formatTimeWithMs(timestamp) {
29
- const date = new Date(timestamp);
30
- const h = date.getHours().toString().padStart(2, "0");
31
- const m = date.getMinutes().toString().padStart(2, "0");
32
- const s = date.getSeconds().toString().padStart(2, "0");
33
- const ms = date.getMilliseconds().toString().padStart(3, "0");
34
- return `${h}:${m}:${s}.${ms}`;
35
- }
36
-
37
- /**
38
- * Main RenderHistoryViewer component
39
- */
40
- export function RenderHistoryViewer({
41
- render,
42
- disableInternalFooter = false,
43
- selectedEventIndex: externalIndex,
44
- onEventIndexChange: externalOnChange,
45
- isPro = false
46
- }) {
47
- // Internal state for event index when not controlled externally
48
- const [internalIndex, setInternalIndex] = useState(0);
49
-
50
- // Use external or internal state
51
- const selectedEventIndex = externalIndex ?? internalIndex;
52
- const onEventIndexChange = externalOnChange ?? setInternalIndex;
53
-
54
- // View mode: "current" shows selected event, "diff" shows comparison
55
- const [activeView, setActiveView] = useState("current");
56
-
57
- // Get all events sorted by timestamp (oldest first)
58
- const allEvents = useMemo(() => {
59
- if (!render.renderHistory || render.renderHistory.length === 0) {
60
- return [];
61
- }
62
- return [...render.renderHistory].sort((a, b) => a.timestamp - b.timestamp);
63
- }, [render.renderHistory]);
64
-
65
- // `isPro` stays a prop so callers can force the unlimited view; the tier cap
66
- // applies otherwise. useLimit() already returns Infinity for Pro, so the two
67
- // agree — this only preserves the prop contract for cross-package callers.
68
- const tierLimit = useLimit("highlightUpdates.historyEvents");
69
- const eventLimit = isPro ? Infinity : tierLimit;
70
-
71
- // Show the most recent N events (negative index clamps to 0, so an
72
- // unlimited tier returns the whole list).
73
- const events = useMemo(() => allEvents.slice(-eventLimit), [allEvents, eventLimit]);
74
- const lockedEventCount = useMemo(() => Math.max(0, allEvents.length - eventLimit), [allEvents.length, eventLimit]);
75
- const totalEvents = events.length;
76
- const currentEvent = events[selectedEventIndex];
77
- const previousEvent = selectedEventIndex > 0 ? events[selectedEventIndex - 1] : null;
78
-
79
- // Navigation handlers
80
- const goToPrevious = useCallback(() => {
81
- if (selectedEventIndex > 0) {
82
- onEventIndexChange(selectedEventIndex - 1);
83
- }
84
- }, [selectedEventIndex, onEventIndexChange]);
85
- const goToNext = useCallback(() => {
86
- if (selectedEventIndex < totalEvents - 1) {
87
- onEventIndexChange(selectedEventIndex + 1);
88
- }
89
- }, [selectedEventIndex, totalEvents, onEventIndexChange]);
90
-
91
- // If no history, show empty state
92
- if (totalEvents === 0) {
93
- // The copy used to tell EVERYONE to go and enable the setting, including
94
- // the people who already had. Asking the tracker which it is costs one
95
- // synchronous read on a branch that renders nothing else.
96
- const historyEnabled = RenderTracker.getSettings().enableRenderHistory;
97
- return /*#__PURE__*/_jsx(ToolEmptyState, {
98
- testID: "buoy-highlight-history-empty"
99
- // paused = the recorder is switched off; stare = armed and watching,
100
- // which is the truth once the setting is on and this component simply
101
- // has not re-rendered yet.
102
- ,
103
- otto: historyEnabled ? "stare" : "paused",
104
- title: "No Render History",
105
- message: historyEnabled ? "History is on and armed — this component has not re-rendered since. Interact with the app to record one." : "Enable render history tracking in settings to see render events here."
106
- });
107
- }
108
- return /*#__PURE__*/_jsxs(_Fragment, {
109
- children: [/*#__PURE__*/_jsxs(View, {
110
- style: [styles.container, {
111
- paddingBottom: !disableInternalFooter && totalEvents > 1 ? 80 : 0
112
- }],
113
- children: [lockedEventCount > 0 && /*#__PURE__*/_jsxs(View, {
114
- testID: "buoy-highlight-history-locked",
115
- style: styles.lockedBanner,
116
- children: [/*#__PURE__*/_jsx(Lock, {
117
- size: 14,
118
- color: night.color.warning
119
- }), /*#__PURE__*/_jsxs(Text, {
120
- testID: "buoy-highlight-history-locked-text",
121
- style: styles.lockedBannerText,
122
- children: [lockedEventCount, " older ", lockedEventCount === 1 ? 'render' : 'renders', " locked"]
123
- }), /*#__PURE__*/_jsx(Text, {
124
- style: styles.lockedBannerSubtext,
125
- children: "Upgrade to Pro"
126
- })]
127
- }), /*#__PURE__*/_jsxs(View, {
128
- style: styles.viewToggleContainer,
129
- children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
130
- testID: "buoy-highlight-history-mode-current",
131
- accessibilityRole: "button",
132
- accessibilityLabel: "Current state",
133
- style: [styles.viewToggleCard, activeView === "current" && styles.viewToggleCardActive],
134
- onPress: () => setActiveView("current"),
135
- activeOpacity: 0.8,
136
- children: [/*#__PURE__*/_jsxs(View, {
137
- style: styles.viewToggleContent,
138
- children: [/*#__PURE__*/_jsx(Database, {
139
- size: 16,
140
- color: activeView === "current" ? night.color.accent : night.color.textSecondary
141
- }), /*#__PURE__*/_jsx(Text, {
142
- style: [styles.viewToggleLabel, activeView === "current" && styles.viewToggleLabelActive],
143
- children: "CURRENT STATE"
144
- })]
145
- }), /*#__PURE__*/_jsxs(Text, {
146
- style: [styles.viewToggleDescription, activeView === "current" && {
147
- color: night.color.text
148
- }],
149
- children: ["View render #", currentEvent?.renderNumber ?? 0, " details"]
150
- })]
151
- }), /*#__PURE__*/_jsxs(View, {
152
- testID: "buoy-highlight-history-mode-diff",
153
- accessibilityLabel: "Diff view, coming soon",
154
- style: [styles.viewToggleCard, styles.viewToggleCardDisabled],
155
- children: [/*#__PURE__*/_jsxs(View, {
156
- style: styles.viewToggleContent,
157
- children: [/*#__PURE__*/_jsx(GitBranch, {
158
- size: 16,
159
- color: night.color.textTertiary
160
- }), /*#__PURE__*/_jsx(Text, {
161
- style: [styles.viewToggleLabel, styles.viewToggleLabelDisabled],
162
- children: "DIFF VIEW"
163
- }), /*#__PURE__*/_jsx(View, {
164
- style: styles.todoBadge,
165
- children: /*#__PURE__*/_jsx(Text, {
166
- style: styles.todoBadgeText,
167
- children: "TODO"
168
- })
169
- })]
170
- }), /*#__PURE__*/_jsx(Text, {
171
- style: [styles.viewToggleDescription, {
172
- color: night.color.textTertiary
173
- }],
174
- children: "Compare renders side by side (coming soon)"
175
- })]
176
- })]
177
- }), /*#__PURE__*/_jsx(ScrollView, {
178
- testID: "buoy-highlight-history-scroll",
179
- style: styles.contentScroll,
180
- contentContainerStyle: styles.contentContainer,
181
- showsVerticalScrollIndicator: false,
182
- children: activeView === "current" ? /*#__PURE__*/_jsx(CurrentStateView, {
183
- event: currentEvent,
184
- render: render
185
- }) : /*#__PURE__*/_jsx(DiffView, {
186
- previousEvent: previousEvent,
187
- currentEvent: currentEvent,
188
- render: render
189
- })
190
- })]
191
- }), !disableInternalFooter && /*#__PURE__*/_jsx(EventStepperFooter, {
192
- currentIndex: selectedEventIndex,
193
- totalItems: totalEvents,
194
- onPrevious: goToPrevious,
195
- onNext: goToNext,
196
- itemLabel: "Render",
197
- subtitle: formatRelativeTime(new Date(currentEvent?.timestamp ?? Date.now()))
198
- })]
199
- });
200
- }
201
-
202
- /**
203
- * Current State View - shows details of the selected render event
204
- */
205
- function CurrentStateView({
206
- event,
207
- render
208
- }) {
209
- if (!event) {
210
- return /*#__PURE__*/_jsx(View, {
211
- testID: "buoy-highlight-history-no-event",
212
- style: styles.noEventContainer,
213
- children: /*#__PURE__*/_jsx(Text, {
214
- style: styles.noEventText,
215
- children: "No event selected"
216
- })
217
- });
218
- }
219
- const causeConfig = CAUSE_CONFIG[event.cause.type];
220
- return /*#__PURE__*/_jsxs(View, {
221
- style: styles.currentStateContainer,
222
- children: [/*#__PURE__*/_jsxs(View, {
223
- style: styles.eventHeader,
224
- children: [/*#__PURE__*/_jsxs(View, {
225
- style: styles.eventHeaderLeft,
226
- children: [/*#__PURE__*/_jsxs(Text, {
227
- testID: "buoy-highlight-history-event-title",
228
- style: styles.eventTitle,
229
- children: ["Render #", event.renderNumber]
230
- }), /*#__PURE__*/_jsx(Text, {
231
- testID: "buoy-highlight-history-event-time",
232
- style: styles.eventTime,
233
- children: formatTimeWithMs(event.timestamp)
234
- })]
235
- }), /*#__PURE__*/_jsxs(View, {
236
- style: [styles.eventBadge, {
237
- backgroundColor: render.color + "30"
238
- }],
239
- children: [/*#__PURE__*/_jsx(View, {
240
- style: [styles.eventBadgeDot, {
241
- backgroundColor: render.color
242
- }]
243
- }), /*#__PURE__*/_jsx(Text, {
244
- testID: "buoy-highlight-history-event-cause",
245
- style: [styles.eventBadgeText, {
246
- color: render.color
247
- }],
248
- children: event.cause.type.toUpperCase()
249
- })]
250
- })]
251
- }), /*#__PURE__*/_jsxs(View, {
252
- style: styles.section,
253
- children: [/*#__PURE__*/_jsxs(SectionHeader, {
254
- children: [/*#__PURE__*/_jsx(SectionHeader.Icon, {
255
- icon: Clock,
256
- color: causeConfig.color,
257
- size: 12
258
- }), /*#__PURE__*/_jsx(SectionHeader.Title, {
259
- children: "WHY DID THIS RENDER?"
260
- })]
261
- }), /*#__PURE__*/_jsx(View, {
262
- style: styles.sectionContent,
263
- children: /*#__PURE__*/_jsx(EnhancedCauseDisplay, {
264
- cause: event.cause,
265
- nativeType: render.viewType
266
- })
267
- })]
268
- }), event.capturedProps && Object.keys(event.capturedProps).length > 0 && /*#__PURE__*/_jsxs(View, {
269
- style: styles.section,
270
- children: [/*#__PURE__*/_jsxs(SectionHeader, {
271
- children: [/*#__PURE__*/_jsx(SectionHeader.Icon, {
272
- icon: Database,
273
- color: night.color.accent,
274
- size: 12
275
- }), /*#__PURE__*/_jsx(SectionHeader.Title, {
276
- children: "CAPTURED PROPS"
277
- })]
278
- }), /*#__PURE__*/_jsx(View, {
279
- style: styles.sectionContent,
280
- children: /*#__PURE__*/_jsx(ScrollView, {
281
- horizontal: true,
282
- showsHorizontalScrollIndicator: false,
283
- style: styles.propsScrollView,
284
- children: /*#__PURE__*/_jsx(Text, {
285
- testID: "buoy-highlight-history-props",
286
- style: styles.propsJson,
287
- children: JSON.stringify(event.capturedProps, null, 2)
288
- })
289
- })
290
- })]
291
- })]
292
- });
293
- }
294
-
295
- /**
296
- * Diff mode types
297
- */
298
-
299
- /**
300
- * Diff View - shows comparison between two render events
301
- */
302
- function DiffView({
303
- previousEvent,
304
- currentEvent,
305
- render
306
- }) {
307
- // Diff mode tab state
308
- const [diffMode, setDiffMode] = useState("props");
309
- if (!previousEvent || !currentEvent) {
310
- return /*#__PURE__*/_jsx(View, {
311
- style: styles.noEventContainer,
312
- children: /*#__PURE__*/_jsx(Text, {
313
- style: styles.noEventText,
314
- children: "Select an event with a previous event to compare"
315
- })
316
- });
317
- }
318
- const prevCauseConfig = CAUSE_CONFIG[previousEvent.cause.type];
319
- const currCauseConfig = CAUSE_CONFIG[currentEvent.cause.type];
320
-
321
- // Check what data is available for diff
322
- const hasPropsData = previousEvent.capturedProps && currentEvent.capturedProps;
323
- const hasStateData = previousEvent.capturedState && currentEvent.capturedState;
324
- return /*#__PURE__*/_jsxs(View, {
325
- style: styles.diffContainer,
326
- children: [/*#__PURE__*/_jsxs(View, {
327
- style: styles.compareBar,
328
- children: [/*#__PURE__*/_jsxs(View, {
329
- style: styles.compareSide,
330
- children: [/*#__PURE__*/_jsxs(View, {
331
- style: styles.compareLabelRow,
332
- children: [/*#__PURE__*/_jsx(Text, {
333
- style: [styles.compareLabel, {
334
- color: buoyColors.warning
335
- }],
336
- children: "PREV"
337
- }), /*#__PURE__*/_jsx(View, {
338
- style: [styles.compareActionBadge, {
339
- backgroundColor: `${prevCauseConfig.color}20`
340
- }],
341
- children: /*#__PURE__*/_jsx(Text, {
342
- style: [styles.compareActionText, {
343
- color: prevCauseConfig.color
344
- }],
345
- children: previousEvent.cause.type.toUpperCase()
346
- })
347
- })]
348
- }), /*#__PURE__*/_jsxs(View, {
349
- style: styles.compareMeta,
350
- children: [/*#__PURE__*/_jsxs(Text, {
351
- style: styles.compareIndex,
352
- children: ["#", previousEvent.renderNumber]
353
- }), /*#__PURE__*/_jsx(Text, {
354
- style: styles.compareTime,
355
- children: formatTimeWithMs(previousEvent.timestamp)
356
- })]
357
- })]
358
- }), /*#__PURE__*/_jsx(View, {
359
- style: styles.compareDivider,
360
- children: /*#__PURE__*/_jsx(Text, {
361
- style: styles.compareArrow,
362
- children: "\u2192"
363
- })
364
- }), /*#__PURE__*/_jsxs(View, {
365
- style: styles.compareSide,
366
- children: [/*#__PURE__*/_jsxs(View, {
367
- style: styles.compareLabelRow,
368
- children: [/*#__PURE__*/_jsx(Text, {
369
- style: [styles.compareLabel, {
370
- color: buoyColors.success
371
- }],
372
- children: "CUR"
373
- }), /*#__PURE__*/_jsx(View, {
374
- style: [styles.compareActionBadge, {
375
- backgroundColor: `${currCauseConfig.color}20`
376
- }],
377
- children: /*#__PURE__*/_jsx(Text, {
378
- style: [styles.compareActionText, {
379
- color: currCauseConfig.color
380
- }],
381
- children: currentEvent.cause.type.toUpperCase()
382
- })
383
- })]
384
- }), /*#__PURE__*/_jsxs(View, {
385
- style: styles.compareMeta,
386
- children: [/*#__PURE__*/_jsxs(Text, {
387
- style: styles.compareIndex,
388
- children: ["#", currentEvent.renderNumber]
389
- }), /*#__PURE__*/_jsx(Text, {
390
- style: styles.compareTime,
391
- children: formatTimeWithMs(currentEvent.timestamp)
392
- })]
393
- })]
394
- })]
395
- }), /*#__PURE__*/_jsxs(View, {
396
- style: styles.diffModeTabs,
397
- children: [/*#__PURE__*/_jsx(TouchableOpacity, {
398
- style: [styles.diffModeTab, diffMode === "cause" && styles.diffModeTabActive],
399
- onPress: () => setDiffMode("cause"),
400
- activeOpacity: 0.7,
401
- children: /*#__PURE__*/_jsx(Text, {
402
- style: [styles.diffModeTabText, diffMode === "cause" && styles.diffModeTabTextActive],
403
- children: "CAUSE"
404
- })
405
- }), /*#__PURE__*/_jsx(TouchableOpacity, {
406
- style: [styles.diffModeTab, diffMode === "props" && styles.diffModeTabActive, !hasPropsData && styles.diffModeTabDisabled],
407
- onPress: () => hasPropsData && setDiffMode("props"),
408
- activeOpacity: hasPropsData ? 0.7 : 1,
409
- children: /*#__PURE__*/_jsx(Text, {
410
- style: [styles.diffModeTabText, diffMode === "props" && styles.diffModeTabTextActive, !hasPropsData && styles.diffModeTabTextDisabled],
411
- children: "PROPS"
412
- })
413
- }), /*#__PURE__*/_jsx(TouchableOpacity, {
414
- style: [styles.diffModeTab, diffMode === "state" && styles.diffModeTabActive, !hasStateData && styles.diffModeTabDisabled],
415
- onPress: () => hasStateData && setDiffMode("state"),
416
- activeOpacity: hasStateData ? 0.7 : 1,
417
- children: /*#__PURE__*/_jsx(Text, {
418
- style: [styles.diffModeTabText, diffMode === "state" && styles.diffModeTabTextActive, !hasStateData && styles.diffModeTabTextDisabled],
419
- children: "STATE"
420
- })
421
- })]
422
- }), diffMode === "cause" && /*#__PURE__*/_jsx(View, {
423
- style: styles.diffSummary,
424
- children: /*#__PURE__*/_jsx(EnhancedCauseDisplay, {
425
- cause: currentEvent.cause,
426
- nativeType: render.viewType
427
- })
428
- }), diffMode === "props" && /*#__PURE__*/_jsx(View, {
429
- style: styles.treeDiffContainer,
430
- children: hasPropsData ? /*#__PURE__*/_jsx(TreeDiffViewer, {
431
- oldValue: previousEvent.capturedProps,
432
- newValue: currentEvent.capturedProps,
433
- theme: "dark",
434
- showUnchanged: true
435
- }) : /*#__PURE__*/_jsxs(View, {
436
- style: styles.noDiffData,
437
- children: [/*#__PURE__*/_jsx(Text, {
438
- style: styles.noDiffDataTitle,
439
- children: "Props Not Captured"
440
- }), /*#__PURE__*/_jsx(Text, {
441
- style: styles.noDiffDataText,
442
- children: "Enable \"Capture Props on Render\" in settings to see props diff."
443
- })]
444
- })
445
- }), diffMode === "state" && /*#__PURE__*/_jsx(View, {
446
- style: styles.treeDiffContainer,
447
- children: hasStateData ? /*#__PURE__*/_jsx(TreeDiffViewer, {
448
- oldValue: previousEvent.capturedState,
449
- newValue: currentEvent.capturedState,
450
- theme: "dark",
451
- showUnchanged: true
452
- }) : /*#__PURE__*/_jsxs(View, {
453
- style: styles.noDiffData,
454
- children: [/*#__PURE__*/_jsx(Text, {
455
- style: styles.noDiffDataTitle,
456
- children: "State Not Captured"
457
- }), /*#__PURE__*/_jsx(Text, {
458
- style: styles.noDiffDataText,
459
- children: "Enable \"Capture State on Render\" in settings to see state diff."
460
- })]
461
- })
462
- })]
463
- });
464
- }
465
-
466
- /**
467
- * External footer component for modal integration
468
- * Uses renderHistory for events (only available when history tracking is enabled)
469
- */
470
- export function RenderHistoryFooter({
471
- render,
472
- selectedEventIndex = 0,
473
- onEventIndexChange = () => {},
474
- isPro = false
475
- }) {
476
- // Get all events from render history (sorted by timestamp)
477
- const allEvents = useMemo(() => {
478
- if (!render.renderHistory || render.renderHistory.length === 0) {
479
- return [];
480
- }
481
- return [...render.renderHistory].sort((a, b) => a.timestamp - b.timestamp);
482
- }, [render.renderHistory]);
483
-
484
- // Same cap as RenderHistoryViewer above; `isPro` remains a caller override.
485
- const tierLimit = useLimit("highlightUpdates.historyEvents");
486
- const eventLimit = isPro ? Infinity : tierLimit;
487
-
488
- // Most recent N (negative index clamps to 0, so unlimited returns all).
489
- const events = useMemo(() => allEvents.slice(-eventLimit), [allEvents, eventLimit]);
490
- const totalEvents = events.length;
491
- const currentEvent = events[selectedEventIndex];
492
- const goToPrevious = useCallback(() => {
493
- onEventIndexChange(Math.max(0, selectedEventIndex - 1));
494
- }, [selectedEventIndex, onEventIndexChange]);
495
- const goToNext = useCallback(() => {
496
- onEventIndexChange(Math.min(totalEvents - 1, selectedEventIndex + 1));
497
- }, [selectedEventIndex, totalEvents, onEventIndexChange]);
498
-
499
- // Don't render if no history events (history tracking might be disabled)
500
- if (totalEvents <= 1) {
501
- return null;
502
- }
503
- return /*#__PURE__*/_jsx(EventStepperFooter, {
504
- currentIndex: selectedEventIndex,
505
- totalItems: totalEvents,
506
- onPrevious: goToPrevious,
507
- onNext: goToNext,
508
- itemLabel: "Render",
509
- subtitle: currentEvent ? formatRelativeTime(new Date(currentEvent.timestamp)) : undefined
510
- });
511
- }
512
- const styles = StyleSheet.create({
513
- container: {
514
- flex: 1,
515
- // Transparent so JsModal's ToolBackground shows through (the modal paints opaque base beneath it).
516
- backgroundColor: "transparent"
517
- },
518
- emptyContainer: {
519
- flex: 1,
520
- alignItems: "center",
521
- justifyContent: "center",
522
- padding: 32,
523
- gap: 12
524
- },
525
- emptyTitle: {
526
- fontSize: 16,
527
- fontWeight: "600",
528
- color: night.color.text
529
- },
530
- emptyText: {
531
- fontSize: 13,
532
- color: night.color.textSecondary,
533
- textAlign: "center",
534
- lineHeight: 18
535
- },
536
- viewToggleContainer: {
537
- flexDirection: "row",
538
- padding: 12,
539
- gap: 8
540
- },
541
- viewToggleCard: {
542
- flex: 1,
543
- backgroundColor: night.color.surface,
544
- borderRadius: 8,
545
- borderWidth: 1,
546
- borderColor: night.color.border,
547
- padding: 10,
548
- gap: 4
549
- },
550
- viewToggleCardActive: {
551
- borderColor: night.color.accentBorderStrong,
552
- backgroundColor: night.color.accentSoft
553
- },
554
- viewToggleCardDisabled: {
555
- opacity: 0.5
556
- },
557
- todoBadge: {
558
- backgroundColor: night.color.fillSecondary,
559
- paddingHorizontal: 6,
560
- paddingVertical: 2,
561
- borderRadius: 4,
562
- marginLeft: 4
563
- },
564
- todoBadgeText: {
565
- fontSize: 9,
566
- fontWeight: "700",
567
- color: night.color.textTertiary,
568
- letterSpacing: 0.3
569
- },
570
- viewToggleContent: {
571
- flexDirection: "row",
572
- alignItems: "center",
573
- gap: 6
574
- },
575
- viewToggleLabel: {
576
- fontSize: 10,
577
- fontWeight: "700",
578
- color: night.color.textSecondary,
579
- letterSpacing: 0.5
580
- },
581
- viewToggleLabelActive: {
582
- color: night.color.accent
583
- },
584
- viewToggleLabelDisabled: {
585
- color: night.color.textTertiary
586
- },
587
- viewToggleDescription: {
588
- fontSize: 11,
589
- color: night.color.textTertiary,
590
- marginTop: 2
591
- },
592
- contentScroll: {
593
- flex: 1
594
- },
595
- contentContainer: {
596
- padding: 12,
597
- paddingTop: 0
598
- },
599
- noEventContainer: {
600
- padding: 24,
601
- alignItems: "center"
602
- },
603
- noEventText: {
604
- fontSize: 13,
605
- color: night.color.textTertiary
606
- },
607
- currentStateContainer: {
608
- gap: 12
609
- },
610
- eventHeader: {
611
- flexDirection: "row",
612
- alignItems: "center",
613
- justifyContent: "space-between",
614
- backgroundColor: night.color.surface,
615
- borderRadius: 8,
616
- borderWidth: 1,
617
- borderColor: night.color.border,
618
- padding: 12
619
- },
620
- eventHeaderLeft: {
621
- gap: 2
622
- },
623
- eventTitle: {
624
- fontSize: 15,
625
- fontWeight: "700",
626
- color: night.color.text
627
- },
628
- eventTime: {
629
- fontSize: 11,
630
- color: night.color.textTertiary,
631
- fontFamily: monoFont
632
- },
633
- eventBadge: {
634
- flexDirection: "row",
635
- alignItems: "center",
636
- paddingHorizontal: 10,
637
- paddingVertical: 4,
638
- borderRadius: 12,
639
- gap: 6
640
- },
641
- eventBadgeDot: {
642
- width: 6,
643
- height: 6,
644
- borderRadius: 3
645
- },
646
- eventBadgeText: {
647
- fontSize: 10,
648
- fontWeight: "700",
649
- fontFamily: monoFont
650
- },
651
- section: {
652
- backgroundColor: night.color.surface,
653
- borderRadius: 8,
654
- borderWidth: 1,
655
- borderColor: night.color.border,
656
- overflow: "hidden"
657
- },
658
- sectionContent: {
659
- padding: 12,
660
- paddingTop: 8
661
- },
662
- causeContainer: {
663
- marginBottom: 12
664
- },
665
- changedList: {
666
- marginBottom: 12,
667
- paddingLeft: 4
668
- },
669
- changedListTitle: {
670
- fontSize: 11,
671
- fontWeight: "600",
672
- color: night.color.textSecondary,
673
- marginBottom: 6
674
- },
675
- changedItem: {
676
- fontSize: 12,
677
- color: night.color.text,
678
- fontFamily: monoFont,
679
- marginBottom: 3,
680
- paddingLeft: 8
681
- },
682
- propsScrollView: {
683
- maxHeight: 150
684
- },
685
- propsJson: {
686
- fontSize: 11,
687
- fontFamily: monoFont,
688
- color: night.color.text,
689
- // Inset code box — the night track color.
690
- backgroundColor: night.color.bg,
691
- padding: 10,
692
- borderRadius: 6
693
- },
694
- diffContainer: {
695
- gap: 12
696
- },
697
- compareBar: {
698
- flexDirection: "row",
699
- backgroundColor: night.color.surface,
700
- borderRadius: 8,
701
- borderWidth: 1,
702
- borderColor: night.color.border,
703
- padding: 10
704
- },
705
- compareSide: {
706
- flex: 1,
707
- gap: 4
708
- },
709
- compareLabelRow: {
710
- flexDirection: "row",
711
- alignItems: "center",
712
- gap: 8
713
- },
714
- compareLabel: {
715
- fontSize: 10,
716
- fontWeight: "700",
717
- letterSpacing: 0.5
718
- },
719
- compareActionBadge: {
720
- paddingHorizontal: 6,
721
- paddingVertical: 2,
722
- borderRadius: 4
723
- },
724
- compareActionText: {
725
- fontSize: 9,
726
- fontWeight: "600"
727
- },
728
- compareMeta: {
729
- flexDirection: "row",
730
- alignItems: "center",
731
- gap: 6
732
- },
733
- compareIndex: {
734
- fontSize: 12,
735
- fontWeight: "600",
736
- color: night.color.text
737
- },
738
- compareTime: {
739
- fontSize: 10,
740
- color: night.color.textTertiary,
741
- fontFamily: monoFont
742
- },
743
- compareDivider: {
744
- width: 30,
745
- alignItems: "center",
746
- justifyContent: "center"
747
- },
748
- compareArrow: {
749
- fontSize: 16,
750
- color: night.color.textTertiary
751
- },
752
- diffSummary: {
753
- backgroundColor: night.color.surface,
754
- borderRadius: 8,
755
- borderWidth: 1,
756
- borderColor: night.color.border,
757
- padding: 12
758
- },
759
- diffSummaryTitle: {
760
- fontSize: 11,
761
- fontWeight: "600",
762
- color: night.color.textSecondary,
763
- marginBottom: 8
764
- },
765
- diffChanges: {
766
- gap: 4
767
- },
768
- diffChangeItem: {
769
- flexDirection: "row",
770
- alignItems: "center",
771
- gap: 6
772
- },
773
- diffChangeIcon: {
774
- fontSize: 12,
775
- fontWeight: "700",
776
- color: night.color.warning,
777
- fontFamily: monoFont
778
- },
779
- diffChangeKey: {
780
- fontSize: 12,
781
- color: night.color.text,
782
- fontFamily: monoFont
783
- },
784
- diffNoChanges: {
785
- fontSize: 12,
786
- color: night.color.textTertiary,
787
- fontStyle: "italic"
788
- },
789
- diffPlaceholder: {
790
- fontSize: 12,
791
- color: night.color.textTertiary,
792
- fontStyle: "italic",
793
- textAlign: "center",
794
- padding: 16
795
- },
796
- // Diff mode tabs
797
- diffModeTabs: {
798
- flexDirection: "row",
799
- backgroundColor: night.color.surface,
800
- borderRadius: 8,
801
- borderWidth: 1,
802
- borderColor: night.color.border,
803
- padding: 4,
804
- gap: 4
805
- },
806
- diffModeTab: {
807
- flex: 1,
808
- paddingVertical: 8,
809
- paddingHorizontal: 12,
810
- borderRadius: 6,
811
- alignItems: "center"
812
- },
813
- diffModeTabActive: {
814
- backgroundColor: night.color.accentSoft
815
- },
816
- diffModeTabDisabled: {
817
- opacity: 0.4
818
- },
819
- diffModeTabText: {
820
- fontSize: 10,
821
- fontWeight: "600",
822
- color: night.color.textSecondary,
823
- letterSpacing: 0.5
824
- },
825
- diffModeTabTextActive: {
826
- color: night.color.accent
827
- },
828
- diffModeTabTextDisabled: {
829
- color: night.color.textTertiary
830
- },
831
- // Cause diff styles
832
- causeDiffContainer: {
833
- gap: 8,
834
- marginBottom: 12
835
- },
836
- causeDiffRow: {
837
- flexDirection: "row",
838
- alignItems: "center",
839
- gap: 8
840
- },
841
- causeDiffLabel: {
842
- fontSize: 11,
843
- fontWeight: "600",
844
- color: night.color.textSecondary,
845
- minWidth: 80
846
- },
847
- causeDiffValue: {
848
- fontSize: 12,
849
- color: night.color.text,
850
- fontFamily: monoFont,
851
- fontWeight: "500"
852
- },
853
- diffChangesTitle: {
854
- fontSize: 11,
855
- fontWeight: "600",
856
- color: night.color.textSecondary,
857
- marginBottom: 6
858
- },
859
- // Tree diff container
860
- treeDiffContainer: {
861
- backgroundColor: night.color.surface,
862
- borderRadius: 8,
863
- borderWidth: 1,
864
- borderColor: night.color.border,
865
- overflow: "hidden",
866
- minHeight: 150
867
- },
868
- noDiffData: {
869
- padding: 24,
870
- alignItems: "center",
871
- gap: 8
872
- },
873
- noDiffDataTitle: {
874
- fontSize: 13,
875
- fontWeight: "600",
876
- color: night.color.text
877
- },
878
- noDiffDataText: {
879
- fontSize: 12,
880
- color: night.color.textTertiary,
881
- textAlign: "center",
882
- lineHeight: 18
883
- },
884
- lockedBanner: {
885
- flexDirection: "row",
886
- alignItems: "center",
887
- justifyContent: "center",
888
- paddingVertical: 10,
889
- paddingHorizontal: 16,
890
- marginHorizontal: 12,
891
- marginTop: 8,
892
- backgroundColor: night.color.warningSoft,
893
- borderRadius: 8,
894
- borderWidth: 1,
895
- borderColor: night.color.warning + "30",
896
- gap: 8
897
- },
898
- lockedBannerText: {
899
- color: night.color.warning,
900
- fontSize: 13,
901
- fontWeight: "500"
902
- },
903
- lockedBannerSubtext: {
904
- color: night.color.textTertiary,
905
- fontSize: 12
906
- }
907
- });
908
- export default RenderHistoryViewer;
1
+ "use strict";import React,{useState,useCallback,useMemo}from"react";import{View,Text,TouchableOpacity,ScrollView,StyleSheet}from"react-native";import{Clock,GitBranch,Database,Lock,formatRelativeTime,SectionHeader,EventStepperFooter,buoyColors,night,useLimit,ToolEmptyState,monoFont}from"@buoy-gg/shared-ui";import{TreeDiffViewer}from"@buoy-gg/shared-ui/dataViewer";import{RenderTracker}from"../utils/RenderTracker";import{EnhancedCauseDisplay,CAUSE_CONFIG}from"./RenderCauseBadge";import{jsx as _jsx,jsxs as _jsxs,Fragment as _Fragment}from"react/jsx-runtime";function formatTimeWithMs(e){const t=new Date(e);return`${t.getHours().toString().padStart(2,"0")}:${t.getMinutes().toString().padStart(2,"0")}:${t.getSeconds().toString().padStart(2,"0")}.${t.getMilliseconds().toString().padStart(3,"0")}`}export function RenderHistoryViewer({render:e,disableInternalFooter:t=!1,selectedEventIndex:o,onEventIndexChange:r,isPro:i=!1}){const[n,s]=useState(0),l=o??n,a=r??s,[c,d]=useState("current"),g=useMemo(()=>e.renderHistory&&0!==e.renderHistory.length?[...e.renderHistory].sort((e,t)=>e.timestamp-t.timestamp):[],[e.renderHistory]),y=useLimit("highlightUpdates.historyEvents"),h=i?1/0:y,f=useMemo(()=>g.slice(-h),[g,h]),x=useMemo(()=>Math.max(0,g.length-h),[g.length,h]),p=f.length,u=f[l],m=l>0?f[l-1]:null,T=useCallback(()=>{l>0&&a(l-1)},[l,a]),b=useCallback(()=>{l<p-1&&a(l+1)},[l,p,a]);if(0===p){const e=RenderTracker.getSettings().enableRenderHistory;return _jsx(ToolEmptyState,{testID:"buoy-highlight-history-empty",otto:e?"stare":"paused",title:"No Render History",message:e?"History is on and armed — this component has not re-rendered since. Interact with the app to record one.":"Enable render history tracking in settings to see render events here."})}return _jsxs(_Fragment,{children:[_jsxs(View,{style:[styles.container,{paddingBottom:!t&&p>1?80:0}],children:[x>0&&_jsxs(View,{testID:"buoy-highlight-history-locked",style:styles.lockedBanner,children:[_jsx(Lock,{size:14,color:night.color.warning}),_jsxs(Text,{testID:"buoy-highlight-history-locked-text",style:styles.lockedBannerText,children:[x," older ",1===x?"render":"renders"," locked"]}),_jsx(Text,{style:styles.lockedBannerSubtext,children:"Upgrade to Pro"})]}),_jsxs(View,{style:styles.viewToggleContainer,children:[_jsxs(TouchableOpacity,{testID:"buoy-highlight-history-mode-current",accessibilityRole:"button",accessibilityLabel:"Current state",style:[styles.viewToggleCard,"current"===c&&styles.viewToggleCardActive],onPress:()=>d("current"),activeOpacity:.8,children:[_jsxs(View,{style:styles.viewToggleContent,children:[_jsx(Database,{size:16,color:"current"===c?night.color.accent:night.color.textSecondary}),_jsx(Text,{style:[styles.viewToggleLabel,"current"===c&&styles.viewToggleLabelActive],children:"CURRENT STATE"})]}),_jsxs(Text,{style:[styles.viewToggleDescription,"current"===c&&{color:night.color.text}],children:["View render #",u?.renderNumber??0," details"]})]}),_jsxs(View,{testID:"buoy-highlight-history-mode-diff",accessibilityLabel:"Diff view, coming soon",style:[styles.viewToggleCard,styles.viewToggleCardDisabled],children:[_jsxs(View,{style:styles.viewToggleContent,children:[_jsx(GitBranch,{size:16,color:night.color.textTertiary}),_jsx(Text,{style:[styles.viewToggleLabel,styles.viewToggleLabelDisabled],children:"DIFF VIEW"}),_jsx(View,{style:styles.todoBadge,children:_jsx(Text,{style:styles.todoBadgeText,children:"TODO"})})]}),_jsx(Text,{style:[styles.viewToggleDescription,{color:night.color.textTertiary}],children:"Compare renders side by side (coming soon)"})]})]}),_jsx(ScrollView,{testID:"buoy-highlight-history-scroll",style:styles.contentScroll,contentContainerStyle:styles.contentContainer,showsVerticalScrollIndicator:!1,children:"current"===c?_jsx(CurrentStateView,{event:u,render:e}):_jsx(DiffView,{previousEvent:m,currentEvent:u,render:e})})]}),!t&&_jsx(EventStepperFooter,{currentIndex:l,totalItems:p,onPrevious:T,onNext:b,itemLabel:"Render",subtitle:formatRelativeTime(new Date(u?.timestamp??Date.now()))})]})}function CurrentStateView({event:e,render:t}){if(!e)return _jsx(View,{testID:"buoy-highlight-history-no-event",style:styles.noEventContainer,children:_jsx(Text,{style:styles.noEventText,children:"No event selected"})});const o=CAUSE_CONFIG[e.cause.type];return _jsxs(View,{style:styles.currentStateContainer,children:[_jsxs(View,{style:styles.eventHeader,children:[_jsxs(View,{style:styles.eventHeaderLeft,children:[_jsxs(Text,{testID:"buoy-highlight-history-event-title",style:styles.eventTitle,children:["Render #",e.renderNumber]}),_jsx(Text,{testID:"buoy-highlight-history-event-time",style:styles.eventTime,children:formatTimeWithMs(e.timestamp)})]}),_jsxs(View,{style:[styles.eventBadge,{backgroundColor:t.color+"30"}],children:[_jsx(View,{style:[styles.eventBadgeDot,{backgroundColor:t.color}]}),_jsx(Text,{testID:"buoy-highlight-history-event-cause",style:[styles.eventBadgeText,{color:t.color}],children:e.cause.type.toUpperCase()})]})]}),_jsxs(View,{style:styles.section,children:[_jsxs(SectionHeader,{children:[_jsx(SectionHeader.Icon,{icon:Clock,color:o.color,size:12}),_jsx(SectionHeader.Title,{children:"WHY DID THIS RENDER?"})]}),_jsx(View,{style:styles.sectionContent,children:_jsx(EnhancedCauseDisplay,{cause:e.cause,nativeType:t.viewType})})]}),e.capturedProps&&Object.keys(e.capturedProps).length>0&&_jsxs(View,{style:styles.section,children:[_jsxs(SectionHeader,{children:[_jsx(SectionHeader.Icon,{icon:Database,color:night.color.accent,size:12}),_jsx(SectionHeader.Title,{children:"CAPTURED PROPS"})]}),_jsx(View,{style:styles.sectionContent,children:_jsx(ScrollView,{horizontal:!0,showsHorizontalScrollIndicator:!1,style:styles.propsScrollView,children:_jsx(Text,{testID:"buoy-highlight-history-props",style:styles.propsJson,children:JSON.stringify(e.capturedProps,null,2)})})})]})]})}function DiffView({previousEvent:e,currentEvent:t,render:o}){const[r,i]=useState("props");if(!e||!t)return _jsx(View,{style:styles.noEventContainer,children:_jsx(Text,{style:styles.noEventText,children:"Select an event with a previous event to compare"})});const n=CAUSE_CONFIG[e.cause.type],s=CAUSE_CONFIG[t.cause.type],l=e.capturedProps&&t.capturedProps,a=e.capturedState&&t.capturedState;return _jsxs(View,{style:styles.diffContainer,children:[_jsxs(View,{style:styles.compareBar,children:[_jsxs(View,{style:styles.compareSide,children:[_jsxs(View,{style:styles.compareLabelRow,children:[_jsx(Text,{style:[styles.compareLabel,{color:buoyColors.warning}],children:"PREV"}),_jsx(View,{style:[styles.compareActionBadge,{backgroundColor:`${n.color}20`}],children:_jsx(Text,{style:[styles.compareActionText,{color:n.color}],children:e.cause.type.toUpperCase()})})]}),_jsxs(View,{style:styles.compareMeta,children:[_jsxs(Text,{style:styles.compareIndex,children:["#",e.renderNumber]}),_jsx(Text,{style:styles.compareTime,children:formatTimeWithMs(e.timestamp)})]})]}),_jsx(View,{style:styles.compareDivider,children:_jsx(Text,{style:styles.compareArrow,children:"→"})}),_jsxs(View,{style:styles.compareSide,children:[_jsxs(View,{style:styles.compareLabelRow,children:[_jsx(Text,{style:[styles.compareLabel,{color:buoyColors.success}],children:"CUR"}),_jsx(View,{style:[styles.compareActionBadge,{backgroundColor:`${s.color}20`}],children:_jsx(Text,{style:[styles.compareActionText,{color:s.color}],children:t.cause.type.toUpperCase()})})]}),_jsxs(View,{style:styles.compareMeta,children:[_jsxs(Text,{style:styles.compareIndex,children:["#",t.renderNumber]}),_jsx(Text,{style:styles.compareTime,children:formatTimeWithMs(t.timestamp)})]})]})]}),_jsxs(View,{style:styles.diffModeTabs,children:[_jsx(TouchableOpacity,{style:[styles.diffModeTab,"cause"===r&&styles.diffModeTabActive],onPress:()=>i("cause"),activeOpacity:.7,children:_jsx(Text,{style:[styles.diffModeTabText,"cause"===r&&styles.diffModeTabTextActive],children:"CAUSE"})}),_jsx(TouchableOpacity,{style:[styles.diffModeTab,"props"===r&&styles.diffModeTabActive,!l&&styles.diffModeTabDisabled],onPress:()=>l&&i("props"),activeOpacity:l?.7:1,children:_jsx(Text,{style:[styles.diffModeTabText,"props"===r&&styles.diffModeTabTextActive,!l&&styles.diffModeTabTextDisabled],children:"PROPS"})}),_jsx(TouchableOpacity,{style:[styles.diffModeTab,"state"===r&&styles.diffModeTabActive,!a&&styles.diffModeTabDisabled],onPress:()=>a&&i("state"),activeOpacity:a?.7:1,children:_jsx(Text,{style:[styles.diffModeTabText,"state"===r&&styles.diffModeTabTextActive,!a&&styles.diffModeTabTextDisabled],children:"STATE"})})]}),"cause"===r&&_jsx(View,{style:styles.diffSummary,children:_jsx(EnhancedCauseDisplay,{cause:t.cause,nativeType:o.viewType})}),"props"===r&&_jsx(View,{style:styles.treeDiffContainer,children:l?_jsx(TreeDiffViewer,{oldValue:e.capturedProps,newValue:t.capturedProps,theme:"dark",showUnchanged:!0}):_jsxs(View,{style:styles.noDiffData,children:[_jsx(Text,{style:styles.noDiffDataTitle,children:"Props Not Captured"}),_jsx(Text,{style:styles.noDiffDataText,children:'Enable "Capture Props on Render" in settings to see props diff.'})]})}),"state"===r&&_jsx(View,{style:styles.treeDiffContainer,children:a?_jsx(TreeDiffViewer,{oldValue:e.capturedState,newValue:t.capturedState,theme:"dark",showUnchanged:!0}):_jsxs(View,{style:styles.noDiffData,children:[_jsx(Text,{style:styles.noDiffDataTitle,children:"State Not Captured"}),_jsx(Text,{style:styles.noDiffDataText,children:'Enable "Capture State on Render" in settings to see state diff.'})]})})]})}export function RenderHistoryFooter({render:e,selectedEventIndex:t=0,onEventIndexChange:o=()=>{},isPro:r=!1}){const i=useMemo(()=>e.renderHistory&&0!==e.renderHistory.length?[...e.renderHistory].sort((e,t)=>e.timestamp-t.timestamp):[],[e.renderHistory]),n=useLimit("highlightUpdates.historyEvents"),s=r?1/0:n,l=useMemo(()=>i.slice(-s),[i,s]),a=l.length,c=l[t],d=useCallback(()=>{o(Math.max(0,t-1))},[t,o]),g=useCallback(()=>{o(Math.min(a-1,t+1))},[t,a,o]);return a<=1?null:_jsx(EventStepperFooter,{currentIndex:t,totalItems:a,onPrevious:d,onNext:g,itemLabel:"Render",subtitle:c?formatRelativeTime(new Date(c.timestamp)):void 0})}const styles=StyleSheet.create({container:{flex:1,backgroundColor:"transparent"},emptyContainer:{flex:1,alignItems:"center",justifyContent:"center",padding:32,gap:12},emptyTitle:{fontSize:16,fontWeight:"600",color:night.color.text},emptyText:{fontSize:13,color:night.color.textSecondary,textAlign:"center",lineHeight:18},viewToggleContainer:{flexDirection:"row",padding:12,gap:8},viewToggleCard:{flex:1,backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,padding:10,gap:4},viewToggleCardActive:{borderColor:night.color.accentBorderStrong,backgroundColor:night.color.accentSoft},viewToggleCardDisabled:{opacity:.5},todoBadge:{backgroundColor:night.color.fillSecondary,paddingHorizontal:6,paddingVertical:2,borderRadius:4,marginLeft:4},todoBadgeText:{fontSize:9,fontWeight:"700",color:night.color.textTertiary,letterSpacing:.3},viewToggleContent:{flexDirection:"row",alignItems:"center",gap:6},viewToggleLabel:{fontSize:10,fontWeight:"700",color:night.color.textSecondary,letterSpacing:.5},viewToggleLabelActive:{color:night.color.accent},viewToggleLabelDisabled:{color:night.color.textTertiary},viewToggleDescription:{fontSize:11,color:night.color.textTertiary,marginTop:2},contentScroll:{flex:1},contentContainer:{padding:12,paddingTop:0},noEventContainer:{padding:24,alignItems:"center"},noEventText:{fontSize:13,color:night.color.textTertiary},currentStateContainer:{gap:12},eventHeader:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,padding:12},eventHeaderLeft:{gap:2},eventTitle:{fontSize:15,fontWeight:"700",color:night.color.text},eventTime:{fontSize:11,color:night.color.textTertiary,fontFamily:monoFont},eventBadge:{flexDirection:"row",alignItems:"center",paddingHorizontal:10,paddingVertical:4,borderRadius:12,gap:6},eventBadgeDot:{width:6,height:6,borderRadius:3},eventBadgeText:{fontSize:10,fontWeight:"700",fontFamily:monoFont},section:{backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,overflow:"hidden"},sectionContent:{padding:12,paddingTop:8},causeContainer:{marginBottom:12},changedList:{marginBottom:12,paddingLeft:4},changedListTitle:{fontSize:11,fontWeight:"600",color:night.color.textSecondary,marginBottom:6},changedItem:{fontSize:12,color:night.color.text,fontFamily:monoFont,marginBottom:3,paddingLeft:8},propsScrollView:{maxHeight:150},propsJson:{fontSize:11,fontFamily:monoFont,color:night.color.text,backgroundColor:night.color.bg,padding:10,borderRadius:6},diffContainer:{gap:12},compareBar:{flexDirection:"row",backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,padding:10},compareSide:{flex:1,gap:4},compareLabelRow:{flexDirection:"row",alignItems:"center",gap:8},compareLabel:{fontSize:10,fontWeight:"700",letterSpacing:.5},compareActionBadge:{paddingHorizontal:6,paddingVertical:2,borderRadius:4},compareActionText:{fontSize:9,fontWeight:"600"},compareMeta:{flexDirection:"row",alignItems:"center",gap:6},compareIndex:{fontSize:12,fontWeight:"600",color:night.color.text},compareTime:{fontSize:10,color:night.color.textTertiary,fontFamily:monoFont},compareDivider:{width:30,alignItems:"center",justifyContent:"center"},compareArrow:{fontSize:16,color:night.color.textTertiary},diffSummary:{backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,padding:12},diffSummaryTitle:{fontSize:11,fontWeight:"600",color:night.color.textSecondary,marginBottom:8},diffChanges:{gap:4},diffChangeItem:{flexDirection:"row",alignItems:"center",gap:6},diffChangeIcon:{fontSize:12,fontWeight:"700",color:night.color.warning,fontFamily:monoFont},diffChangeKey:{fontSize:12,color:night.color.text,fontFamily:monoFont},diffNoChanges:{fontSize:12,color:night.color.textTertiary,fontStyle:"italic"},diffPlaceholder:{fontSize:12,color:night.color.textTertiary,fontStyle:"italic",textAlign:"center",padding:16},diffModeTabs:{flexDirection:"row",backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,padding:4,gap:4},diffModeTab:{flex:1,paddingVertical:8,paddingHorizontal:12,borderRadius:6,alignItems:"center"},diffModeTabActive:{backgroundColor:night.color.accentSoft},diffModeTabDisabled:{opacity:.4},diffModeTabText:{fontSize:10,fontWeight:"600",color:night.color.textSecondary,letterSpacing:.5},diffModeTabTextActive:{color:night.color.accent},diffModeTabTextDisabled:{color:night.color.textTertiary},causeDiffContainer:{gap:8,marginBottom:12},causeDiffRow:{flexDirection:"row",alignItems:"center",gap:8},causeDiffLabel:{fontSize:11,fontWeight:"600",color:night.color.textSecondary,minWidth:80},causeDiffValue:{fontSize:12,color:night.color.text,fontFamily:monoFont,fontWeight:"500"},diffChangesTitle:{fontSize:11,fontWeight:"600",color:night.color.textSecondary,marginBottom:6},treeDiffContainer:{backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,overflow:"hidden",minHeight:150},noDiffData:{padding:24,alignItems:"center",gap:8},noDiffDataTitle:{fontSize:13,fontWeight:"600",color:night.color.text},noDiffDataText:{fontSize:12,color:night.color.textTertiary,textAlign:"center",lineHeight:18},lockedBanner:{flexDirection:"row",alignItems:"center",justifyContent:"center",paddingVertical:10,paddingHorizontal:16,marginHorizontal:12,marginTop:8,backgroundColor:night.color.warningSoft,borderRadius:8,borderWidth:1,borderColor:night.color.warning+"30",gap:8},lockedBannerText:{color:night.color.warning,fontSize:13,fontWeight:"500"},lockedBannerSubtext:{color:night.color.textTertiary,fontSize:12}});export default RenderHistoryViewer;