@buoy-gg/highlight-updates 7.0.35 → 7.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +28 -6
  2. package/lib/commonjs/highlight-updates/HighlightUpdatesOverlay.js +1 -281
  3. package/lib/commonjs/highlight-updates/components/HighlightFilterView.js +1 -1474
  4. package/lib/commonjs/highlight-updates/components/HighlightUpdatesModal.js +1 -641
  5. package/lib/commonjs/highlight-updates/components/IdentifierBadge.js +1 -273
  6. package/lib/commonjs/highlight-updates/components/IsolatedRenderList.js +1 -188
  7. package/lib/commonjs/highlight-updates/components/ModalHeaderContent.js +1 -293
  8. package/lib/commonjs/highlight-updates/components/RenderCauseBadge.js +1 -508
  9. package/lib/commonjs/highlight-updates/components/RenderDetailView.js +1 -846
  10. package/lib/commonjs/highlight-updates/components/RenderHistoryViewer.js +1 -915
  11. package/lib/commonjs/highlight-updates/components/RenderListItem.js +1 -235
  12. package/lib/commonjs/highlight-updates/components/RendersCopySettingsView.js +1 -466
  13. package/lib/commonjs/highlight-updates/components/StatsDisplay.js +1 -73
  14. package/lib/commonjs/highlight-updates/types/copySettings.js +1 -107
  15. package/lib/commonjs/highlight-updates/utils/CommitProfiler.js +1 -446
  16. package/lib/commonjs/highlight-updates/utils/HighlightUpdatesController.js +1 -1920
  17. package/lib/commonjs/highlight-updates/utils/PerformanceLogger.js +1 -359
  18. package/lib/commonjs/highlight-updates/utils/ProfilerInterceptor.js +1 -371
  19. package/lib/commonjs/highlight-updates/utils/RenderCauseDetector.js +1 -1840
  20. package/lib/commonjs/highlight-updates/utils/RenderTracker.js +1 -952
  21. package/lib/commonjs/highlight-updates/utils/ViewTypeMapper.js +1 -264
  22. package/lib/commonjs/highlight-updates/utils/copySettingsStorage.js +1 -32
  23. package/lib/commonjs/highlight-updates/utils/devtoolsComponentNames.js +1 -188
  24. package/lib/commonjs/highlight-updates/utils/namedComposite.js +1 -41
  25. package/lib/commonjs/highlight-updates/utils/ownStateChanged.js +1 -103
  26. package/lib/commonjs/highlight-updates/utils/rawEventEmitter.js +1 -50
  27. package/lib/commonjs/highlight-updates/utils/renderExportFormatter.js +1 -58
  28. package/lib/commonjs/highlight-updates/utils/rendersExportFormatter.js +1 -485
  29. package/lib/commonjs/highlight-updates/utils/screenElements.js +1 -1046
  30. package/lib/commonjs/highlight-updates/utils/tapMatch.js +1 -58
  31. package/lib/commonjs/highlight-updates/utils/testIDs.js +1 -68
  32. package/lib/commonjs/highlight-updates/utils/touchCapture.js +1 -277
  33. package/lib/commonjs/index.js +1 -429
  34. package/lib/commonjs/preset.js +1 -278
  35. package/lib/commonjs/sync/highlightUpdatesSyncAdapter.js +1 -235
  36. package/lib/module/highlight-updates/HighlightUpdatesOverlay.js +1 -274
  37. package/lib/module/highlight-updates/components/HighlightFilterView.js +1 -1468
  38. package/lib/module/highlight-updates/components/HighlightUpdatesModal.js +1 -634
  39. package/lib/module/highlight-updates/components/IdentifierBadge.js +1 -265
  40. package/lib/module/highlight-updates/components/IsolatedRenderList.js +1 -183
  41. package/lib/module/highlight-updates/components/ModalHeaderContent.js +1 -288
  42. package/lib/module/highlight-updates/components/RenderCauseBadge.js +1 -499
  43. package/lib/module/highlight-updates/components/RenderDetailView.js +1 -840
  44. package/lib/module/highlight-updates/components/RenderHistoryViewer.js +1 -908
  45. package/lib/module/highlight-updates/components/RenderListItem.js +1 -230
  46. package/lib/module/highlight-updates/components/RendersCopySettingsView.js +1 -462
  47. package/lib/module/highlight-updates/components/StatsDisplay.js +1 -70
  48. package/lib/module/highlight-updates/types/copySettings.js +1 -102
  49. package/lib/module/highlight-updates/utils/CommitProfiler.js +1 -442
  50. package/lib/module/highlight-updates/utils/HighlightUpdatesController.js +1 -1916
  51. package/lib/module/highlight-updates/utils/PerformanceLogger.js +1 -353
  52. package/lib/module/highlight-updates/utils/ProfilerInterceptor.js +1 -358
  53. package/lib/module/highlight-updates/utils/RenderCauseDetector.js +1 -1830
  54. package/lib/module/highlight-updates/utils/RenderTracker.js +1 -949
  55. package/lib/module/highlight-updates/utils/ViewTypeMapper.js +1 -255
  56. package/lib/module/highlight-updates/utils/copySettingsStorage.js +1 -26
  57. package/lib/module/highlight-updates/utils/devtoolsComponentNames.js +1 -178
  58. package/lib/module/highlight-updates/utils/namedComposite.js +1 -36
  59. package/lib/module/highlight-updates/utils/ownStateChanged.js +1 -98
  60. package/lib/module/highlight-updates/utils/rawEventEmitter.js +1 -46
  61. package/lib/module/highlight-updates/utils/renderExportFormatter.js +1 -54
  62. package/lib/module/highlight-updates/utils/rendersExportFormatter.js +1 -478
  63. package/lib/module/highlight-updates/utils/screenElements.js +1 -1040
  64. package/lib/module/highlight-updates/utils/tapMatch.js +1 -52
  65. package/lib/module/highlight-updates/utils/testIDs.js +1 -60
  66. package/lib/module/highlight-updates/utils/touchCapture.js +1 -270
  67. package/lib/module/index.js +1 -130
  68. package/lib/module/preset.js +1 -272
  69. package/lib/module/sync/highlightUpdatesSyncAdapter.js +1 -230
  70. package/lib/typescript/highlight-updates/utils/screenElements.d.ts +52 -1
  71. package/lib/typescript/highlight-updates/utils/tapMatch.d.ts +11 -0
  72. package/lib/typescript/sync/highlightUpdatesSyncAdapter.d.ts +1 -1
  73. package/package.json +8 -8
  74. package/lib/typescript/highlight-updates/HighlightUpdatesOverlay.d.ts.map +0 -1
  75. package/lib/typescript/highlight-updates/components/HighlightFilterView.d.ts.map +0 -1
  76. package/lib/typescript/highlight-updates/components/HighlightUpdatesModal.d.ts.map +0 -1
  77. package/lib/typescript/highlight-updates/components/IdentifierBadge.d.ts.map +0 -1
  78. package/lib/typescript/highlight-updates/components/IsolatedRenderList.d.ts.map +0 -1
  79. package/lib/typescript/highlight-updates/components/ModalHeaderContent.d.ts.map +0 -1
  80. package/lib/typescript/highlight-updates/components/RenderCauseBadge.d.ts.map +0 -1
  81. package/lib/typescript/highlight-updates/components/RenderDetailView.d.ts.map +0 -1
  82. package/lib/typescript/highlight-updates/components/RenderHistoryViewer.d.ts.map +0 -1
  83. package/lib/typescript/highlight-updates/components/RenderListItem.d.ts.map +0 -1
  84. package/lib/typescript/highlight-updates/components/RendersCopySettingsView.d.ts.map +0 -1
  85. package/lib/typescript/highlight-updates/components/StatsDisplay.d.ts.map +0 -1
  86. package/lib/typescript/highlight-updates/types/copySettings.d.ts.map +0 -1
  87. package/lib/typescript/highlight-updates/utils/CommitProfiler.d.ts.map +0 -1
  88. package/lib/typescript/highlight-updates/utils/HighlightUpdatesController.d.ts.map +0 -1
  89. package/lib/typescript/highlight-updates/utils/PerformanceLogger.d.ts.map +0 -1
  90. package/lib/typescript/highlight-updates/utils/ProfilerInterceptor.d.ts.map +0 -1
  91. package/lib/typescript/highlight-updates/utils/RenderCauseDetector.d.ts.map +0 -1
  92. package/lib/typescript/highlight-updates/utils/RenderTracker.d.ts.map +0 -1
  93. package/lib/typescript/highlight-updates/utils/ViewTypeMapper.d.ts.map +0 -1
  94. package/lib/typescript/highlight-updates/utils/copySettingsStorage.d.ts.map +0 -1
  95. package/lib/typescript/highlight-updates/utils/devtoolsComponentNames.d.ts.map +0 -1
  96. package/lib/typescript/highlight-updates/utils/namedComposite.d.ts.map +0 -1
  97. package/lib/typescript/highlight-updates/utils/ownStateChanged.d.ts.map +0 -1
  98. package/lib/typescript/highlight-updates/utils/rawEventEmitter.d.ts.map +0 -1
  99. package/lib/typescript/highlight-updates/utils/renderExportFormatter.d.ts.map +0 -1
  100. package/lib/typescript/highlight-updates/utils/rendersExportFormatter.d.ts.map +0 -1
  101. package/lib/typescript/highlight-updates/utils/screenElements.d.ts.map +0 -1
  102. package/lib/typescript/highlight-updates/utils/tapMatch.d.ts.map +0 -1
  103. package/lib/typescript/highlight-updates/utils/testIDs.d.ts.map +0 -1
  104. package/lib/typescript/highlight-updates/utils/touchCapture.d.ts.map +0 -1
  105. package/lib/typescript/index.d.ts.map +0 -1
  106. package/lib/typescript/preset.d.ts.map +0 -1
  107. package/lib/typescript/sync/highlightUpdatesSyncAdapter.d.ts.map +0 -1
@@ -1,840 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * RenderDetailView
5
- *
6
- * Minimal, glanceable view for render details.
7
- * Design principle: Dev should understand WHY in 3 seconds.
8
- *
9
- * Layout:
10
- * - Header: Component name + native type
11
- * - Answer Card: Cause badges + hook change (THE answer)
12
- * - History Row: Compact inline navigation
13
- */
14
-
15
- import React, { useMemo, useState, useCallback } from "react";
16
- import { View, Text, TouchableOpacity, ScrollView, StyleSheet } from "react-native";
17
- import { CopyButton, formatRelativeTime, PlusIcon, MinusIcon, EventStepperFooter, Lock, night, useLimit, monoFont } from "@buoy-gg/shared-ui";
18
- import { TreeDiffViewer } from "@buoy-gg/shared-ui/dataViewer";
19
- import { CAUSE_CONFIG, COMPONENT_CAUSE_CONFIG } from "./RenderCauseBadge";
20
- import { generateSingleComponentExport } from "../utils/rendersExportFormatter";
21
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
22
- // Free tier limit for render history events
23
- export function RenderDetailView({
24
- render,
25
- disableInternalFooter = false,
26
- selectedEventIndex: externalIndex,
27
- onEventIndexChange: externalOnChange,
28
- onAddFilter,
29
- isPro = false
30
- }) {
31
- // Internal state for event index when not controlled externally
32
- const [internalIndex, setInternalIndex] = useState(0);
33
-
34
- // Use external or internal state
35
- const selectedEventIndex = externalIndex ?? internalIndex;
36
- const onEventIndexChange = externalOnChange ?? setInternalIndex;
37
-
38
- // Get events sorted by timestamp (oldest first)
39
- const events = useMemo(() => {
40
- if (!render.renderHistory || render.renderHistory.length === 0) {
41
- return [];
42
- }
43
- return [...render.renderHistory].sort((a, b) => a.timestamp - b.timestamp);
44
- }, [render.renderHistory]);
45
- const totalEvents = events.length;
46
- const currentEvent = events[selectedEventIndex];
47
-
48
- // `isPro` stays a prop so callers can force the unlimited view; the tier cap
49
- // applies otherwise. useLimit() already returns Infinity for Pro, so the two
50
- // agree — this only preserves the prop contract for cross-package callers.
51
- const tierLimit = useLimit("highlightUpdates.detailEvents");
52
- const eventLimit = isPro ? Infinity : tierLimit;
53
- const hiddenEventCount = useMemo(() => Math.max(0, totalEvents - eventLimit), [eventLimit, totalEvents]);
54
-
55
- // Use current event's cause if available, otherwise fall back to lastRenderCause
56
- const displayCause = currentEvent?.cause || render.lastRenderCause;
57
-
58
- // Navigation handlers
59
- const goToPrevious = useCallback(() => {
60
- if (selectedEventIndex > 0) {
61
- onEventIndexChange(selectedEventIndex - 1);
62
- }
63
- }, [selectedEventIndex, onEventIndexChange]);
64
- const goToNext = useCallback(() => {
65
- // Infinity - 1 is Infinity, so an unlimited tier just gets totalEvents - 1.
66
- const maxIndex = Math.min(eventLimit - 1, totalEvents - 1);
67
- if (selectedEventIndex < maxIndex) {
68
- onEventIndexChange(selectedEventIndex + 1);
69
- }
70
- }, [selectedEventIndex, totalEvents, onEventIndexChange, eventLimit]);
71
-
72
- // Memoize copy data
73
- const copyData = useMemo(() => generateSingleComponentExport(render), [render]);
74
-
75
- // Get component name (prefer componentName, fall back to displayName)
76
- const componentName = render.componentName || render.displayName;
77
- const nativeType = render.viewType;
78
-
79
- // Calculate render stats
80
- const renderDuration = render.lastRenderTime - render.firstRenderTime;
81
- const rendersPerSec = renderDuration > 0 ? (render.renderCount / (renderDuration / 1000)).toFixed(1) : render.renderCount.toString();
82
-
83
- // Determine if we should show footer (either history or filters)
84
- const showHistoryFooter = !disableInternalFooter && totalEvents > 1;
85
- return /*#__PURE__*/_jsxs(View, {
86
- style: styles.container,
87
- children: [/*#__PURE__*/_jsxs(View, {
88
- style: styles.header,
89
- children: [/*#__PURE__*/_jsxs(View, {
90
- style: styles.headerLeft,
91
- children: [/*#__PURE__*/_jsx(Text, {
92
- testID: "buoy-highlight-detail-name",
93
- style: styles.componentName,
94
- numberOfLines: 1,
95
- children: componentName
96
- }), /*#__PURE__*/_jsx(View, {
97
- style: styles.nativeTypeBadge,
98
- children: /*#__PURE__*/_jsx(Text, {
99
- testID: "buoy-highlight-detail-type",
100
- style: styles.nativeTypeText,
101
- children: nativeType
102
- })
103
- })]
104
- }), /*#__PURE__*/_jsx(CopyButton, {
105
- value: copyData,
106
- size: 14,
107
- testID: "buoy-highlight-detail-copy"
108
- })]
109
- }), /*#__PURE__*/_jsxs(ScrollView, {
110
- testID: "buoy-highlight-detail-scroll",
111
- style: styles.scrollView,
112
- contentContainerStyle: [styles.scrollContent, showHistoryFooter && {
113
- paddingBottom: 100
114
- }],
115
- showsVerticalScrollIndicator: false,
116
- children: [displayCause && /*#__PURE__*/_jsx(AnswerCard, {
117
- cause: displayCause,
118
- renderNumber: currentEvent?.renderNumber
119
- }), /*#__PURE__*/_jsx(DetailsSection, {
120
- render: render,
121
- rendersPerSec: rendersPerSec
122
- }), hiddenEventCount > 0 && /*#__PURE__*/_jsxs(View, {
123
- testID: "buoy-highlight-detail-locked",
124
- style: styles.lockedBanner,
125
- children: [/*#__PURE__*/_jsx(Lock, {
126
- size: 14,
127
- color: night.color.warning
128
- }), /*#__PURE__*/_jsxs(Text, {
129
- testID: "buoy-highlight-detail-locked-text",
130
- style: styles.lockedBannerText,
131
- children: [hiddenEventCount, " ", hiddenEventCount === 1 ? 'event' : 'events', " hidden"]
132
- }), /*#__PURE__*/_jsx(Text, {
133
- style: styles.lockedBannerSubtext,
134
- children: "Upgrade to Pro"
135
- })]
136
- }), onAddFilter && /*#__PURE__*/_jsx(QuickActionsSection, {
137
- render: render,
138
- onAddFilter: onAddFilter
139
- })]
140
- }), showHistoryFooter && /*#__PURE__*/_jsx(EventStepperFooter, {
141
- currentIndex: selectedEventIndex,
142
- totalItems: totalEvents,
143
- onPrevious: goToPrevious,
144
- onNext: goToNext,
145
- itemLabel: "Render",
146
- subtitle: currentEvent?.timestamp ? formatRelativeTime(new Date(currentEvent.timestamp)) : undefined,
147
- applySafeAreaInset: false,
148
- absolute: true
149
- })]
150
- });
151
- }
152
-
153
- /**
154
- * AnswerCard - The hero section showing WHY the component rendered
155
- * Design: Single badge + what changed below it
156
- */
157
- function AnswerCard({
158
- cause,
159
- renderNumber
160
- }) {
161
- // Use component cause if available, otherwise native cause
162
- const displayCauseType = cause.componentCause || cause.type;
163
- const config = cause.componentCause ? COMPONENT_CAUSE_CONFIG[cause.componentCause] : CAUSE_CONFIG[cause.type];
164
- const hasHookChanges = cause.hookChanges && cause.hookChanges.length > 0;
165
- const hasChangedKeys = cause.changedKeys && cause.changedKeys.length > 0;
166
-
167
- // Get contextual label based on cause type
168
- const getLabel = () => {
169
- if (cause.type === "mount") return "First render";
170
- if (displayCauseType === "parent") return "Triggered by";
171
- return "Changed:";
172
- };
173
- return /*#__PURE__*/_jsxs(View, {
174
- testID: "buoy-highlight-detail-cause",
175
- style: styles.answerCard,
176
- children: [/*#__PURE__*/_jsxs(View, {
177
- style: styles.causeBadgeRow,
178
- children: [/*#__PURE__*/_jsx(Text, {
179
- testID: "buoy-highlight-detail-cause-label",
180
- style: styles.causeLabel,
181
- children: getLabel()
182
- }), /*#__PURE__*/_jsx(View, {
183
- style: [styles.causeBadgeLarge, {
184
- backgroundColor: config.color + "20"
185
- }],
186
- children: /*#__PURE__*/_jsx(Text, {
187
- testID: "buoy-highlight-detail-cause-badge",
188
- style: [styles.causeBadgeLargeText, {
189
- color: config.color
190
- }],
191
- children: config.label.toUpperCase()
192
- })
193
- })]
194
- }), hasHookChanges && /*#__PURE__*/_jsx(View, {
195
- style: styles.hookChangesContainer,
196
- children: cause.hookChanges.map((hook, index) => {
197
- const hookKey = `${hook.type}[${hook.index}]`;
198
- const oldValue = {
199
- [hookKey]: hook.previousValue
200
- };
201
- const newValue = {
202
- [hookKey]: hook.currentValue
203
- };
204
- return /*#__PURE__*/_jsx(View, {
205
- style: styles.hookDiffContainer,
206
- children: /*#__PURE__*/_jsx(TreeDiffViewer, {
207
- oldValue: oldValue,
208
- newValue: newValue,
209
- theme: "dark",
210
- showUnchanged: false
211
- })
212
- }, index);
213
- })
214
- }), !hasHookChanges && hasChangedKeys && /*#__PURE__*/_jsx(View, {
215
- style: styles.propsChangesContainer,
216
- children: cause.changedKeys.filter(k => !k.includes("(ref only)")).slice(0, 5).map((key, index) => /*#__PURE__*/_jsx(View, {
217
- style: styles.propChangeChip,
218
- children: /*#__PURE__*/_jsx(Text, {
219
- testID: `buoy-highlight-detail-changed-${index}`,
220
- style: styles.propChangeText,
221
- children: key
222
- })
223
- }, index))
224
- })]
225
- });
226
- }
227
-
228
- /**
229
- * DetailsSection - Component identifiers, measurements, and stats
230
- * Helps devs find the component in their codebase
231
- */
232
- function DetailsSection({
233
- render,
234
- rendersPerSec
235
- }) {
236
- const hasIdentifiers = render.testID || render.nativeID || render.accessibilityLabel;
237
- const hasMeasurements = render.measurements;
238
- return /*#__PURE__*/_jsxs(View, {
239
- style: styles.detailsSection,
240
- children: [hasIdentifiers && /*#__PURE__*/_jsxs(View, {
241
- testID: "buoy-highlight-detail-identifiers",
242
- style: styles.detailsCard,
243
- children: [/*#__PURE__*/_jsx(Text, {
244
- style: styles.detailsCardTitle,
245
- children: "Identifiers"
246
- }), render.testID && /*#__PURE__*/_jsx(DetailRow, {
247
- label: "testID",
248
- value: render.testID
249
- }), render.nativeID && /*#__PURE__*/_jsx(DetailRow, {
250
- label: "nativeID",
251
- value: render.nativeID
252
- }), render.accessibilityLabel && /*#__PURE__*/_jsx(DetailRow, {
253
- label: "a11y",
254
- value: render.accessibilityLabel
255
- })]
256
- }), /*#__PURE__*/_jsxs(View, {
257
- testID: "buoy-highlight-detail-stats",
258
- style: styles.statsRow,
259
- children: [/*#__PURE__*/_jsxs(View, {
260
- testID: "buoy-highlight-detail-stat-renders",
261
- style: styles.statItem,
262
- children: [/*#__PURE__*/_jsx(Text, {
263
- testID: "buoy-highlight-detail-stat-renders-value",
264
- style: [styles.statValue, {
265
- color: render.color
266
- }],
267
- children: render.renderCount
268
- }), /*#__PURE__*/_jsx(Text, {
269
- style: styles.statLabel,
270
- children: "renders"
271
- })]
272
- }), /*#__PURE__*/_jsx(View, {
273
- style: styles.statDivider
274
- }), /*#__PURE__*/_jsxs(View, {
275
- testID: "buoy-highlight-detail-stat-rate",
276
- style: styles.statItem,
277
- children: [/*#__PURE__*/_jsx(Text, {
278
- testID: "buoy-highlight-detail-stat-rate-value",
279
- style: styles.statValue,
280
- children: rendersPerSec
281
- }), /*#__PURE__*/_jsx(Text, {
282
- style: styles.statLabel,
283
- children: "/sec"
284
- })]
285
- }), /*#__PURE__*/_jsx(View, {
286
- style: styles.statDivider
287
- }), /*#__PURE__*/_jsxs(View, {
288
- testID: "buoy-highlight-detail-stat-tag",
289
- style: styles.statItem,
290
- children: [/*#__PURE__*/_jsx(Text, {
291
- testID: "buoy-highlight-detail-stat-tag-value",
292
- style: styles.statValue,
293
- children: render.nativeTag
294
- }), /*#__PURE__*/_jsx(Text, {
295
- style: styles.statLabel,
296
- children: "tag"
297
- })]
298
- })]
299
- }), hasMeasurements && /*#__PURE__*/_jsxs(View, {
300
- testID: "buoy-highlight-detail-measure",
301
- style: styles.measurementsRow,
302
- children: [/*#__PURE__*/_jsxs(View, {
303
- style: styles.measurementItem,
304
- children: [/*#__PURE__*/_jsx(Text, {
305
- style: styles.measurementLabel,
306
- children: "x"
307
- }), /*#__PURE__*/_jsx(Text, {
308
- testID: "buoy-highlight-detail-measure-x",
309
- style: styles.measurementValue,
310
- children: Math.round(render.measurements.x)
311
- })]
312
- }), /*#__PURE__*/_jsxs(View, {
313
- style: styles.measurementItem,
314
- children: [/*#__PURE__*/_jsx(Text, {
315
- style: styles.measurementLabel,
316
- children: "y"
317
- }), /*#__PURE__*/_jsx(Text, {
318
- testID: "buoy-highlight-detail-measure-y",
319
- style: styles.measurementValue,
320
- children: Math.round(render.measurements.y)
321
- })]
322
- }), /*#__PURE__*/_jsxs(View, {
323
- style: styles.measurementItem,
324
- children: [/*#__PURE__*/_jsx(Text, {
325
- style: styles.measurementLabel,
326
- children: "w"
327
- }), /*#__PURE__*/_jsx(Text, {
328
- testID: "buoy-highlight-detail-measure-w",
329
- style: styles.measurementValue,
330
- children: Math.round(render.measurements.width)
331
- })]
332
- }), /*#__PURE__*/_jsxs(View, {
333
- style: styles.measurementItem,
334
- children: [/*#__PURE__*/_jsx(Text, {
335
- style: styles.measurementLabel,
336
- children: "h"
337
- }), /*#__PURE__*/_jsx(Text, {
338
- testID: "buoy-highlight-detail-measure-h",
339
- style: styles.measurementValue,
340
- children: Math.round(render.measurements.height)
341
- })]
342
- })]
343
- })]
344
- });
345
- }
346
-
347
- /**
348
- * DetailRow - Single row for identifier display
349
- */
350
- function DetailRow({
351
- label,
352
- value
353
- }) {
354
- const handle = `buoy-highlight-detail-id-${label.toLowerCase()}`;
355
- return /*#__PURE__*/_jsxs(View, {
356
- testID: handle,
357
- style: styles.detailRow,
358
- children: [/*#__PURE__*/_jsx(Text, {
359
- style: styles.detailLabel,
360
- children: label
361
- }), /*#__PURE__*/_jsx(Text, {
362
- testID: `${handle}-value`,
363
- style: styles.detailValue,
364
- numberOfLines: 1,
365
- children: value
366
- })]
367
- });
368
- }
369
-
370
- /**
371
- * QuickActionsSection - Quick filter actions for the component
372
- * Users select a filter option, then use action buttons to include/exclude
373
- */
374
- function QuickActionsSection({
375
- render,
376
- onAddFilter
377
- }) {
378
- const [selectedIndex, setSelectedIndex] = useState(null);
379
-
380
- // Build list of available filter options (most specific to most general)
381
- const filterOptions = useMemo(() => {
382
- const options = [];
383
-
384
- // Most specific first
385
- if (render.nativeID) {
386
- options.push({
387
- type: "nativeID",
388
- value: render.nativeID,
389
- label: "nativeID"
390
- });
391
- }
392
- if (render.testID) {
393
- options.push({
394
- type: "testID",
395
- value: render.testID,
396
- label: "testID"
397
- });
398
- }
399
- if (render.accessibilityLabel) {
400
- options.push({
401
- type: "accessibilityLabel",
402
- value: render.accessibilityLabel,
403
- label: "a11y"
404
- });
405
- }
406
- if (render.componentName) {
407
- options.push({
408
- type: "component",
409
- value: render.componentName,
410
- label: "component"
411
- });
412
- }
413
- // Most general last (always available)
414
- options.push({
415
- type: "viewType",
416
- value: render.viewType,
417
- label: "viewType"
418
- });
419
- return options;
420
- }, [render]);
421
- const selectedOption = selectedIndex !== null ? filterOptions[selectedIndex] : null;
422
- const handleSelectOption = useCallback(index => {
423
- setSelectedIndex(prev => prev === index ? null : index);
424
- }, []);
425
- const handleInclude = useCallback(() => {
426
- if (selectedOption) {
427
- onAddFilter({
428
- type: selectedOption.type,
429
- value: selectedOption.value
430
- }, "include");
431
- setSelectedIndex(null);
432
- }
433
- }, [selectedOption, onAddFilter]);
434
- const handleExclude = useCallback(() => {
435
- if (selectedOption) {
436
- onAddFilter({
437
- type: selectedOption.type,
438
- value: selectedOption.value
439
- }, "exclude");
440
- setSelectedIndex(null);
441
- }
442
- }, [selectedOption, onAddFilter]);
443
- return /*#__PURE__*/_jsxs(View, {
444
- testID: "buoy-highlight-quick",
445
- style: styles.quickActionsSection,
446
- children: [/*#__PURE__*/_jsx(Text, {
447
- style: styles.quickActionsTitle,
448
- children: "Quick Filters"
449
- }), /*#__PURE__*/_jsx(View, {
450
- style: styles.filterOptionsList,
451
- children: filterOptions.map((option, index) => /*#__PURE__*/_jsx(FilterOptionCard, {
452
- testID: `buoy-highlight-quick-${option.type.toLowerCase()}`,
453
- label: option.label,
454
- value: option.value,
455
- isSelected: selectedIndex === index,
456
- onSelect: () => handleSelectOption(index)
457
- }, option.type))
458
- }), /*#__PURE__*/_jsxs(View, {
459
- style: styles.filterActionButtons,
460
- children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
461
- testID: "buoy-highlight-quick-include",
462
- accessibilityRole: "button",
463
- accessibilityLabel: "Only show this",
464
- style: [styles.filterActionButton, styles.filterActionButtonInclude, !selectedOption && styles.filterActionButtonDisabled],
465
- onPress: handleInclude,
466
- disabled: !selectedOption,
467
- activeOpacity: 0.7,
468
- children: [/*#__PURE__*/_jsx(PlusIcon, {
469
- size: 14,
470
- color: selectedOption ? night.color.accent : night.color.textTertiary
471
- }), /*#__PURE__*/_jsx(Text, {
472
- style: [styles.filterActionButtonText, {
473
- color: selectedOption ? night.color.accent : night.color.textTertiary
474
- }],
475
- children: "Only Show This"
476
- })]
477
- }), /*#__PURE__*/_jsxs(TouchableOpacity, {
478
- testID: "buoy-highlight-quick-exclude",
479
- accessibilityRole: "button",
480
- accessibilityLabel: "Hide this",
481
- style: [styles.filterActionButton, styles.filterActionButtonExclude, !selectedOption && styles.filterActionButtonDisabled],
482
- onPress: handleExclude,
483
- disabled: !selectedOption,
484
- activeOpacity: 0.7,
485
- children: [/*#__PURE__*/_jsx(MinusIcon, {
486
- size: 14,
487
- color: selectedOption ? night.color.danger : night.color.textTertiary
488
- }), /*#__PURE__*/_jsx(Text, {
489
- style: [styles.filterActionButtonText, {
490
- color: selectedOption ? night.color.danger : night.color.textTertiary
491
- }],
492
- children: "Hide This"
493
- })]
494
- })]
495
- })]
496
- });
497
- }
498
-
499
- /**
500
- * FilterOptionCard - A selectable filter option card
501
- */
502
- function FilterOptionCard({
503
- testID,
504
- label,
505
- value,
506
- isSelected,
507
- onSelect
508
- }) {
509
- return /*#__PURE__*/_jsxs(TouchableOpacity, {
510
- testID: testID,
511
- accessibilityRole: "button",
512
- accessibilityLabel: `${label}, ${value}`,
513
- style: [styles.filterOptionCard, isSelected && styles.filterOptionCardSelected],
514
- onPress: onSelect,
515
- activeOpacity: 0.7,
516
- children: [/*#__PURE__*/_jsx(Text, {
517
- style: [styles.filterOptionLabel, isSelected && styles.filterOptionLabelSelected],
518
- children: label
519
- }), /*#__PURE__*/_jsx(Text, {
520
- testID: testID ? `${testID}-value` : undefined,
521
- style: [styles.filterOptionValue, isSelected && styles.filterOptionValueSelected],
522
- numberOfLines: 1,
523
- children: value
524
- })]
525
- });
526
- }
527
- const styles = StyleSheet.create({
528
- container: {
529
- flex: 1,
530
- // Transparent so JsModal's ToolBackground shows through (the modal paints opaque base beneath it).
531
- backgroundColor: "transparent"
532
- },
533
- // Header
534
- header: {
535
- flexDirection: "row",
536
- alignItems: "center",
537
- justifyContent: "center",
538
- gap: 12,
539
- padding: 16,
540
- paddingBottom: 0
541
- },
542
- // ScrollView
543
- scrollView: {
544
- flex: 1
545
- },
546
- scrollContent: {
547
- padding: 16,
548
- paddingTop: 12,
549
- paddingBottom: 80,
550
- gap: 12
551
- },
552
- headerLeft: {
553
- flex: 1,
554
- flexDirection: "row",
555
- alignItems: "center",
556
- justifyContent: "center",
557
- gap: 10
558
- },
559
- componentName: {
560
- fontSize: 18,
561
- fontWeight: "700",
562
- color: night.color.text,
563
- flexShrink: 1
564
- },
565
- nativeTypeBadge: {
566
- // Inset display chip — the night track color.
567
- backgroundColor: night.color.bg,
568
- paddingVertical: 3,
569
- paddingHorizontal: 8,
570
- borderRadius: 4
571
- },
572
- nativeTypeText: {
573
- fontSize: 11,
574
- fontWeight: "600",
575
- color: night.color.textTertiary,
576
- fontFamily: monoFont
577
- },
578
- // Answer Card
579
- answerCard: {
580
- backgroundColor: night.color.surface,
581
- borderRadius: 8,
582
- borderWidth: 1,
583
- borderColor: night.color.border,
584
- padding: 12,
585
- gap: 6
586
- },
587
- causeBadgeRow: {
588
- flexDirection: "row",
589
- alignItems: "center",
590
- gap: 8
591
- },
592
- causeBadgeLarge: {
593
- paddingVertical: 4,
594
- paddingHorizontal: 10,
595
- borderRadius: 4
596
- },
597
- causeBadgeLargeText: {
598
- fontSize: 11,
599
- fontWeight: "700",
600
- letterSpacing: 0.5
601
- },
602
- causeLabel: {
603
- fontSize: 12,
604
- color: night.color.textSecondary,
605
- fontWeight: "500"
606
- },
607
- hookChangesContainer: {
608
- gap: 6
609
- },
610
- hookDiffContainer: {
611
- // Inset code box — the night track color.
612
- backgroundColor: night.color.bg,
613
- borderRadius: 6,
614
- overflow: "hidden"
615
- },
616
- propsChangesContainer: {
617
- flexDirection: "row",
618
- flexWrap: "wrap",
619
- gap: 4
620
- },
621
- propChangeChip: {
622
- // Inset display chip — the night track color.
623
- backgroundColor: night.color.bg,
624
- paddingVertical: 2,
625
- paddingHorizontal: 6,
626
- borderRadius: 4
627
- },
628
- propChangeText: {
629
- fontSize: 11,
630
- color: night.color.text,
631
- fontFamily: monoFont
632
- },
633
- // Details Section
634
- detailsSection: {
635
- gap: 10
636
- },
637
- detailsCard: {
638
- backgroundColor: night.color.surface,
639
- borderRadius: 8,
640
- borderWidth: 1,
641
- borderColor: night.color.border,
642
- padding: 12,
643
- gap: 6
644
- },
645
- detailsCardTitle: {
646
- fontSize: 10,
647
- fontWeight: "600",
648
- color: night.color.textTertiary,
649
- letterSpacing: 0.5,
650
- textTransform: "uppercase",
651
- marginBottom: 4
652
- },
653
- detailRow: {
654
- flexDirection: "row",
655
- alignItems: "center",
656
- gap: 8
657
- },
658
- detailLabel: {
659
- fontSize: 11,
660
- fontWeight: "600",
661
- color: night.color.textSecondary,
662
- minWidth: 55
663
- },
664
- detailValue: {
665
- fontSize: 12,
666
- color: night.color.text,
667
- fontFamily: monoFont,
668
- flex: 1
669
- },
670
- // Stats Row
671
- statsRow: {
672
- flexDirection: "row",
673
- alignItems: "center",
674
- justifyContent: "center",
675
- backgroundColor: night.color.surface,
676
- borderRadius: 8,
677
- borderWidth: 1,
678
- borderColor: night.color.border,
679
- paddingVertical: 10,
680
- paddingHorizontal: 16
681
- },
682
- statItem: {
683
- flex: 1,
684
- alignItems: "center"
685
- },
686
- statValue: {
687
- fontSize: 16,
688
- fontWeight: "700",
689
- color: night.color.text,
690
- fontFamily: monoFont
691
- },
692
- statLabel: {
693
- fontSize: 10,
694
- color: night.color.textTertiary,
695
- marginTop: 2
696
- },
697
- statDivider: {
698
- width: 1,
699
- height: 24,
700
- backgroundColor: night.color.border,
701
- marginHorizontal: 12
702
- },
703
- // Measurements Row
704
- measurementsRow: {
705
- flexDirection: "row",
706
- alignItems: "center",
707
- justifyContent: "space-around",
708
- backgroundColor: night.color.surface,
709
- borderRadius: 8,
710
- borderWidth: 1,
711
- borderColor: night.color.border,
712
- paddingVertical: 8,
713
- paddingHorizontal: 12
714
- },
715
- measurementItem: {
716
- flexDirection: "row",
717
- alignItems: "baseline",
718
- gap: 4
719
- },
720
- measurementLabel: {
721
- fontSize: 10,
722
- fontWeight: "600",
723
- color: night.color.textTertiary,
724
- textTransform: "uppercase"
725
- },
726
- measurementValue: {
727
- fontSize: 12,
728
- fontWeight: "600",
729
- color: night.color.text,
730
- fontFamily: monoFont
731
- },
732
- // Quick Actions Section
733
- quickActionsSection: {
734
- backgroundColor: night.color.surface,
735
- borderRadius: 8,
736
- borderWidth: 1,
737
- borderColor: night.color.border,
738
- padding: 12,
739
- gap: 10
740
- },
741
- quickActionsTitle: {
742
- fontSize: 10,
743
- fontWeight: "600",
744
- color: night.color.textTertiary,
745
- letterSpacing: 0.5,
746
- textTransform: "uppercase",
747
- marginBottom: 2
748
- },
749
- filterOptionsList: {
750
- gap: 6
751
- },
752
- filterOptionCard: {
753
- flexDirection: "row",
754
- alignItems: "center",
755
- backgroundColor: night.color.surfaceElevated,
756
- borderRadius: 6,
757
- paddingVertical: 10,
758
- paddingHorizontal: 12,
759
- borderWidth: 1,
760
- borderColor: "transparent",
761
- gap: 10
762
- },
763
- filterOptionCardSelected: {
764
- borderColor: night.color.accentBorderStrong,
765
- backgroundColor: night.color.accentSoft
766
- },
767
- filterOptionLabel: {
768
- fontSize: 10,
769
- fontWeight: "600",
770
- color: night.color.textTertiary,
771
- minWidth: 70
772
- },
773
- filterOptionLabelSelected: {
774
- color: night.color.accent
775
- },
776
- filterOptionValue: {
777
- fontSize: 12,
778
- color: night.color.text,
779
- fontFamily: monoFont,
780
- flex: 1
781
- },
782
- filterOptionValueSelected: {
783
- color: night.color.text
784
- },
785
- filterActionButtons: {
786
- flexDirection: "row",
787
- gap: 8,
788
- marginTop: 12
789
- },
790
- filterActionButton: {
791
- flexDirection: "row",
792
- alignItems: "center",
793
- justifyContent: "center",
794
- gap: 4,
795
- paddingVertical: 8,
796
- paddingHorizontal: 10,
797
- borderRadius: 6,
798
- borderWidth: 1
799
- },
800
- filterActionButtonInclude: {
801
- backgroundColor: night.color.accentSoft,
802
- borderColor: night.color.accentBorderStrong
803
- },
804
- filterActionButtonExclude: {
805
- backgroundColor: night.color.dangerSoft,
806
- borderColor: night.color.danger + "40"
807
- },
808
- filterActionButtonDisabled: {
809
- backgroundColor: night.color.surfaceElevated,
810
- borderColor: night.color.border,
811
- opacity: 0.5
812
- },
813
- filterActionButtonText: {
814
- fontSize: 11,
815
- fontWeight: "600"
816
- },
817
- // Locked Banner
818
- lockedBanner: {
819
- flexDirection: "row",
820
- alignItems: "center",
821
- justifyContent: "center",
822
- backgroundColor: night.color.surface,
823
- borderRadius: 8,
824
- borderWidth: 1,
825
- borderColor: night.color.warning + "40",
826
- paddingVertical: 12,
827
- paddingHorizontal: 16,
828
- gap: 8
829
- },
830
- lockedBannerText: {
831
- color: night.color.warning,
832
- fontSize: 13,
833
- fontWeight: "600"
834
- },
835
- lockedBannerSubtext: {
836
- color: night.color.textTertiary,
837
- fontSize: 12
838
- }
839
- });
840
- export default RenderDetailView;
1
+ "use strict";import React,{useMemo,useState,useCallback}from"react";import{View,Text,TouchableOpacity,ScrollView,StyleSheet}from"react-native";import{CopyButton,formatRelativeTime,PlusIcon,MinusIcon,EventStepperFooter,Lock,night,useLimit,monoFont}from"@buoy-gg/shared-ui";import{TreeDiffViewer}from"@buoy-gg/shared-ui/dataViewer";import{CAUSE_CONFIG,COMPONENT_CAUSE_CONFIG}from"./RenderCauseBadge";import{generateSingleComponentExport}from"../utils/rendersExportFormatter";import{jsx as _jsx,jsxs as _jsxs}from"react/jsx-runtime";export function RenderDetailView({render:e,disableInternalFooter:t=!1,selectedEventIndex:i,onEventIndexChange:o,onAddFilter:l,isPro:r=!1}){const[s,n]=useState(0),a=i??s,c=o??n,d=useMemo(()=>e.renderHistory&&0!==e.renderHistory.length?[...e.renderHistory].sort((e,t)=>e.timestamp-t.timestamp):[],[e.renderHistory]),h=d.length,u=d[a],g=useLimit("highlightUpdates.detailEvents"),y=r?1/0:g,x=useMemo(()=>Math.max(0,h-y),[y,h]),b=u?.cause||e.lastRenderCause,p=useCallback(()=>{a>0&&c(a-1)},[a,c]),m=useCallback(()=>{const e=Math.min(y-1,h-1);a<e&&c(a+1)},[a,h,c,y]),f=useMemo(()=>generateSingleComponentExport(e),[e]),C=e.componentName||e.displayName,w=e.viewType,j=e.lastRenderTime-e.firstRenderTime,I=j>0?(e.renderCount/(j/1e3)).toFixed(1):e.renderCount.toString(),T=!t&&h>1;return _jsxs(View,{style:styles.container,children:[_jsxs(View,{style:styles.header,children:[_jsxs(View,{style:styles.headerLeft,children:[_jsx(Text,{testID:"buoy-highlight-detail-name",style:styles.componentName,numberOfLines:1,children:C}),_jsx(View,{style:styles.nativeTypeBadge,children:_jsx(Text,{testID:"buoy-highlight-detail-type",style:styles.nativeTypeText,children:w})})]}),_jsx(CopyButton,{value:f,size:14,testID:"buoy-highlight-detail-copy"})]}),_jsxs(ScrollView,{testID:"buoy-highlight-detail-scroll",style:styles.scrollView,contentContainerStyle:[styles.scrollContent,T&&{paddingBottom:100}],showsVerticalScrollIndicator:!1,children:[b&&_jsx(AnswerCard,{cause:b,renderNumber:u?.renderNumber}),_jsx(DetailsSection,{render:e,rendersPerSec:I}),x>0&&_jsxs(View,{testID:"buoy-highlight-detail-locked",style:styles.lockedBanner,children:[_jsx(Lock,{size:14,color:night.color.warning}),_jsxs(Text,{testID:"buoy-highlight-detail-locked-text",style:styles.lockedBannerText,children:[x," ",1===x?"event":"events"," hidden"]}),_jsx(Text,{style:styles.lockedBannerSubtext,children:"Upgrade to Pro"})]}),l&&_jsx(QuickActionsSection,{render:e,onAddFilter:l})]}),T&&_jsx(EventStepperFooter,{currentIndex:a,totalItems:h,onPrevious:p,onNext:m,itemLabel:"Render",subtitle:u?.timestamp?formatRelativeTime(new Date(u.timestamp)):void 0,applySafeAreaInset:!1,absolute:!0})]})}function AnswerCard({cause:e,renderNumber:t}){const i=e.componentCause||e.type,o=e.componentCause?COMPONENT_CAUSE_CONFIG[e.componentCause]:CAUSE_CONFIG[e.type],l=e.hookChanges&&e.hookChanges.length>0,r=e.changedKeys&&e.changedKeys.length>0;return _jsxs(View,{testID:"buoy-highlight-detail-cause",style:styles.answerCard,children:[_jsxs(View,{style:styles.causeBadgeRow,children:[_jsx(Text,{testID:"buoy-highlight-detail-cause-label",style:styles.causeLabel,children:"mount"===e.type?"First render":"parent"===i?"Triggered by":"Changed:"}),_jsx(View,{style:[styles.causeBadgeLarge,{backgroundColor:o.color+"20"}],children:_jsx(Text,{testID:"buoy-highlight-detail-cause-badge",style:[styles.causeBadgeLargeText,{color:o.color}],children:o.label.toUpperCase()})})]}),l&&_jsx(View,{style:styles.hookChangesContainer,children:e.hookChanges.map((e,t)=>{const i=`${e.type}[${e.index}]`,o={[i]:e.previousValue},l={[i]:e.currentValue};return _jsx(View,{style:styles.hookDiffContainer,children:_jsx(TreeDiffViewer,{oldValue:o,newValue:l,theme:"dark",showUnchanged:!1})},t)})}),!l&&r&&_jsx(View,{style:styles.propsChangesContainer,children:e.changedKeys.filter(e=>!e.includes("(ref only)")).slice(0,5).map((e,t)=>_jsx(View,{style:styles.propChangeChip,children:_jsx(Text,{testID:`buoy-highlight-detail-changed-${t}`,style:styles.propChangeText,children:e})},t))})]})}function DetailsSection({render:e,rendersPerSec:t}){const i=e.testID||e.nativeID||e.accessibilityLabel,o=e.measurements;return _jsxs(View,{style:styles.detailsSection,children:[i&&_jsxs(View,{testID:"buoy-highlight-detail-identifiers",style:styles.detailsCard,children:[_jsx(Text,{style:styles.detailsCardTitle,children:"Identifiers"}),e.testID&&_jsx(DetailRow,{label:"testID",value:e.testID}),e.nativeID&&_jsx(DetailRow,{label:"nativeID",value:e.nativeID}),e.accessibilityLabel&&_jsx(DetailRow,{label:"a11y",value:e.accessibilityLabel})]}),_jsxs(View,{testID:"buoy-highlight-detail-stats",style:styles.statsRow,children:[_jsxs(View,{testID:"buoy-highlight-detail-stat-renders",style:styles.statItem,children:[_jsx(Text,{testID:"buoy-highlight-detail-stat-renders-value",style:[styles.statValue,{color:e.color}],children:e.renderCount}),_jsx(Text,{style:styles.statLabel,children:"renders"})]}),_jsx(View,{style:styles.statDivider}),_jsxs(View,{testID:"buoy-highlight-detail-stat-rate",style:styles.statItem,children:[_jsx(Text,{testID:"buoy-highlight-detail-stat-rate-value",style:styles.statValue,children:t}),_jsx(Text,{style:styles.statLabel,children:"/sec"})]}),_jsx(View,{style:styles.statDivider}),_jsxs(View,{testID:"buoy-highlight-detail-stat-tag",style:styles.statItem,children:[_jsx(Text,{testID:"buoy-highlight-detail-stat-tag-value",style:styles.statValue,children:e.nativeTag}),_jsx(Text,{style:styles.statLabel,children:"tag"})]})]}),o&&_jsxs(View,{testID:"buoy-highlight-detail-measure",style:styles.measurementsRow,children:[_jsxs(View,{style:styles.measurementItem,children:[_jsx(Text,{style:styles.measurementLabel,children:"x"}),_jsx(Text,{testID:"buoy-highlight-detail-measure-x",style:styles.measurementValue,children:Math.round(e.measurements.x)})]}),_jsxs(View,{style:styles.measurementItem,children:[_jsx(Text,{style:styles.measurementLabel,children:"y"}),_jsx(Text,{testID:"buoy-highlight-detail-measure-y",style:styles.measurementValue,children:Math.round(e.measurements.y)})]}),_jsxs(View,{style:styles.measurementItem,children:[_jsx(Text,{style:styles.measurementLabel,children:"w"}),_jsx(Text,{testID:"buoy-highlight-detail-measure-w",style:styles.measurementValue,children:Math.round(e.measurements.width)})]}),_jsxs(View,{style:styles.measurementItem,children:[_jsx(Text,{style:styles.measurementLabel,children:"h"}),_jsx(Text,{testID:"buoy-highlight-detail-measure-h",style:styles.measurementValue,children:Math.round(e.measurements.height)})]})]})]})}function DetailRow({label:e,value:t}){const i=`buoy-highlight-detail-id-${e.toLowerCase()}`;return _jsxs(View,{testID:i,style:styles.detailRow,children:[_jsx(Text,{style:styles.detailLabel,children:e}),_jsx(Text,{testID:`${i}-value`,style:styles.detailValue,numberOfLines:1,children:t})]})}function QuickActionsSection({render:e,onAddFilter:t}){const[i,o]=useState(null),l=useMemo(()=>{const t=[];return e.nativeID&&t.push({type:"nativeID",value:e.nativeID,label:"nativeID"}),e.testID&&t.push({type:"testID",value:e.testID,label:"testID"}),e.accessibilityLabel&&t.push({type:"accessibilityLabel",value:e.accessibilityLabel,label:"a11y"}),e.componentName&&t.push({type:"component",value:e.componentName,label:"component"}),t.push({type:"viewType",value:e.viewType,label:"viewType"}),t},[e]),r=null!==i?l[i]:null,s=useCallback(e=>{o(t=>t===e?null:e)},[]),n=useCallback(()=>{r&&(t({type:r.type,value:r.value},"include"),o(null))},[r,t]),a=useCallback(()=>{r&&(t({type:r.type,value:r.value},"exclude"),o(null))},[r,t]);return _jsxs(View,{testID:"buoy-highlight-quick",style:styles.quickActionsSection,children:[_jsx(Text,{style:styles.quickActionsTitle,children:"Quick Filters"}),_jsx(View,{style:styles.filterOptionsList,children:l.map((e,t)=>_jsx(FilterOptionCard,{testID:`buoy-highlight-quick-${e.type.toLowerCase()}`,label:e.label,value:e.value,isSelected:i===t,onSelect:()=>s(t)},e.type))}),_jsxs(View,{style:styles.filterActionButtons,children:[_jsxs(TouchableOpacity,{testID:"buoy-highlight-quick-include",accessibilityRole:"button",accessibilityLabel:"Only show this",style:[styles.filterActionButton,styles.filterActionButtonInclude,!r&&styles.filterActionButtonDisabled],onPress:n,disabled:!r,activeOpacity:.7,children:[_jsx(PlusIcon,{size:14,color:r?night.color.accent:night.color.textTertiary}),_jsx(Text,{style:[styles.filterActionButtonText,{color:r?night.color.accent:night.color.textTertiary}],children:"Only Show This"})]}),_jsxs(TouchableOpacity,{testID:"buoy-highlight-quick-exclude",accessibilityRole:"button",accessibilityLabel:"Hide this",style:[styles.filterActionButton,styles.filterActionButtonExclude,!r&&styles.filterActionButtonDisabled],onPress:a,disabled:!r,activeOpacity:.7,children:[_jsx(MinusIcon,{size:14,color:r?night.color.danger:night.color.textTertiary}),_jsx(Text,{style:[styles.filterActionButtonText,{color:r?night.color.danger:night.color.textTertiary}],children:"Hide This"})]})]})]})}function FilterOptionCard({testID:e,label:t,value:i,isSelected:o,onSelect:l}){return _jsxs(TouchableOpacity,{testID:e,accessibilityRole:"button",accessibilityLabel:`${t}, ${i}`,style:[styles.filterOptionCard,o&&styles.filterOptionCardSelected],onPress:l,activeOpacity:.7,children:[_jsx(Text,{style:[styles.filterOptionLabel,o&&styles.filterOptionLabelSelected],children:t}),_jsx(Text,{testID:e?`${e}-value`:void 0,style:[styles.filterOptionValue,o&&styles.filterOptionValueSelected],numberOfLines:1,children:i})]})}const styles=StyleSheet.create({container:{flex:1,backgroundColor:"transparent"},header:{flexDirection:"row",alignItems:"center",justifyContent:"center",gap:12,padding:16,paddingBottom:0},scrollView:{flex:1},scrollContent:{padding:16,paddingTop:12,paddingBottom:80,gap:12},headerLeft:{flex:1,flexDirection:"row",alignItems:"center",justifyContent:"center",gap:10},componentName:{fontSize:18,fontWeight:"700",color:night.color.text,flexShrink:1},nativeTypeBadge:{backgroundColor:night.color.bg,paddingVertical:3,paddingHorizontal:8,borderRadius:4},nativeTypeText:{fontSize:11,fontWeight:"600",color:night.color.textTertiary,fontFamily:monoFont},answerCard:{backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,padding:12,gap:6},causeBadgeRow:{flexDirection:"row",alignItems:"center",gap:8},causeBadgeLarge:{paddingVertical:4,paddingHorizontal:10,borderRadius:4},causeBadgeLargeText:{fontSize:11,fontWeight:"700",letterSpacing:.5},causeLabel:{fontSize:12,color:night.color.textSecondary,fontWeight:"500"},hookChangesContainer:{gap:6},hookDiffContainer:{backgroundColor:night.color.bg,borderRadius:6,overflow:"hidden"},propsChangesContainer:{flexDirection:"row",flexWrap:"wrap",gap:4},propChangeChip:{backgroundColor:night.color.bg,paddingVertical:2,paddingHorizontal:6,borderRadius:4},propChangeText:{fontSize:11,color:night.color.text,fontFamily:monoFont},detailsSection:{gap:10},detailsCard:{backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,padding:12,gap:6},detailsCardTitle:{fontSize:10,fontWeight:"600",color:night.color.textTertiary,letterSpacing:.5,textTransform:"uppercase",marginBottom:4},detailRow:{flexDirection:"row",alignItems:"center",gap:8},detailLabel:{fontSize:11,fontWeight:"600",color:night.color.textSecondary,minWidth:55},detailValue:{fontSize:12,color:night.color.text,fontFamily:monoFont,flex:1},statsRow:{flexDirection:"row",alignItems:"center",justifyContent:"center",backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,paddingVertical:10,paddingHorizontal:16},statItem:{flex:1,alignItems:"center"},statValue:{fontSize:16,fontWeight:"700",color:night.color.text,fontFamily:monoFont},statLabel:{fontSize:10,color:night.color.textTertiary,marginTop:2},statDivider:{width:1,height:24,backgroundColor:night.color.border,marginHorizontal:12},measurementsRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-around",backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,paddingVertical:8,paddingHorizontal:12},measurementItem:{flexDirection:"row",alignItems:"baseline",gap:4},measurementLabel:{fontSize:10,fontWeight:"600",color:night.color.textTertiary,textTransform:"uppercase"},measurementValue:{fontSize:12,fontWeight:"600",color:night.color.text,fontFamily:monoFont},quickActionsSection:{backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.border,padding:12,gap:10},quickActionsTitle:{fontSize:10,fontWeight:"600",color:night.color.textTertiary,letterSpacing:.5,textTransform:"uppercase",marginBottom:2},filterOptionsList:{gap:6},filterOptionCard:{flexDirection:"row",alignItems:"center",backgroundColor:night.color.surfaceElevated,borderRadius:6,paddingVertical:10,paddingHorizontal:12,borderWidth:1,borderColor:"transparent",gap:10},filterOptionCardSelected:{borderColor:night.color.accentBorderStrong,backgroundColor:night.color.accentSoft},filterOptionLabel:{fontSize:10,fontWeight:"600",color:night.color.textTertiary,minWidth:70},filterOptionLabelSelected:{color:night.color.accent},filterOptionValue:{fontSize:12,color:night.color.text,fontFamily:monoFont,flex:1},filterOptionValueSelected:{color:night.color.text},filterActionButtons:{flexDirection:"row",gap:8,marginTop:12},filterActionButton:{flexDirection:"row",alignItems:"center",justifyContent:"center",gap:4,paddingVertical:8,paddingHorizontal:10,borderRadius:6,borderWidth:1},filterActionButtonInclude:{backgroundColor:night.color.accentSoft,borderColor:night.color.accentBorderStrong},filterActionButtonExclude:{backgroundColor:night.color.dangerSoft,borderColor:night.color.danger+"40"},filterActionButtonDisabled:{backgroundColor:night.color.surfaceElevated,borderColor:night.color.border,opacity:.5},filterActionButtonText:{fontSize:11,fontWeight:"600"},lockedBanner:{flexDirection:"row",alignItems:"center",justifyContent:"center",backgroundColor:night.color.surface,borderRadius:8,borderWidth:1,borderColor:night.color.warning+"40",paddingVertical:12,paddingHorizontal:16,gap:8},lockedBannerText:{color:night.color.warning,fontSize:13,fontWeight:"600"},lockedBannerSubtext:{color:night.color.textTertiary,fontSize:12}});export default RenderDetailView;