@buoy-gg/highlight-updates 2.1.12 → 2.1.14

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 (64) hide show
  1. package/lib/commonjs/highlight-updates/HighlightUpdatesOverlay.js +1 -285
  2. package/lib/commonjs/highlight-updates/components/HighlightFilterView.js +1 -1371
  3. package/lib/commonjs/highlight-updates/components/HighlightUpdatesModal.js +1 -591
  4. package/lib/commonjs/highlight-updates/components/IdentifierBadge.js +1 -267
  5. package/lib/commonjs/highlight-updates/components/IsolatedRenderList.js +1 -178
  6. package/lib/commonjs/highlight-updates/components/ModalHeaderContent.js +1 -303
  7. package/lib/commonjs/highlight-updates/components/RenderCauseBadge.js +1 -500
  8. package/lib/commonjs/highlight-updates/components/RenderDetailView.js +1 -830
  9. package/lib/commonjs/highlight-updates/components/RenderHistoryViewer.js +1 -894
  10. package/lib/commonjs/highlight-updates/components/RenderListItem.js +1 -220
  11. package/lib/commonjs/highlight-updates/components/StatsDisplay.js +1 -70
  12. package/lib/commonjs/highlight-updates/components/index.js +1 -97
  13. package/lib/commonjs/highlight-updates/utils/HighlightUpdatesController.js +1 -1435
  14. package/lib/commonjs/highlight-updates/utils/PerformanceLogger.js +1 -359
  15. package/lib/commonjs/highlight-updates/utils/ProfilerInterceptor.js +1 -371
  16. package/lib/commonjs/highlight-updates/utils/RenderCauseDetector.js +1 -1828
  17. package/lib/commonjs/highlight-updates/utils/RenderTracker.js +1 -903
  18. package/lib/commonjs/highlight-updates/utils/ViewTypeMapper.js +1 -264
  19. package/lib/commonjs/highlight-updates/utils/renderExportFormatter.js +1 -58
  20. package/lib/commonjs/index.js +1 -311
  21. package/lib/commonjs/preset.js +1 -278
  22. package/lib/module/highlight-updates/HighlightUpdatesOverlay.js +1 -278
  23. package/lib/module/highlight-updates/components/HighlightFilterView.js +1 -1365
  24. package/lib/module/highlight-updates/components/HighlightUpdatesModal.js +1 -585
  25. package/lib/module/highlight-updates/components/IdentifierBadge.js +1 -259
  26. package/lib/module/highlight-updates/components/IsolatedRenderList.js +1 -174
  27. package/lib/module/highlight-updates/components/ModalHeaderContent.js +1 -298
  28. package/lib/module/highlight-updates/components/RenderCauseBadge.js +1 -491
  29. package/lib/module/highlight-updates/components/RenderDetailView.js +1 -826
  30. package/lib/module/highlight-updates/components/RenderHistoryViewer.js +1 -888
  31. package/lib/module/highlight-updates/components/RenderListItem.js +1 -215
  32. package/lib/module/highlight-updates/components/StatsDisplay.js +1 -67
  33. package/lib/module/highlight-updates/components/index.js +1 -16
  34. package/lib/module/highlight-updates/utils/HighlightUpdatesController.js +1 -1431
  35. package/lib/module/highlight-updates/utils/PerformanceLogger.js +1 -353
  36. package/lib/module/highlight-updates/utils/ProfilerInterceptor.js +1 -358
  37. package/lib/module/highlight-updates/utils/RenderCauseDetector.js +1 -1818
  38. package/lib/module/highlight-updates/utils/RenderTracker.js +1 -900
  39. package/lib/module/highlight-updates/utils/ViewTypeMapper.js +1 -255
  40. package/lib/module/highlight-updates/utils/renderExportFormatter.js +1 -54
  41. package/lib/module/index.js +1 -71
  42. package/lib/module/preset.js +1 -272
  43. package/package.json +7 -7
  44. package/lib/typescript/highlight-updates/HighlightUpdatesOverlay.d.ts.map +0 -1
  45. package/lib/typescript/highlight-updates/components/HighlightFilterView.d.ts.map +0 -1
  46. package/lib/typescript/highlight-updates/components/HighlightUpdatesModal.d.ts.map +0 -1
  47. package/lib/typescript/highlight-updates/components/IdentifierBadge.d.ts.map +0 -1
  48. package/lib/typescript/highlight-updates/components/IsolatedRenderList.d.ts.map +0 -1
  49. package/lib/typescript/highlight-updates/components/ModalHeaderContent.d.ts.map +0 -1
  50. package/lib/typescript/highlight-updates/components/RenderCauseBadge.d.ts.map +0 -1
  51. package/lib/typescript/highlight-updates/components/RenderDetailView.d.ts.map +0 -1
  52. package/lib/typescript/highlight-updates/components/RenderHistoryViewer.d.ts.map +0 -1
  53. package/lib/typescript/highlight-updates/components/RenderListItem.d.ts.map +0 -1
  54. package/lib/typescript/highlight-updates/components/StatsDisplay.d.ts.map +0 -1
  55. package/lib/typescript/highlight-updates/components/index.d.ts.map +0 -1
  56. package/lib/typescript/highlight-updates/utils/HighlightUpdatesController.d.ts.map +0 -1
  57. package/lib/typescript/highlight-updates/utils/PerformanceLogger.d.ts.map +0 -1
  58. package/lib/typescript/highlight-updates/utils/ProfilerInterceptor.d.ts.map +0 -1
  59. package/lib/typescript/highlight-updates/utils/RenderCauseDetector.d.ts.map +0 -1
  60. package/lib/typescript/highlight-updates/utils/RenderTracker.d.ts.map +0 -1
  61. package/lib/typescript/highlight-updates/utils/ViewTypeMapper.d.ts.map +0 -1
  62. package/lib/typescript/highlight-updates/utils/renderExportFormatter.d.ts.map +0 -1
  63. package/lib/typescript/index.d.ts.map +0 -1
  64. package/lib/typescript/preset.d.ts.map +0 -1
@@ -1,591 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.HighlightUpdatesModal = HighlightUpdatesModal;
7
- exports.default = void 0;
8
- var _react = _interopRequireWildcard(require("react"));
9
- var _reactNative = require("react-native");
10
- var _sharedUi = require("@buoy-gg/shared-ui");
11
- var _license = require("@buoy-gg/license");
12
- var _HighlightUpdatesController = _interopRequireDefault(require("../utils/HighlightUpdatesController"));
13
- var _RenderTracker = require("../utils/RenderTracker");
14
- var _RenderDetailView = require("./RenderDetailView");
15
- var _HighlightFilterView = require("./HighlightFilterView");
16
- var _IsolatedRenderList = require("./IsolatedRenderList");
17
- var _ModalHeaderContent = require("./ModalHeaderContent");
18
- var _RenderHistoryViewer = require("./RenderHistoryViewer");
19
- var _jsxRuntime = require("react/jsx-runtime");
20
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
21
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
22
- /**
23
- * HighlightUpdatesModal
24
- *
25
- * Main modal interface for the Highlight Updates dev tool.
26
- * Shows a list of tracked component renders with controls for
27
- * start/stop, clear, and filtering.
28
- *
29
- * PERFORMANCE OPTIMIZED:
30
- * - Uses isolated components to prevent parent re-renders
31
- * - Stats display is isolated (StatsDisplay)
32
- * - Render list is isolated (IsolatedRenderList)
33
- * - Header components are memoized
34
- * - Uses refs for values not displayed in UI
35
- */
36
-
37
- // Disabled banner - memoized since props rarely change
38
- const DisabledBanner = /*#__PURE__*/_react.default.memo(function DisabledBanner() {
39
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
40
- style: styles.disabledBanner,
41
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Power, {
42
- size: 14,
43
- color: _sharedUi.buoyColors.warning
44
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
45
- style: styles.disabledText,
46
- children: "Render tracking is disabled"
47
- })]
48
- });
49
- });
50
-
51
- /**
52
- * Format render data for copying to clipboard as JSON
53
- */
54
- function formatRenderDataForClipboard() {
55
- const renders = _RenderTracker.RenderTracker.getRenders();
56
- const exportData = {
57
- exportedAt: new Date().toISOString(),
58
- totalComponents: renders.length,
59
- totalRenders: renders.reduce((sum, r) => sum + r.renderCount, 0),
60
- components: renders.map(render => ({
61
- componentName: render.componentName || render.displayName,
62
- viewType: render.viewType,
63
- nativeTag: render.nativeTag,
64
- testID: render.testID,
65
- nativeID: render.nativeID,
66
- accessibilityLabel: render.accessibilityLabel,
67
- renderCount: render.renderCount,
68
- firstRenderTime: render.firstRenderTime,
69
- lastRenderTime: render.lastRenderTime,
70
- lastRenderCause: render.lastRenderCause ? {
71
- type: render.lastRenderCause.type,
72
- componentCause: render.lastRenderCause.componentCause,
73
- changedKeys: render.lastRenderCause.changedKeys,
74
- hookChanges: render.lastRenderCause.hookChanges?.map(h => ({
75
- type: h.type,
76
- index: h.index,
77
- description: h.description
78
- }))
79
- } : null,
80
- renderHistory: render.renderHistory?.map(event => ({
81
- renderNumber: event.renderNumber,
82
- timestamp: event.timestamp,
83
- cause: {
84
- type: event.cause.type,
85
- componentCause: event.cause.componentCause,
86
- changedKeys: event.cause.changedKeys
87
- }
88
- }))
89
- }))
90
- };
91
- return JSON.stringify(exportData, null, 2);
92
- }
93
- function HighlightUpdatesModal({
94
- visible,
95
- onClose,
96
- onBack,
97
- onMinimize,
98
- enableSharedModalDimensions = false,
99
- initialNativeTag,
100
- onInitialNativeTagHandled
101
- }) {
102
- const isPro = (0, _license.useIsPro)();
103
-
104
- // ============================================================================
105
- // TRACKING STATE - subscribed via isolated component
106
- // ============================================================================
107
- const [isTracking, setIsTracking] = (0, _react.useState)(false);
108
- const [isFrozen, setIsFrozen] = (0, _react.useState)(() => _HighlightUpdatesController.default.getFrozen());
109
-
110
- // Track if there are renders for header clear button state
111
- const [hasRenders, setHasRenders] = (0, _react.useState)(() => _RenderTracker.RenderTracker.getStats().totalComponents > 0);
112
-
113
- // ============================================================================
114
- // UI STATE - kept in parent for view switching
115
- // ============================================================================
116
- const [selectedRender, setSelectedRender] = (0, _react.useState)(null);
117
- const [selectedRenderIndex, setSelectedRenderIndex] = (0, _react.useState)(0);
118
- const [showFilterView, setShowFilterView] = (0, _react.useState)(false);
119
- const [filterViewActiveTab, setFilterViewActiveTab] = (0, _react.useState)("filters");
120
- const [detailViewActiveTab, setDetailViewActiveTab] = (0, _react.useState)("details");
121
- const [historyEventIndex, setHistoryEventIndex] = (0, _react.useState)(0);
122
- const [searchText, setSearchText] = (0, _react.useState)("");
123
- const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
124
- const searchInputRef = (0, _react.useRef)(null);
125
-
126
- // Track the renders list for navigation
127
- const rendersListRef = (0, _react.useRef)([]);
128
-
129
- // ============================================================================
130
- // FILTER STATE - use ref for filter config, state for display count only
131
- // ============================================================================
132
- const filtersRef = (0, _react.useRef)(_RenderTracker.RenderTracker.getFilters());
133
- const [activeFilterCount, setActiveFilterCount] = (0, _react.useState)(() => {
134
- const filters = _RenderTracker.RenderTracker.getFilters();
135
- return filters.includePatterns.length + filters.excludePatterns.length;
136
- });
137
-
138
- // Expose filters via state for HighlightFilterView (it needs to display them)
139
- const [filters, setFilters] = (0, _react.useState)(() => _RenderTracker.RenderTracker.getFilters());
140
-
141
- // ============================================================================
142
- // SETTINGS STATE
143
- // ============================================================================
144
- const [settings, setSettings] = (0, _react.useState)(() => _RenderTracker.RenderTracker.getSettings());
145
-
146
- // ============================================================================
147
- // PERSISTENCE REFS - prevent saving on initial load
148
- // ============================================================================
149
- const hasLoadedTrackingState = (0, _react.useRef)(false);
150
- const hasLoadedFilters = (0, _react.useRef)(false);
151
- const hasLoadedSettings = (0, _react.useRef)(false);
152
-
153
- // ============================================================================
154
- // LOAD PERSISTED STATE
155
- // ============================================================================
156
-
157
- // Tracking state is intentionally NOT persisted.
158
- // Always starts OFF to prevent infinite re-render loops on load where
159
- // the overlay highlights its own components before exclusion filters can take effect.
160
- // The user must explicitly enable tracking each session.
161
- (0, _react.useEffect)(() => {
162
- if (!visible || hasLoadedTrackingState.current) return;
163
- hasLoadedTrackingState.current = true;
164
- }, [visible]);
165
-
166
- // Load persisted filters on mount
167
- (0, _react.useEffect)(() => {
168
- if (!visible || hasLoadedFilters.current) return;
169
- const loadFilters = async () => {
170
- try {
171
- const storedFilters = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.highlightUpdates.filters());
172
- if (storedFilters) {
173
- const parsedFilters = JSON.parse(storedFilters);
174
- const restoredFilters = {
175
- includeTestID: new Set(parsedFilters.includeTestID || []),
176
- includeNativeID: new Set(parsedFilters.includeNativeID || []),
177
- includeViewType: new Set(parsedFilters.includeViewType || []),
178
- includeComponent: new Set(parsedFilters.includeComponent || []),
179
- excludeTestID: new Set(parsedFilters.excludeTestID || []),
180
- excludeNativeID: new Set(parsedFilters.excludeNativeID || []),
181
- excludeViewType: new Set(parsedFilters.excludeViewType || []),
182
- excludeComponent: new Set(parsedFilters.excludeComponent || []),
183
- includePatterns: parsedFilters.includePatterns || [],
184
- excludePatterns: parsedFilters.excludePatterns || []
185
- };
186
- _RenderTracker.RenderTracker.setFilters(restoredFilters);
187
- const newFilters = _RenderTracker.RenderTracker.getFilters();
188
- filtersRef.current = newFilters;
189
- setFilters(newFilters);
190
- setActiveFilterCount(newFilters.includePatterns.length + newFilters.excludePatterns.length);
191
- }
192
- hasLoadedFilters.current = true;
193
- } catch (error) {
194
- // Failed to load filters
195
- }
196
- };
197
- loadFilters();
198
- }, [visible]);
199
-
200
- // Save filters when they change
201
- (0, _react.useEffect)(() => {
202
- if (!hasLoadedFilters.current) return;
203
- const saveFilters = async () => {
204
- try {
205
- const filtersToSave = {
206
- includeTestID: Array.from(filters.includeTestID),
207
- includeNativeID: Array.from(filters.includeNativeID),
208
- includeViewType: Array.from(filters.includeViewType),
209
- includeComponent: Array.from(filters.includeComponent),
210
- excludeTestID: Array.from(filters.excludeTestID),
211
- excludeNativeID: Array.from(filters.excludeNativeID),
212
- excludeViewType: Array.from(filters.excludeViewType),
213
- excludeComponent: Array.from(filters.excludeComponent),
214
- includePatterns: filters.includePatterns,
215
- excludePatterns: filters.excludePatterns
216
- };
217
- await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.highlightUpdates.filters(), JSON.stringify(filtersToSave));
218
- } catch (error) {
219
- // Failed to save filters
220
- }
221
- };
222
- saveFilters();
223
- }, [filters]);
224
-
225
- // Load persisted settings on mount
226
- (0, _react.useEffect)(() => {
227
- if (!visible || hasLoadedSettings.current) return;
228
- const loadSettings = async () => {
229
- try {
230
- const storedSettings = await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.highlightUpdates.settings());
231
- if (storedSettings) {
232
- const parsedSettings = JSON.parse(storedSettings);
233
- // Never restore excludeDevTools or performanceLogging from persistence -
234
- // excludeDevTools must always default to true to prevent infinite re-render loops
235
- const {
236
- performanceLogging: _ignored,
237
- excludeDevTools: _alwaysTrue,
238
- ...settingsToRestore
239
- } = parsedSettings;
240
- _RenderTracker.RenderTracker.setSettings(settingsToRestore);
241
- setSettings(_RenderTracker.RenderTracker.getSettings());
242
- }
243
- hasLoadedSettings.current = true;
244
- } catch (error) {
245
- hasLoadedSettings.current = true;
246
- }
247
- };
248
- loadSettings();
249
- }, [visible]);
250
-
251
- // Save settings when they change
252
- (0, _react.useEffect)(() => {
253
- if (!hasLoadedSettings.current) return;
254
- const saveSettings = async () => {
255
- try {
256
- // Never persist excludeDevTools - it must always default to true on startup
257
- const {
258
- performanceLogging: _ignored,
259
- excludeDevTools: _neverPersist,
260
- ...settingsToSave
261
- } = settings;
262
- await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.highlightUpdates.settings(), JSON.stringify(settingsToSave));
263
- } catch (error) {
264
- // Failed to save settings
265
- }
266
- };
267
- saveSettings();
268
- }, [settings]);
269
-
270
- // ============================================================================
271
- // SUBSCRIPTIONS - only for tracking state, not renders
272
- // ============================================================================
273
-
274
- // Subscribe to tracking state changes only
275
- (0, _react.useEffect)(() => {
276
- const unsubscribeState = _RenderTracker.RenderTracker.subscribeToState(state => {
277
- setIsTracking(state.isTracking);
278
- });
279
- return () => {
280
- unsubscribeState();
281
- };
282
- }, []);
283
-
284
- // Subscribe to freeze state changes
285
- (0, _react.useEffect)(() => {
286
- const unsubscribeFreeze = _HighlightUpdatesController.default.subscribeToFreeze(frozen => {
287
- setIsFrozen(frozen);
288
- });
289
- return () => {
290
- unsubscribeFreeze();
291
- };
292
- }, []);
293
-
294
- // Focus search input when activated
295
- (0, _react.useEffect)(() => {
296
- if (isSearchActive) {
297
- requestAnimationFrame(() => {
298
- searchInputRef.current?.focus();
299
- });
300
- }
301
- }, [isSearchActive]);
302
-
303
- // Clear spotlight when modal is closed
304
- (0, _react.useEffect)(() => {
305
- if (!visible) {
306
- _HighlightUpdatesController.default.setSpotlight(null);
307
- }
308
- }, [visible]);
309
-
310
- // ============================================================================
311
- // DEEP LINK NAVIGATION - "Click Overlay Badge → Jump to Detail"
312
- // ============================================================================
313
-
314
- // Handle initial navigation when a badge is tapped
315
- (0, _react.useEffect)(() => {
316
- if (visible && initialNativeTag != null) {
317
- // Look up the render by nativeTag
318
- const render = _RenderTracker.RenderTracker.getRender(String(initialNativeTag));
319
- if (render) {
320
- // Navigate to detail view for this component
321
- setSelectedRender(render);
322
- setSelectedRenderIndex(0);
323
- setShowFilterView(false);
324
- // Set spotlight to show which component is being viewed
325
- _HighlightUpdatesController.default.setSpotlight(render.nativeTag);
326
- }
327
- // Notify parent that we've handled the navigation
328
- onInitialNativeTagHandled?.();
329
- }
330
- }, [visible, initialNativeTag, onInitialNativeTagHandled]);
331
-
332
- // ============================================================================
333
- // CALLBACKS - stable references for child components
334
- // ============================================================================
335
-
336
- const handleToggleTracking = (0, _react.useCallback)(() => {
337
- if (!_HighlightUpdatesController.default.isInitialized()) {
338
- _HighlightUpdatesController.default.initialize();
339
- }
340
- _HighlightUpdatesController.default.toggle();
341
- }, []);
342
- const handleToggleFreeze = (0, _react.useCallback)(() => {
343
- _HighlightUpdatesController.default.toggleFreeze();
344
- }, []);
345
- const handleClear = (0, _react.useCallback)(() => {
346
- _HighlightUpdatesController.default.clearRenderCounts();
347
- setHasRenders(false);
348
- }, []);
349
-
350
- // Pass a lazy getter so CopyButton calls it at click time with fresh data
351
- const copyData = hasRenders ? formatRenderDataForClipboard : "";
352
- const handleSearch = (0, _react.useCallback)(text => {
353
- setSearchText(text);
354
- }, []);
355
- const handleRenderPress = (0, _react.useCallback)((render, index, allRenders) => {
356
- setSelectedRender(render);
357
- setSelectedRenderIndex(index);
358
- setDetailViewActiveTab("details"); // Reset to details tab when selecting a new render
359
- setHistoryEventIndex(0); // Reset history event index when selecting a new render
360
- rendersListRef.current = allRenders;
361
- // Set spotlight to show which component is being viewed
362
- _HighlightUpdatesController.default.setSpotlight(render.nativeTag);
363
- }, []);
364
- const handleRendersChange = (0, _react.useCallback)(renders => {
365
- rendersListRef.current = renders;
366
- }, []);
367
- const handleBackFromDetail = (0, _react.useCallback)(() => {
368
- setSelectedRender(null);
369
- setSelectedRenderIndex(0);
370
- // Clear the spotlight
371
- _HighlightUpdatesController.default.setSpotlight(null);
372
- }, []);
373
- const handlePreviousRender = (0, _react.useCallback)(() => {
374
- const renders = rendersListRef.current;
375
- if (selectedRenderIndex > 0) {
376
- const newIndex = selectedRenderIndex - 1;
377
- const newRender = renders[newIndex];
378
- if (newRender) {
379
- setSelectedRender(newRender);
380
- setSelectedRenderIndex(newIndex);
381
- _HighlightUpdatesController.default.setSpotlight(newRender.nativeTag);
382
- }
383
- }
384
- }, [selectedRenderIndex]);
385
- const handleNextRender = (0, _react.useCallback)(() => {
386
- const renders = rendersListRef.current;
387
- if (selectedRenderIndex < renders.length - 1) {
388
- const newIndex = selectedRenderIndex + 1;
389
- const newRender = renders[newIndex];
390
- if (newRender) {
391
- setSelectedRender(newRender);
392
- setSelectedRenderIndex(newIndex);
393
- _HighlightUpdatesController.default.setSpotlight(newRender.nativeTag);
394
- }
395
- }
396
- }, [selectedRenderIndex]);
397
- const handleBackFromFilter = (0, _react.useCallback)(() => {
398
- setShowFilterView(false);
399
- }, []);
400
- const handleFilterToggle = (0, _react.useCallback)(() => {
401
- setShowFilterView(true);
402
- }, []);
403
- const handleSearchToggle = (0, _react.useCallback)(() => {
404
- setIsSearchActive(true);
405
- }, []);
406
- const handleSearchClose = (0, _react.useCallback)(() => {
407
- setIsSearchActive(false);
408
- }, []);
409
- const handleFilterChange = (0, _react.useCallback)(newFilters => {
410
- _RenderTracker.RenderTracker.setFilters(newFilters);
411
- const updatedFilters = _RenderTracker.RenderTracker.getFilters();
412
- filtersRef.current = updatedFilters;
413
- setFilters(updatedFilters);
414
- setActiveFilterCount(updatedFilters.includePatterns.length + updatedFilters.excludePatterns.length);
415
- }, []);
416
-
417
- // Handler for adding a filter from the detail view (quick actions)
418
- const handleAddFilter = (0, _react.useCallback)((pattern, mode) => {
419
- const currentFilters = _RenderTracker.RenderTracker.getFilters();
420
- const newFilters = {};
421
- if (mode === "include") {
422
- // Check if pattern already exists
423
- const exists = currentFilters.includePatterns.some(p => p.type === pattern.type && p.value === pattern.value);
424
- if (!exists) {
425
- newFilters.includePatterns = [...currentFilters.includePatterns, pattern];
426
- }
427
- } else {
428
- // Check if pattern already exists
429
- const exists = currentFilters.excludePatterns.some(p => p.type === pattern.type && p.value === pattern.value);
430
- if (!exists) {
431
- newFilters.excludePatterns = [...currentFilters.excludePatterns, pattern];
432
- }
433
- }
434
- if (Object.keys(newFilters).length > 0) {
435
- handleFilterChange(newFilters);
436
- // Go back to the list view after adding filter
437
- setSelectedRender(null);
438
- setSelectedRenderIndex(0);
439
- // Clear the spotlight
440
- _HighlightUpdatesController.default.setSpotlight(null);
441
- }
442
- }, [handleFilterChange]);
443
- const handleSettingsChange = (0, _react.useCallback)(newSettings => {
444
- _RenderTracker.RenderTracker.setSettings(newSettings);
445
- setSettings(_RenderTracker.RenderTracker.getSettings());
446
- }, []);
447
-
448
- // Callback for IsolatedRenderList to update hasRenders (for header clear button)
449
- const handleStatsChange = (0, _react.useCallback)(stats => {
450
- setHasRenders(stats.totalComponents > 0);
451
- }, []);
452
-
453
- // ============================================================================
454
- // HEADER RENDERING - using memoized components
455
- // ============================================================================
456
-
457
- const renderHeaderContent = (0, _react.useCallback)(() => {
458
- if (showFilterView) {
459
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ModalHeaderContent.FilterViewHeader, {
460
- onBack: handleBackFromFilter,
461
- activeTab: filterViewActiveTab,
462
- onTabChange: setFilterViewActiveTab,
463
- activeFilterCount: activeFilterCount
464
- });
465
- }
466
- if (selectedRender) {
467
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ModalHeaderContent.DetailViewHeader, {
468
- onBack: handleBackFromDetail,
469
- activeTab: detailViewActiveTab,
470
- onTabChange: setDetailViewActiveTab,
471
- hasHistory: (selectedRender.renderHistory?.length ?? 0) > 0
472
- });
473
- }
474
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ModalHeaderContent.MainListHeader, {
475
- onBack: onBack,
476
- isSearchActive: isSearchActive,
477
- searchText: searchText,
478
- onSearchChange: handleSearch,
479
- onSearchToggle: handleSearchToggle,
480
- onSearchClose: handleSearchClose,
481
- onFilterToggle: handleFilterToggle,
482
- onToggleTracking: handleToggleTracking,
483
- onToggleFreeze: handleToggleFreeze,
484
- onClear: handleClear,
485
- copyData: copyData,
486
- isTracking: isTracking,
487
- isFrozen: isFrozen,
488
- activeFilterCount: activeFilterCount,
489
- hasRenders: hasRenders,
490
- searchInputRef: searchInputRef
491
- });
492
- }, [showFilterView, selectedRender, onBack, isSearchActive, searchText, isTracking, isFrozen, activeFilterCount, hasRenders, filterViewActiveTab, detailViewActiveTab, handleBackFromFilter, handleBackFromDetail, handleSearch, handleSearchToggle, handleSearchClose, handleFilterToggle, handleToggleTracking, handleToggleFreeze, handleClear, copyData]);
493
-
494
- // ============================================================================
495
- // RENDER
496
- // ============================================================================
497
-
498
- const persistenceKey = enableSharedModalDimensions ? _sharedUi.devToolsStorageKeys.modal.root() : _sharedUi.devToolsStorageKeys.highlightUpdates.modal();
499
- if (!visible) return null;
500
-
501
- // Footer for navigating through the renders list or history events
502
- const totalRenders = rendersListRef.current.length;
503
- const footerNode = selectedRender ? detailViewActiveTab === "details" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.EventStepperFooter, {
504
- currentIndex: selectedRenderIndex,
505
- totalItems: totalRenders,
506
- onPrevious: handlePreviousRender,
507
- onNext: handleNextRender,
508
- itemLabel: "Component",
509
- subtitle: selectedRender.componentName || selectedRender.displayName || selectedRender.viewType
510
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_RenderHistoryViewer.RenderHistoryFooter, {
511
- render: selectedRender,
512
- selectedEventIndex: historyEventIndex,
513
- onEventIndexChange: setHistoryEventIndex,
514
- isPro: isPro
515
- }) : null;
516
- return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.TickProvider, {
517
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.JsModal, {
518
- visible: visible,
519
- onClose: onClose,
520
- onMinimize: onMinimize,
521
- persistenceKey: persistenceKey,
522
- header: {
523
- showToggleButton: true,
524
- customContent: renderHeaderContent()
525
- },
526
- enablePersistence: true,
527
- initialMode: "bottomSheet",
528
- enableGlitchEffects: true,
529
- styles: {},
530
- footer: footerNode,
531
- footerHeight: selectedRender ? detailViewActiveTab === "details" ? 68 : (selectedRender.renderHistory?.length ?? 0) > 1 ? 68 : 0 : 0,
532
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
533
- nativeID: "__rn_buoy__highlight-modal",
534
- style: styles.container,
535
- children: selectedRender ? detailViewActiveTab === "details" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_RenderDetailView.RenderDetailView, {
536
- render: selectedRender,
537
- disableInternalFooter: true,
538
- onAddFilter: handleAddFilter,
539
- isPro: isPro
540
- }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_RenderHistoryViewer.RenderHistoryViewer, {
541
- render: selectedRender,
542
- disableInternalFooter: true,
543
- selectedEventIndex: historyEventIndex,
544
- onEventIndexChange: setHistoryEventIndex,
545
- isPro: isPro
546
- }) : showFilterView ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_HighlightFilterView.HighlightFilterView, {
547
- filters: filters,
548
- onFilterChange: handleFilterChange,
549
- settings: settings,
550
- onSettingsChange: handleSettingsChange,
551
- availableProps: _RenderTracker.RenderTracker.getAvailableProps(),
552
- activeTab: filterViewActiveTab
553
- }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
554
- children: [!isTracking && /*#__PURE__*/(0, _jsxRuntime.jsx)(DisabledBanner, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_IsolatedRenderList.IsolatedRenderList, {
555
- searchText: searchText,
556
- filters: filters,
557
- onSelectRender: handleRenderPress,
558
- onStatsChange: handleStatsChange,
559
- onRendersChange: handleRendersChange,
560
- isTracking: isTracking,
561
- isPro: isPro
562
- })]
563
- })
564
- })
565
- })
566
- });
567
- }
568
- const styles = _reactNative.StyleSheet.create({
569
- container: {
570
- flex: 1,
571
- backgroundColor: _sharedUi.buoyColors.base
572
- },
573
- disabledBanner: {
574
- flexDirection: "row",
575
- alignItems: "center",
576
- gap: 8,
577
- padding: 10,
578
- marginHorizontal: 12,
579
- marginTop: 8,
580
- backgroundColor: _sharedUi.buoyColors.warning + "15",
581
- borderRadius: 8,
582
- borderWidth: 1,
583
- borderColor: _sharedUi.buoyColors.warning + "20"
584
- },
585
- disabledText: {
586
- color: _sharedUi.buoyColors.warning,
587
- fontSize: 11,
588
- flex: 1
589
- }
590
- });
591
- var _default = exports.default = HighlightUpdatesModal;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.HighlightUpdatesModal=HighlightUpdatesModal,exports.default=void 0;var _react=_interopRequireWildcard(require("react")),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_license=require("@buoy-gg/license"),_HighlightUpdatesController=_interopRequireDefault(require("../utils/HighlightUpdatesController")),_RenderTracker=require("../utils/RenderTracker"),_RenderDetailView=require("./RenderDetailView"),_HighlightFilterView=require("./HighlightFilterView"),_IsolatedRenderList=require("./IsolatedRenderList"),_ModalHeaderContent=require("./ModalHeaderContent"),_RenderHistoryViewer=require("./RenderHistoryViewer"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var r=new WeakMap,a=new WeakMap;return(_interopRequireWildcard=function(e,t){if(!t&&e&&e.__esModule)return e;var n,i,s={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return s;if(n=t?a:r){if(n.has(e))return n.get(e);n.set(e,s)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((i=(n=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(i.get||i.set)?n(s,t,i):s[t]=e[t]);return s})(e,t)}const DisabledBanner=_react.default.memo(function(){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.disabledBanner,children:[(0,_jsxRuntime.jsx)(_sharedUi.Power,{size:14,color:_sharedUi.buoyColors.warning}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.disabledText,children:"Render tracking is disabled"})]})});function formatRenderDataForClipboard(){const e=_RenderTracker.RenderTracker.getRenders(),t={exportedAt:(new Date).toISOString(),totalComponents:e.length,totalRenders:e.reduce((e,t)=>e+t.renderCount,0),components:e.map(e=>({componentName:e.componentName||e.displayName,viewType:e.viewType,nativeTag:e.nativeTag,testID:e.testID,nativeID:e.nativeID,accessibilityLabel:e.accessibilityLabel,renderCount:e.renderCount,firstRenderTime:e.firstRenderTime,lastRenderTime:e.lastRenderTime,lastRenderCause:e.lastRenderCause?{type:e.lastRenderCause.type,componentCause:e.lastRenderCause.componentCause,changedKeys:e.lastRenderCause.changedKeys,hookChanges:e.lastRenderCause.hookChanges?.map(e=>({type:e.type,index:e.index,description:e.description}))}:null,renderHistory:e.renderHistory?.map(e=>({renderNumber:e.renderNumber,timestamp:e.timestamp,cause:{type:e.cause.type,componentCause:e.cause.componentCause,changedKeys:e.cause.changedKeys}}))}))};return JSON.stringify(t,null,2)}function HighlightUpdatesModal({visible:e,onClose:t,onBack:r,onMinimize:a,enableSharedModalDimensions:n=!1,initialNativeTag:i,onInitialNativeTagHandled:s}){const l=(0,_license.useIsPro)(),[o,c]=(0,_react.useState)(!1),[d,u]=(0,_react.useState)(()=>_HighlightUpdatesController.default.getFrozen()),[g,_]=(0,_react.useState)(()=>_RenderTracker.RenderTracker.getStats().totalComponents>0),[h,p]=(0,_react.useState)(null),[f,R]=(0,_react.useState)(0),[T,m]=(0,_react.useState)(!1),[C,y]=(0,_react.useState)("filters"),[x,k]=(0,_react.useState)("details"),[b,S]=(0,_react.useState)(0),[v,w]=(0,_react.useState)(""),[H,U]=(0,_react.useState)(!1),I=(0,_react.useRef)(null),j=(0,_react.useRef)([]),D=(0,_react.useRef)(_RenderTracker.RenderTracker.getFilters()),[P,F]=(0,_react.useState)(()=>{const e=_RenderTracker.RenderTracker.getFilters();return e.includePatterns.length+e.excludePatterns.length}),[N,V]=(0,_react.useState)(()=>_RenderTracker.RenderTracker.getFilters()),[M,q]=(0,_react.useState)(()=>_RenderTracker.RenderTracker.getSettings()),E=(0,_react.useRef)(!1),A=(0,_react.useRef)(!1),z=(0,_react.useRef)(!1);(0,_react.useEffect)(()=>{e&&!E.current&&(E.current=!0)},[e]),(0,_react.useEffect)(()=>{e&&!A.current&&(async()=>{try{const e=await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.highlightUpdates.filters());if(e){const t=JSON.parse(e),r={includeTestID:new Set(t.includeTestID||[]),includeNativeID:new Set(t.includeNativeID||[]),includeViewType:new Set(t.includeViewType||[]),includeComponent:new Set(t.includeComponent||[]),excludeTestID:new Set(t.excludeTestID||[]),excludeNativeID:new Set(t.excludeNativeID||[]),excludeViewType:new Set(t.excludeViewType||[]),excludeComponent:new Set(t.excludeComponent||[]),includePatterns:t.includePatterns||[],excludePatterns:t.excludePatterns||[]};_RenderTracker.RenderTracker.setFilters(r);const a=_RenderTracker.RenderTracker.getFilters();D.current=a,V(a),F(a.includePatterns.length+a.excludePatterns.length)}A.current=!0}catch(e){}})()},[e]),(0,_react.useEffect)(()=>{A.current&&(async()=>{try{const e={includeTestID:Array.from(N.includeTestID),includeNativeID:Array.from(N.includeNativeID),includeViewType:Array.from(N.includeViewType),includeComponent:Array.from(N.includeComponent),excludeTestID:Array.from(N.excludeTestID),excludeNativeID:Array.from(N.excludeNativeID),excludeViewType:Array.from(N.excludeViewType),excludeComponent:Array.from(N.excludeComponent),includePatterns:N.includePatterns,excludePatterns:N.excludePatterns};await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.highlightUpdates.filters(),JSON.stringify(e))}catch(e){}})()},[N]),(0,_react.useEffect)(()=>{e&&!z.current&&(async()=>{try{const e=await _sharedUi.persistentStorage.getItem(_sharedUi.devToolsStorageKeys.highlightUpdates.settings());if(e){const t=JSON.parse(e),{performanceLogging:r,excludeDevTools:a,...n}=t;_RenderTracker.RenderTracker.setSettings(n),q(_RenderTracker.RenderTracker.getSettings())}z.current=!0}catch(e){z.current=!0}})()},[e]),(0,_react.useEffect)(()=>{z.current&&(async()=>{try{const{performanceLogging:e,excludeDevTools:t,...r}=M;await _sharedUi.persistentStorage.setItem(_sharedUi.devToolsStorageKeys.highlightUpdates.settings(),JSON.stringify(r))}catch(e){}})()},[M]),(0,_react.useEffect)(()=>{const e=_RenderTracker.RenderTracker.subscribeToState(e=>{c(e.isTracking)});return()=>{e()}},[]),(0,_react.useEffect)(()=>{const e=_HighlightUpdatesController.default.subscribeToFreeze(e=>{u(e)});return()=>{e()}},[]),(0,_react.useEffect)(()=>{H&&requestAnimationFrame(()=>{I.current?.focus()})},[H]),(0,_react.useEffect)(()=>{e||_HighlightUpdatesController.default.setSpotlight(null)},[e]),(0,_react.useEffect)(()=>{if(e&&null!=i){const e=_RenderTracker.RenderTracker.getRender(String(i));e&&(p(e),R(0),m(!1),_HighlightUpdatesController.default.setSpotlight(e.nativeTag)),s?.()}},[e,i,s]);const O=(0,_react.useCallback)(()=>{_HighlightUpdatesController.default.isInitialized()||_HighlightUpdatesController.default.initialize(),_HighlightUpdatesController.default.toggle()},[]),K=(0,_react.useCallback)(()=>{_HighlightUpdatesController.default.toggleFreeze()},[]),L=(0,_react.useCallback)(()=>{_HighlightUpdatesController.default.clearRenderCounts(),_(!1)},[]),B=g?formatRenderDataForClipboard:"",W=(0,_react.useCallback)(e=>{w(e)},[]),J=(0,_react.useCallback)((e,t,r)=>{p(e),R(t),k("details"),S(0),j.current=r,_HighlightUpdatesController.default.setSpotlight(e.nativeTag)},[]),G=(0,_react.useCallback)(e=>{j.current=e},[]),Q=(0,_react.useCallback)(()=>{p(null),R(0),_HighlightUpdatesController.default.setSpotlight(null)},[]),X=(0,_react.useCallback)(()=>{const e=j.current;if(f>0){const t=f-1,r=e[t];r&&(p(r),R(t),_HighlightUpdatesController.default.setSpotlight(r.nativeTag))}},[f]),Y=(0,_react.useCallback)(()=>{const e=j.current;if(f<e.length-1){const t=f+1,r=e[t];r&&(p(r),R(t),_HighlightUpdatesController.default.setSpotlight(r.nativeTag))}},[f]),Z=(0,_react.useCallback)(()=>{m(!1)},[]),$=(0,_react.useCallback)(()=>{m(!0)},[]),ee=(0,_react.useCallback)(()=>{U(!0)},[]),te=(0,_react.useCallback)(()=>{U(!1)},[]),re=(0,_react.useCallback)(e=>{_RenderTracker.RenderTracker.setFilters(e);const t=_RenderTracker.RenderTracker.getFilters();D.current=t,V(t),F(t.includePatterns.length+t.excludePatterns.length)},[]),ae=(0,_react.useCallback)((e,t)=>{const r=_RenderTracker.RenderTracker.getFilters(),a={};"include"===t?r.includePatterns.some(t=>t.type===e.type&&t.value===e.value)||(a.includePatterns=[...r.includePatterns,e]):r.excludePatterns.some(t=>t.type===e.type&&t.value===e.value)||(a.excludePatterns=[...r.excludePatterns,e]),Object.keys(a).length>0&&(re(a),p(null),R(0),_HighlightUpdatesController.default.setSpotlight(null))},[re]),ne=(0,_react.useCallback)(e=>{_RenderTracker.RenderTracker.setSettings(e),q(_RenderTracker.RenderTracker.getSettings())},[]),ie=(0,_react.useCallback)(e=>{_(e.totalComponents>0)},[]),se=(0,_react.useCallback)(()=>T?(0,_jsxRuntime.jsx)(_ModalHeaderContent.FilterViewHeader,{onBack:Z,activeTab:C,onTabChange:y,activeFilterCount:P}):h?(0,_jsxRuntime.jsx)(_ModalHeaderContent.DetailViewHeader,{onBack:Q,activeTab:x,onTabChange:k,hasHistory:(h.renderHistory?.length??0)>0}):(0,_jsxRuntime.jsx)(_ModalHeaderContent.MainListHeader,{onBack:r,isSearchActive:H,searchText:v,onSearchChange:W,onSearchToggle:ee,onSearchClose:te,onFilterToggle:$,onToggleTracking:O,onToggleFreeze:K,onClear:L,copyData:B,isTracking:o,isFrozen:d,activeFilterCount:P,hasRenders:g,searchInputRef:I}),[T,h,r,H,v,o,d,P,g,C,x,Z,Q,W,ee,te,$,O,K,L,B]),le=n?_sharedUi.devToolsStorageKeys.modal.root():_sharedUi.devToolsStorageKeys.highlightUpdates.modal();if(!e)return null;const oe=j.current.length,ce=h?"details"===x?(0,_jsxRuntime.jsx)(_sharedUi.EventStepperFooter,{currentIndex:f,totalItems:oe,onPrevious:X,onNext:Y,itemLabel:"Component",subtitle:h.componentName||h.displayName||h.viewType}):(0,_jsxRuntime.jsx)(_RenderHistoryViewer.RenderHistoryFooter,{render:h,selectedEventIndex:b,onEventIndexChange:S,isPro:l}):null;return(0,_jsxRuntime.jsx)(_sharedUi.TickProvider,{children:(0,_jsxRuntime.jsx)(_sharedUi.JsModal,{visible:e,onClose:t,onMinimize:a,persistenceKey:le,header:{showToggleButton:!0,customContent:se()},enablePersistence:!0,initialMode:"bottomSheet",enableGlitchEffects:!0,styles:{},footer:ce,footerHeight:h&&("details"===x||(h.renderHistory?.length??0)>1)?68:0,children:(0,_jsxRuntime.jsx)(_reactNative.View,{nativeID:"__rn_buoy__highlight-modal",style:styles.container,children:h?"details"===x?(0,_jsxRuntime.jsx)(_RenderDetailView.RenderDetailView,{render:h,disableInternalFooter:!0,onAddFilter:ae,isPro:l}):(0,_jsxRuntime.jsx)(_RenderHistoryViewer.RenderHistoryViewer,{render:h,disableInternalFooter:!0,selectedEventIndex:b,onEventIndexChange:S,isPro:l}):T?(0,_jsxRuntime.jsx)(_HighlightFilterView.HighlightFilterView,{filters:N,onFilterChange:re,settings:M,onSettingsChange:ne,availableProps:_RenderTracker.RenderTracker.getAvailableProps(),activeTab:C}):(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[!o&&(0,_jsxRuntime.jsx)(DisabledBanner,{}),(0,_jsxRuntime.jsx)(_IsolatedRenderList.IsolatedRenderList,{searchText:v,filters:N,onSelectRender:J,onStatsChange:ie,onRendersChange:G,isTracking:o,isPro:l})]})})})})}const styles=_reactNative.StyleSheet.create({container:{flex:1,backgroundColor:_sharedUi.buoyColors.base},disabledBanner:{flexDirection:"row",alignItems:"center",gap:8,padding:10,marginHorizontal:12,marginTop:8,backgroundColor:_sharedUi.buoyColors.warning+"15",borderRadius:8,borderWidth:1,borderColor:_sharedUi.buoyColors.warning+"20"},disabledText:{color:_sharedUi.buoyColors.warning,fontSize:11,flex:1}});var _default=exports.default=HighlightUpdatesModal;