@buoy-gg/highlight-updates 7.0.32 → 7.0.34

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.
@@ -110,21 +110,38 @@ function IsolatedRenderListInner({
110
110
 
111
111
  // Show empty state when no renders
112
112
  if (renders.length === 0) {
113
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
114
- testID: "buoy-highlight-empty",
115
- style: styles.emptyState,
116
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Activity, {
117
- size: 32,
118
- color: _sharedUi.night.color.textTertiary
119
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
120
- testID: "buoy-highlight-empty-title",
121
- style: styles.emptyTitle,
122
- children: "No renders tracked"
123
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
124
- testID: "buoy-highlight-empty-text",
125
- style: styles.emptyText,
126
- children: isTracking ? "Component renders will appear here" : "Enable tracking to start capturing"
127
- })]
113
+ const term = searchText.trim();
114
+
115
+ // Read straight off the tracker rather than held in state: this runs only
116
+ // on the empty branch, so it costs nothing on the hot path, and it is
117
+ // always the current truth. `totalTracked` is every component the tracker
118
+ // holds; `unsearched` is what the settings and filters allow BEFORE the
119
+ // search box.
120
+ const totalTracked = _RenderTracker.RenderTracker.getStats().totalComponents;
121
+ const unsearched = term ? _RenderTracker.RenderTracker.getFilteredRenders("").length : 0;
122
+ const content = (0, _sharedUi.resolveListEmptyState)({
123
+ subject: "components",
124
+ verb: "tracked",
125
+ search: searchText,
126
+ // The denominator is what the FILTERS left, not the raw tracker count —
127
+ // "clear the search to see them" has to be true of what you get back.
128
+ total: term ? unsearched : totalTracked,
129
+ capturing: isTracking,
130
+ blocked: term && unsearched === 0 && totalTracked > 0 ? "The active filters hide everything tracked, so there is nothing to search." : undefined,
131
+ waiting: {
132
+ // stare = "watching for a specific event; recording armed".
133
+ otto: "stare",
134
+ title: "No renders tracked",
135
+ message: "Component renders will appear here"
136
+ },
137
+ paused: {
138
+ title: "No renders tracked",
139
+ message: "Enable tracking to start capturing"
140
+ }
141
+ });
142
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
143
+ ...content,
144
+ testID: "buoy-highlight-empty"
128
145
  });
129
146
  }
130
147
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.FlatList, {
@@ -149,22 +166,6 @@ const styles = _reactNative.StyleSheet.create({
149
166
  listContent: {
150
167
  paddingTop: 8
151
168
  },
152
- emptyState: {
153
- alignItems: "center",
154
- paddingVertical: 40
155
- },
156
- emptyTitle: {
157
- color: _sharedUi.night.color.text,
158
- fontSize: 14,
159
- fontWeight: "600",
160
- marginTop: 12,
161
- marginBottom: 6
162
- },
163
- emptyText: {
164
- color: _sharedUi.night.color.textTertiary,
165
- fontSize: 12,
166
- textAlign: "center"
167
- },
168
169
  lockedBanner: {
169
170
  flexDirection: "row",
170
171
  alignItems: "center",
@@ -30,41 +30,23 @@ const SearchSectionInner = /*#__PURE__*/(0, _react.memo)(function SearchSection(
30
30
  onSearchClose
31
31
  }) {
32
32
  if (!isActive) return null;
33
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
34
- nativeID: "__rn_buoy__search-container",
35
- testID: "buoy-highlight-search-container",
36
- style: styles.headerSearchContainer,
37
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Search, {
38
- size: 14,
39
- color: _sharedUi.night.color.textSecondary
40
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
41
- testID: "buoy-highlight-search-field",
42
- style: styles.headerSearchInput,
43
- placeholder: "Search testID, nativeID, component...",
44
- placeholderTextColor: _sharedUi.night.color.placeholder,
45
- value: searchText,
46
- onChangeText: onSearchChange,
47
- onSubmitEditing: onSearchClose,
48
- onBlur: onSearchClose,
49
- accessibilityLabel: "Search renders",
50
- autoCapitalize: "none",
51
- autoCorrect: false,
52
- returnKeyType: "search",
53
- autoFocus: true
54
- }), searchText.length > 0 ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
55
- testID: "buoy-highlight-search-clear",
56
- accessibilityRole: "button",
57
- accessibilityLabel: "Clear search",
58
- onPress: () => {
59
- onSearchChange("");
60
- onSearchClose();
61
- },
62
- style: styles.headerSearchClear,
63
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.X, {
64
- size: 14,
65
- color: _sharedUi.night.color.textSecondary
66
- })
67
- }) : null]
33
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Search, {
34
+ value: searchText,
35
+ onChangeText: onSearchChange,
36
+ onCancel: () => {
37
+ onSearchChange("");
38
+ onSearchClose();
39
+ },
40
+ onDismiss: onSearchClose,
41
+ dismissOnBlur: true,
42
+ clearOnlyWhenText: true,
43
+ placeholder: "Search testID, nativeID, component...",
44
+ accessibilityLabel: "Search renders",
45
+ iconSize: 14,
46
+ testID: "buoy-highlight-search-field",
47
+ containerTestID: "buoy-highlight-search-container",
48
+ containerNativeID: "__rn_buoy__search-container",
49
+ clearTestID: "buoy-highlight-search-clear"
68
50
  });
69
51
  });
70
52
  const SearchSection = exports.SearchSection = SearchSectionInner;
@@ -287,27 +269,6 @@ const CopySettingsViewHeader = exports.CopySettingsViewHeader = /*#__PURE__*/(0,
287
269
  // ============================================================================
288
270
 
289
271
  const styles = _reactNative.StyleSheet.create({
290
- headerSearchContainer: {
291
- flexDirection: "row",
292
- alignItems: "center",
293
- backgroundColor: _sharedUi.night.color.surfaceElevated,
294
- borderRadius: 10,
295
- borderWidth: 1,
296
- borderColor: _sharedUi.night.color.border,
297
- paddingHorizontal: 12,
298
- paddingVertical: 5
299
- },
300
- headerSearchInput: {
301
- flex: 1,
302
- color: _sharedUi.night.color.text,
303
- fontSize: 13,
304
- marginLeft: 6,
305
- paddingVertical: 2
306
- },
307
- headerSearchClear: {
308
- marginLeft: 6,
309
- padding: 4
310
- },
311
272
  headerActionButton: {
312
273
  width: 32,
313
274
  height: 32,
@@ -10,6 +10,7 @@ var _react = _interopRequireWildcard(require("react"));
10
10
  var _reactNative = require("react-native");
11
11
  var _sharedUi = require("@buoy-gg/shared-ui");
12
12
  var _dataViewer = require("@buoy-gg/shared-ui/dataViewer");
13
+ var _RenderTracker = require("../utils/RenderTracker");
13
14
  var _RenderCauseBadge = require("./RenderCauseBadge");
14
15
  var _jsxRuntime = require("react/jsx-runtime");
15
16
  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); }
@@ -96,21 +97,19 @@ function RenderHistoryViewer({
96
97
 
97
98
  // If no history, show empty state
98
99
  if (totalEvents === 0) {
99
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
100
- testID: "buoy-highlight-history-empty",
101
- style: styles.emptyContainer,
102
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Clock, {
103
- size: 32,
104
- color: _sharedUi.night.color.textTertiary
105
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
106
- testID: "buoy-highlight-history-empty-title",
107
- style: styles.emptyTitle,
108
- children: "No Render History"
109
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
110
- testID: "buoy-highlight-history-empty-text",
111
- style: styles.emptyText,
112
- children: "Enable render history tracking in settings to see render events here."
113
- })]
100
+ // The copy used to tell EVERYONE to go and enable the setting, including
101
+ // the people who already had. Asking the tracker which it is costs one
102
+ // synchronous read on a branch that renders nothing else.
103
+ const historyEnabled = _RenderTracker.RenderTracker.getSettings().enableRenderHistory;
104
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ToolEmptyState, {
105
+ testID: "buoy-highlight-history-empty"
106
+ // paused = the recorder is switched off; stare = armed and watching,
107
+ // which is the truth once the setting is on and this component simply
108
+ // has not re-rendered yet.
109
+ ,
110
+ otto: historyEnabled ? "stare" : "paused",
111
+ title: "No Render History",
112
+ message: historyEnabled ? "History is on and armed — this component has not re-rendered since. Interact with the app to record one." : "Enable render history tracking in settings to see render events here."
114
113
  });
115
114
  }
116
115
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
@@ -195,77 +195,35 @@ function RendersCopySettingsView({
195
195
  totalComponents,
196
196
  totalRenders
197
197
  } = (0, _rendersExportFormatter.getExportSummary)(previewRenders);
198
- if (!isPreviewExpanded) {
199
- const warningColor = sizeWarningLevel === "danger" ? _sharedUi.night.color.danger : sizeWarningLevel === "warning" ? _sharedUi.night.color.warning : _sharedUi.night.color.textSecondary;
200
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
201
- style: styles.collapsedPreview,
202
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
203
- testID: "buoy-highlight-copy-preview-show",
204
- accessibilityRole: "button",
205
- accessibilityLabel: "Show preview",
206
- style: styles.expandButton,
207
- onPress: () => setIsPreviewExpanded(true),
208
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
209
- style: styles.expandButtonContent,
210
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Eye, {
211
- size: 16,
212
- color: _sharedUi.night.color.info
213
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
214
- style: styles.expandButtonTextContainer,
215
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
216
- style: styles.expandButtonTitle,
217
- children: "Show Preview"
218
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
219
- testID: "buoy-highlight-copy-preview-summary",
220
- style: styles.expandButtonSubtitle,
221
- children: [totalComponents, " component", totalComponents !== 1 ? "s" : "", " \xB7 ", totalRenders, " renders \xB7 ~", formatBytes(estimatedSize), !hasLiveData ? " (mock data)" : ""]
222
- })]
223
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronDown, {
224
- size: 16,
225
- color: _sharedUi.night.color.textTertiary
226
- })]
198
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ExportPreview, {
199
+ expanded: isPreviewExpanded,
200
+ onExpandedChange: setIsPreviewExpanded,
201
+ summary: `${totalComponents} component${totalComponents !== 1 ? "s" : ""} · ${totalRenders} renders · ~${formatBytes(estimatedSize)}${!hasLiveData ? " (mock data)" : ""}`,
202
+ warningLevel: sizeWarningLevel,
203
+ warningText: {
204
+ warning: "Large payload — preview may be slow",
205
+ danger: "Very large payload — try a smaller topN or turn off history"
206
+ },
207
+ testIDs: {
208
+ expand: "buoy-highlight-copy-preview-show",
209
+ collapse: "buoy-highlight-copy-preview-hide",
210
+ summary: "buoy-highlight-copy-preview-summary",
211
+ warning: "buoy-highlight-copy-size-warning"
212
+ },
213
+ renderBody: () => {
214
+ const exportText = generateCopyText();
215
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
216
+ testID: "buoy-highlight-copy-preview-scroll",
217
+ style: styles.previewScroll,
218
+ nestedScrollEnabled: true,
219
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
220
+ testID: "buoy-highlight-copy-preview-text",
221
+ style: styles.previewText,
222
+ selectable: true,
223
+ children: exportText
227
224
  })
228
- }), sizeWarningLevel !== "none" && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
229
- testID: "buoy-highlight-copy-size-warning",
230
- style: [styles.sizeWarning, sizeWarningLevel === "danger" && styles.sizeWarningDanger],
231
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.AlertTriangle, {
232
- size: 12,
233
- color: warningColor
234
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
235
- style: [styles.sizeWarningText, {
236
- color: warningColor
237
- }],
238
- children: sizeWarningLevel === "danger" ? "Very large payload — try a smaller topN or turn off history" : "Large payload — preview may be slow"
239
- })]
240
- })]
241
- });
242
- }
243
- const exportText = generateCopyText();
244
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
245
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
246
- testID: "buoy-highlight-copy-preview-hide",
247
- accessibilityRole: "button",
248
- accessibilityLabel: "Hide preview",
249
- style: styles.collapseButton,
250
- onPress: () => setIsPreviewExpanded(false),
251
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
252
- style: styles.collapseButtonText,
253
- children: "Hide Preview"
254
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronUp, {
255
- size: 14,
256
- color: _sharedUi.night.color.textSecondary
257
- })]
258
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
259
- testID: "buoy-highlight-copy-preview-scroll",
260
- style: styles.previewScroll,
261
- nestedScrollEnabled: true,
262
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
263
- testID: "buoy-highlight-copy-preview-text",
264
- style: styles.previewText,
265
- selectable: true,
266
- children: exportText
267
- })
268
- })]
225
+ });
226
+ }
269
227
  });
270
228
  }, [isPreviewExpanded, previewRenders, estimatedSize, sizeWarningLevel, hasLiveData, generateCopyText]);
271
229
  const renderPreviewHeaderActions = (0, _react.useCallback)(() => {
@@ -490,71 +448,6 @@ function RendersCopySettingsView({
490
448
  });
491
449
  }
492
450
  const styles = _reactNative.StyleSheet.create({
493
- collapsedPreview: {
494
- gap: 8
495
- },
496
- expandButton: {
497
- backgroundColor: _sharedUi.night.color.surfaceElevated,
498
- borderRadius: 8,
499
- borderWidth: 1,
500
- borderColor: _sharedUi.night.color.border,
501
- padding: 12
502
- },
503
- expandButtonContent: {
504
- flexDirection: "row",
505
- alignItems: "center",
506
- gap: 10
507
- },
508
- expandButtonTextContainer: {
509
- flex: 1
510
- },
511
- expandButtonTitle: {
512
- fontSize: 13,
513
- fontWeight: "600",
514
- color: _sharedUi.night.color.text
515
- },
516
- expandButtonSubtitle: {
517
- fontSize: 11,
518
- color: _sharedUi.night.color.textSecondary,
519
- marginTop: 2
520
- },
521
- collapseButton: {
522
- flexDirection: "row",
523
- alignItems: "center",
524
- justifyContent: "center",
525
- gap: 6,
526
- paddingVertical: 8,
527
- marginBottom: 8,
528
- backgroundColor: _sharedUi.night.color.surfaceElevated,
529
- borderRadius: 6,
530
- borderWidth: 1,
531
- borderColor: _sharedUi.night.color.border
532
- },
533
- collapseButtonText: {
534
- fontSize: 12,
535
- fontWeight: "500",
536
- color: _sharedUi.night.color.textSecondary
537
- },
538
- sizeWarning: {
539
- flexDirection: "row",
540
- alignItems: "center",
541
- gap: 6,
542
- paddingHorizontal: 10,
543
- paddingVertical: 6,
544
- backgroundColor: _sharedUi.night.color.warningSoft,
545
- borderRadius: 6,
546
- borderWidth: 1,
547
- borderColor: _sharedUi.night.color.warning + "30"
548
- },
549
- sizeWarningDanger: {
550
- backgroundColor: _sharedUi.night.color.dangerSoft,
551
- borderColor: _sharedUi.night.color.danger + "30"
552
- },
553
- sizeWarningText: {
554
- fontSize: 11,
555
- fontWeight: "500",
556
- flex: 1
557
- },
558
451
  previewScroll: {
559
452
  maxHeight: 360
560
453
  },
@@ -11,39 +11,22 @@ var _copySettings = require("../types/copySettings");
11
11
  /**
12
12
  * Copy Settings Storage
13
13
  *
14
- * Persists the highlight-updates copy/export settings.
14
+ * Persists the highlight-updates copy/export settings through the shared
15
+ * `definePersistedSetting` (merge-over-defaults, best-effort save/clear).
15
16
  */
16
17
 
18
+ const copySettings = (0, _sharedUi.definePersistedSetting)(_sharedUi.devToolsStorageKeys.highlightUpdates.copySettings(), _copySettings.DEFAULT_COPY_SETTINGS, {
19
+ sanitize: (merged, stored) => ({
20
+ ...merged,
21
+ filterCauses: stored?.filterCauses ?? _copySettings.DEFAULT_COPY_SETTINGS.filterCauses
22
+ })
23
+ });
17
24
  async function saveCopySettings(settings) {
18
- try {
19
- const key = _sharedUi.devToolsStorageKeys.highlightUpdates.copySettings();
20
- await _sharedUi.persistentStorage.setItem(key, JSON.stringify(settings));
21
- } catch {
22
- // Silently fail — persistence is optional
23
- }
25
+ await copySettings.save(settings);
24
26
  }
25
27
  async function loadCopySettings() {
26
- try {
27
- const key = _sharedUi.devToolsStorageKeys.highlightUpdates.copySettings();
28
- const value = await _sharedUi.persistentStorage.getItem(key);
29
- if (value && value !== "") {
30
- const parsed = JSON.parse(value);
31
- return {
32
- ..._copySettings.DEFAULT_COPY_SETTINGS,
33
- ...parsed,
34
- filterCauses: parsed.filterCauses ?? _copySettings.DEFAULT_COPY_SETTINGS.filterCauses
35
- };
36
- }
37
- return null;
38
- } catch {
39
- return null;
40
- }
28
+ return copySettings.loadOrNull();
41
29
  }
42
30
  async function clearCopySettings() {
43
- try {
44
- const key = _sharedUi.devToolsStorageKeys.highlightUpdates.copySettings();
45
- await _sharedUi.persistentStorage.removeItem(key);
46
- } catch {
47
- // Silently fail
48
- }
31
+ await copySettings.clear();
49
32
  }
@@ -15,7 +15,7 @@ import React, { useState, useEffect, useRef, useCallback, memo, useMemo } from "
15
15
  import { View, Text, FlatList, StyleSheet } from "react-native";
16
16
  import { RenderTracker } from "../utils/RenderTracker";
17
17
  import { RenderListItem } from "./RenderListItem";
18
- import { Activity, Lock, night, useLimit } from "@buoy-gg/shared-ui";
18
+ import { Lock, night, useLimit, ToolEmptyState, resolveListEmptyState } from "@buoy-gg/shared-ui";
19
19
 
20
20
  // Free tier limit for tracked components
21
21
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -105,21 +105,38 @@ function IsolatedRenderListInner({
105
105
 
106
106
  // Show empty state when no renders
107
107
  if (renders.length === 0) {
108
- return /*#__PURE__*/_jsxs(View, {
109
- testID: "buoy-highlight-empty",
110
- style: styles.emptyState,
111
- children: [/*#__PURE__*/_jsx(Activity, {
112
- size: 32,
113
- color: night.color.textTertiary
114
- }), /*#__PURE__*/_jsx(Text, {
115
- testID: "buoy-highlight-empty-title",
116
- style: styles.emptyTitle,
117
- children: "No renders tracked"
118
- }), /*#__PURE__*/_jsx(Text, {
119
- testID: "buoy-highlight-empty-text",
120
- style: styles.emptyText,
121
- children: isTracking ? "Component renders will appear here" : "Enable tracking to start capturing"
122
- })]
108
+ const term = searchText.trim();
109
+
110
+ // Read straight off the tracker rather than held in state: this runs only
111
+ // on the empty branch, so it costs nothing on the hot path, and it is
112
+ // always the current truth. `totalTracked` is every component the tracker
113
+ // holds; `unsearched` is what the settings and filters allow BEFORE the
114
+ // search box.
115
+ const totalTracked = RenderTracker.getStats().totalComponents;
116
+ const unsearched = term ? RenderTracker.getFilteredRenders("").length : 0;
117
+ const content = resolveListEmptyState({
118
+ subject: "components",
119
+ verb: "tracked",
120
+ search: searchText,
121
+ // The denominator is what the FILTERS left, not the raw tracker count —
122
+ // "clear the search to see them" has to be true of what you get back.
123
+ total: term ? unsearched : totalTracked,
124
+ capturing: isTracking,
125
+ blocked: term && unsearched === 0 && totalTracked > 0 ? "The active filters hide everything tracked, so there is nothing to search." : undefined,
126
+ waiting: {
127
+ // stare = "watching for a specific event; recording armed".
128
+ otto: "stare",
129
+ title: "No renders tracked",
130
+ message: "Component renders will appear here"
131
+ },
132
+ paused: {
133
+ title: "No renders tracked",
134
+ message: "Enable tracking to start capturing"
135
+ }
136
+ });
137
+ return /*#__PURE__*/_jsx(ToolEmptyState, {
138
+ ...content,
139
+ testID: "buoy-highlight-empty"
123
140
  });
124
141
  }
125
142
  return /*#__PURE__*/_jsx(FlatList, {
@@ -144,22 +161,6 @@ const styles = StyleSheet.create({
144
161
  listContent: {
145
162
  paddingTop: 8
146
163
  },
147
- emptyState: {
148
- alignItems: "center",
149
- paddingVertical: 40
150
- },
151
- emptyTitle: {
152
- color: night.color.text,
153
- fontSize: 14,
154
- fontWeight: "600",
155
- marginTop: 12,
156
- marginBottom: 6
157
- },
158
- emptyText: {
159
- color: night.color.textTertiary,
160
- fontSize: 12,
161
- textAlign: "center"
162
- },
163
164
  lockedBanner: {
164
165
  flexDirection: "row",
165
166
  alignItems: "center",
@@ -10,8 +10,8 @@
10
10
  */
11
11
 
12
12
  import React, { memo } from "react";
13
- import { View, TouchableOpacity, TextInput, StyleSheet } from "react-native";
14
- import { Trash2, Search, Filter, X, Pause, Copy, ModalHeader, TabSelector, night, PowerToggleButton } from "@buoy-gg/shared-ui";
13
+ import { TouchableOpacity, StyleSheet } from "react-native";
14
+ import { Trash2, Search, Filter, Pause, Copy, ModalHeader, TabSelector, night, PowerToggleButton } from "@buoy-gg/shared-ui";
15
15
  import { StatsDisplay } from "./StatsDisplay";
16
16
 
17
17
  // ============================================================================
@@ -25,41 +25,23 @@ const SearchSectionInner = /*#__PURE__*/memo(function SearchSection({
25
25
  onSearchClose
26
26
  }) {
27
27
  if (!isActive) return null;
28
- return /*#__PURE__*/_jsxs(View, {
29
- nativeID: "__rn_buoy__search-container",
30
- testID: "buoy-highlight-search-container",
31
- style: styles.headerSearchContainer,
32
- children: [/*#__PURE__*/_jsx(Search, {
33
- size: 14,
34
- color: night.color.textSecondary
35
- }), /*#__PURE__*/_jsx(TextInput, {
36
- testID: "buoy-highlight-search-field",
37
- style: styles.headerSearchInput,
38
- placeholder: "Search testID, nativeID, component...",
39
- placeholderTextColor: night.color.placeholder,
40
- value: searchText,
41
- onChangeText: onSearchChange,
42
- onSubmitEditing: onSearchClose,
43
- onBlur: onSearchClose,
44
- accessibilityLabel: "Search renders",
45
- autoCapitalize: "none",
46
- autoCorrect: false,
47
- returnKeyType: "search",
48
- autoFocus: true
49
- }), searchText.length > 0 ? /*#__PURE__*/_jsx(TouchableOpacity, {
50
- testID: "buoy-highlight-search-clear",
51
- accessibilityRole: "button",
52
- accessibilityLabel: "Clear search",
53
- onPress: () => {
54
- onSearchChange("");
55
- onSearchClose();
56
- },
57
- style: styles.headerSearchClear,
58
- children: /*#__PURE__*/_jsx(X, {
59
- size: 14,
60
- color: night.color.textSecondary
61
- })
62
- }) : null]
28
+ return /*#__PURE__*/_jsx(ModalHeader.Search, {
29
+ value: searchText,
30
+ onChangeText: onSearchChange,
31
+ onCancel: () => {
32
+ onSearchChange("");
33
+ onSearchClose();
34
+ },
35
+ onDismiss: onSearchClose,
36
+ dismissOnBlur: true,
37
+ clearOnlyWhenText: true,
38
+ placeholder: "Search testID, nativeID, component...",
39
+ accessibilityLabel: "Search renders",
40
+ iconSize: 14,
41
+ testID: "buoy-highlight-search-field",
42
+ containerTestID: "buoy-highlight-search-container",
43
+ containerNativeID: "__rn_buoy__search-container",
44
+ clearTestID: "buoy-highlight-search-clear"
63
45
  });
64
46
  });
65
47
  export const SearchSection = SearchSectionInner;
@@ -282,27 +264,6 @@ export const CopySettingsViewHeader = /*#__PURE__*/memo(function CopySettingsVie
282
264
  // ============================================================================
283
265
 
284
266
  const styles = StyleSheet.create({
285
- headerSearchContainer: {
286
- flexDirection: "row",
287
- alignItems: "center",
288
- backgroundColor: night.color.surfaceElevated,
289
- borderRadius: 10,
290
- borderWidth: 1,
291
- borderColor: night.color.border,
292
- paddingHorizontal: 12,
293
- paddingVertical: 5
294
- },
295
- headerSearchInput: {
296
- flex: 1,
297
- color: night.color.text,
298
- fontSize: 13,
299
- marginLeft: 6,
300
- paddingVertical: 2
301
- },
302
- headerSearchClear: {
303
- marginLeft: 6,
304
- padding: 4
305
- },
306
267
  headerActionButton: {
307
268
  width: 32,
308
269
  height: 32,
@@ -10,8 +10,9 @@
10
10
 
11
11
  import React, { useState, useCallback, useMemo } from "react";
12
12
  import { View, Text, TouchableOpacity, ScrollView, StyleSheet } from "react-native";
13
- import { Clock, GitBranch, Database, Lock, formatRelativeTime, SectionHeader, EventStepperFooter, buoyColors, night, useLimit } from "@buoy-gg/shared-ui";
13
+ import { Clock, GitBranch, Database, Lock, formatRelativeTime, SectionHeader, EventStepperFooter, buoyColors, night, useLimit, ToolEmptyState } from "@buoy-gg/shared-ui";
14
14
  import { TreeDiffViewer } from "@buoy-gg/shared-ui/dataViewer";
15
+ import { RenderTracker } from "../utils/RenderTracker";
15
16
  import { EnhancedCauseDisplay, CAUSE_CONFIG } from "./RenderCauseBadge";
16
17
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
17
18
  /**
@@ -89,21 +90,19 @@ export function RenderHistoryViewer({
89
90
 
90
91
  // If no history, show empty state
91
92
  if (totalEvents === 0) {
92
- return /*#__PURE__*/_jsxs(View, {
93
- testID: "buoy-highlight-history-empty",
94
- style: styles.emptyContainer,
95
- children: [/*#__PURE__*/_jsx(Clock, {
96
- size: 32,
97
- color: night.color.textTertiary
98
- }), /*#__PURE__*/_jsx(Text, {
99
- testID: "buoy-highlight-history-empty-title",
100
- style: styles.emptyTitle,
101
- children: "No Render History"
102
- }), /*#__PURE__*/_jsx(Text, {
103
- testID: "buoy-highlight-history-empty-text",
104
- style: styles.emptyText,
105
- children: "Enable render history tracking in settings to see render events here."
106
- })]
93
+ // The copy used to tell EVERYONE to go and enable the setting, including
94
+ // the people who already had. Asking the tracker which it is costs one
95
+ // synchronous read on a branch that renders nothing else.
96
+ const historyEnabled = RenderTracker.getSettings().enableRenderHistory;
97
+ return /*#__PURE__*/_jsx(ToolEmptyState, {
98
+ testID: "buoy-highlight-history-empty"
99
+ // paused = the recorder is switched off; stare = armed and watching,
100
+ // which is the truth once the setting is on and this component simply
101
+ // has not re-rendered yet.
102
+ ,
103
+ otto: historyEnabled ? "stare" : "paused",
104
+ title: "No Render History",
105
+ message: historyEnabled ? "History is on and armed — this component has not re-rendered since. Interact with the app to record one." : "Enable render history tracking in settings to see render events here."
107
106
  });
108
107
  }
109
108
  return /*#__PURE__*/_jsxs(_Fragment, {
@@ -8,12 +8,12 @@
8
8
  */
9
9
 
10
10
  import { useCallback, useEffect, useMemo, useState } from "react";
11
- import { Text, StyleSheet, ScrollView, View, TouchableOpacity } from "react-native";
12
- import { DynamicFilterView, macOSColors, night, FileText, FileCode, Zap, Settings, Eye, ChevronDown, ChevronUp, AlertTriangle, Layers, ToolbarCopyButton } from "@buoy-gg/shared-ui";
11
+ import { Text, StyleSheet, ScrollView } from "react-native";
12
+ import { DynamicFilterView, macOSColors, night, FileText, FileCode, Zap, Settings, Eye, Layers, ToolbarCopyButton, ExportPreview } from "@buoy-gg/shared-ui";
13
13
  import { DEFAULT_COPY_SETTINGS, COPY_PRESETS, PRESET_METADATA, detectActivePreset } from "../types/copySettings";
14
14
  import { generateExport, estimateExportSize, getExportSummary } from "../utils/rendersExportFormatter";
15
15
  import { loadCopySettings, saveCopySettings } from "../utils/copySettingsStorage";
16
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
16
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
17
17
  const SIZE_WARNING_THRESHOLD = 50 * 1024;
18
18
  const SIZE_DANGER_THRESHOLD = 200 * 1024;
19
19
  const CAUSE_OPTIONS = [{
@@ -191,77 +191,35 @@ export function RendersCopySettingsView({
191
191
  totalComponents,
192
192
  totalRenders
193
193
  } = getExportSummary(previewRenders);
194
- if (!isPreviewExpanded) {
195
- const warningColor = sizeWarningLevel === "danger" ? night.color.danger : sizeWarningLevel === "warning" ? night.color.warning : night.color.textSecondary;
196
- return /*#__PURE__*/_jsxs(View, {
197
- style: styles.collapsedPreview,
198
- children: [/*#__PURE__*/_jsx(TouchableOpacity, {
199
- testID: "buoy-highlight-copy-preview-show",
200
- accessibilityRole: "button",
201
- accessibilityLabel: "Show preview",
202
- style: styles.expandButton,
203
- onPress: () => setIsPreviewExpanded(true),
204
- children: /*#__PURE__*/_jsxs(View, {
205
- style: styles.expandButtonContent,
206
- children: [/*#__PURE__*/_jsx(Eye, {
207
- size: 16,
208
- color: night.color.info
209
- }), /*#__PURE__*/_jsxs(View, {
210
- style: styles.expandButtonTextContainer,
211
- children: [/*#__PURE__*/_jsx(Text, {
212
- style: styles.expandButtonTitle,
213
- children: "Show Preview"
214
- }), /*#__PURE__*/_jsxs(Text, {
215
- testID: "buoy-highlight-copy-preview-summary",
216
- style: styles.expandButtonSubtitle,
217
- children: [totalComponents, " component", totalComponents !== 1 ? "s" : "", " \xB7 ", totalRenders, " renders \xB7 ~", formatBytes(estimatedSize), !hasLiveData ? " (mock data)" : ""]
218
- })]
219
- }), /*#__PURE__*/_jsx(ChevronDown, {
220
- size: 16,
221
- color: night.color.textTertiary
222
- })]
194
+ return /*#__PURE__*/_jsx(ExportPreview, {
195
+ expanded: isPreviewExpanded,
196
+ onExpandedChange: setIsPreviewExpanded,
197
+ summary: `${totalComponents} component${totalComponents !== 1 ? "s" : ""} · ${totalRenders} renders · ~${formatBytes(estimatedSize)}${!hasLiveData ? " (mock data)" : ""}`,
198
+ warningLevel: sizeWarningLevel,
199
+ warningText: {
200
+ warning: "Large payload — preview may be slow",
201
+ danger: "Very large payload — try a smaller topN or turn off history"
202
+ },
203
+ testIDs: {
204
+ expand: "buoy-highlight-copy-preview-show",
205
+ collapse: "buoy-highlight-copy-preview-hide",
206
+ summary: "buoy-highlight-copy-preview-summary",
207
+ warning: "buoy-highlight-copy-size-warning"
208
+ },
209
+ renderBody: () => {
210
+ const exportText = generateCopyText();
211
+ return /*#__PURE__*/_jsx(ScrollView, {
212
+ testID: "buoy-highlight-copy-preview-scroll",
213
+ style: styles.previewScroll,
214
+ nestedScrollEnabled: true,
215
+ children: /*#__PURE__*/_jsx(Text, {
216
+ testID: "buoy-highlight-copy-preview-text",
217
+ style: styles.previewText,
218
+ selectable: true,
219
+ children: exportText
223
220
  })
224
- }), sizeWarningLevel !== "none" && /*#__PURE__*/_jsxs(View, {
225
- testID: "buoy-highlight-copy-size-warning",
226
- style: [styles.sizeWarning, sizeWarningLevel === "danger" && styles.sizeWarningDanger],
227
- children: [/*#__PURE__*/_jsx(AlertTriangle, {
228
- size: 12,
229
- color: warningColor
230
- }), /*#__PURE__*/_jsx(Text, {
231
- style: [styles.sizeWarningText, {
232
- color: warningColor
233
- }],
234
- children: sizeWarningLevel === "danger" ? "Very large payload — try a smaller topN or turn off history" : "Large payload — preview may be slow"
235
- })]
236
- })]
237
- });
238
- }
239
- const exportText = generateCopyText();
240
- return /*#__PURE__*/_jsxs(View, {
241
- children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
242
- testID: "buoy-highlight-copy-preview-hide",
243
- accessibilityRole: "button",
244
- accessibilityLabel: "Hide preview",
245
- style: styles.collapseButton,
246
- onPress: () => setIsPreviewExpanded(false),
247
- children: [/*#__PURE__*/_jsx(Text, {
248
- style: styles.collapseButtonText,
249
- children: "Hide Preview"
250
- }), /*#__PURE__*/_jsx(ChevronUp, {
251
- size: 14,
252
- color: night.color.textSecondary
253
- })]
254
- }), /*#__PURE__*/_jsx(ScrollView, {
255
- testID: "buoy-highlight-copy-preview-scroll",
256
- style: styles.previewScroll,
257
- nestedScrollEnabled: true,
258
- children: /*#__PURE__*/_jsx(Text, {
259
- testID: "buoy-highlight-copy-preview-text",
260
- style: styles.previewText,
261
- selectable: true,
262
- children: exportText
263
- })
264
- })]
221
+ });
222
+ }
265
223
  });
266
224
  }, [isPreviewExpanded, previewRenders, estimatedSize, sizeWarningLevel, hasLiveData, generateCopyText]);
267
225
  const renderPreviewHeaderActions = useCallback(() => {
@@ -486,71 +444,6 @@ export function RendersCopySettingsView({
486
444
  });
487
445
  }
488
446
  const styles = StyleSheet.create({
489
- collapsedPreview: {
490
- gap: 8
491
- },
492
- expandButton: {
493
- backgroundColor: night.color.surfaceElevated,
494
- borderRadius: 8,
495
- borderWidth: 1,
496
- borderColor: night.color.border,
497
- padding: 12
498
- },
499
- expandButtonContent: {
500
- flexDirection: "row",
501
- alignItems: "center",
502
- gap: 10
503
- },
504
- expandButtonTextContainer: {
505
- flex: 1
506
- },
507
- expandButtonTitle: {
508
- fontSize: 13,
509
- fontWeight: "600",
510
- color: night.color.text
511
- },
512
- expandButtonSubtitle: {
513
- fontSize: 11,
514
- color: night.color.textSecondary,
515
- marginTop: 2
516
- },
517
- collapseButton: {
518
- flexDirection: "row",
519
- alignItems: "center",
520
- justifyContent: "center",
521
- gap: 6,
522
- paddingVertical: 8,
523
- marginBottom: 8,
524
- backgroundColor: night.color.surfaceElevated,
525
- borderRadius: 6,
526
- borderWidth: 1,
527
- borderColor: night.color.border
528
- },
529
- collapseButtonText: {
530
- fontSize: 12,
531
- fontWeight: "500",
532
- color: night.color.textSecondary
533
- },
534
- sizeWarning: {
535
- flexDirection: "row",
536
- alignItems: "center",
537
- gap: 6,
538
- paddingHorizontal: 10,
539
- paddingVertical: 6,
540
- backgroundColor: night.color.warningSoft,
541
- borderRadius: 6,
542
- borderWidth: 1,
543
- borderColor: night.color.warning + "30"
544
- },
545
- sizeWarningDanger: {
546
- backgroundColor: night.color.dangerSoft,
547
- borderColor: night.color.danger + "30"
548
- },
549
- sizeWarningText: {
550
- fontSize: 11,
551
- fontWeight: "500",
552
- flex: 1
553
- },
554
447
  previewScroll: {
555
448
  maxHeight: 360
556
449
  },
@@ -3,41 +3,24 @@
3
3
  /**
4
4
  * Copy Settings Storage
5
5
  *
6
- * Persists the highlight-updates copy/export settings.
6
+ * Persists the highlight-updates copy/export settings through the shared
7
+ * `definePersistedSetting` (merge-over-defaults, best-effort save/clear).
7
8
  */
8
9
 
9
- import { persistentStorage, devToolsStorageKeys } from "@buoy-gg/shared-ui";
10
+ import { definePersistedSetting, devToolsStorageKeys } from "@buoy-gg/shared-ui";
10
11
  import { DEFAULT_COPY_SETTINGS } from "../types/copySettings";
12
+ const copySettings = definePersistedSetting(devToolsStorageKeys.highlightUpdates.copySettings(), DEFAULT_COPY_SETTINGS, {
13
+ sanitize: (merged, stored) => ({
14
+ ...merged,
15
+ filterCauses: stored?.filterCauses ?? DEFAULT_COPY_SETTINGS.filterCauses
16
+ })
17
+ });
11
18
  export async function saveCopySettings(settings) {
12
- try {
13
- const key = devToolsStorageKeys.highlightUpdates.copySettings();
14
- await persistentStorage.setItem(key, JSON.stringify(settings));
15
- } catch {
16
- // Silently fail — persistence is optional
17
- }
19
+ await copySettings.save(settings);
18
20
  }
19
21
  export async function loadCopySettings() {
20
- try {
21
- const key = devToolsStorageKeys.highlightUpdates.copySettings();
22
- const value = await persistentStorage.getItem(key);
23
- if (value && value !== "") {
24
- const parsed = JSON.parse(value);
25
- return {
26
- ...DEFAULT_COPY_SETTINGS,
27
- ...parsed,
28
- filterCauses: parsed.filterCauses ?? DEFAULT_COPY_SETTINGS.filterCauses
29
- };
30
- }
31
- return null;
32
- } catch {
33
- return null;
34
- }
22
+ return copySettings.loadOrNull();
35
23
  }
36
24
  export async function clearCopySettings() {
37
- try {
38
- const key = devToolsStorageKeys.highlightUpdates.copySettings();
39
- await persistentStorage.removeItem(key);
40
- } catch {
41
- // Silently fail
42
- }
25
+ await copySettings.clear();
43
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"IsolatedRenderList.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/components/IsolatedRenderList.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAkE,MAAM,OAAO,CAAC;AAEvF,OAAO,EAAiB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAK9F,UAAU,uBAAuB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,YAAY,CAAC;IACtB,cAAc,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IAC5F,aAAa,EAAE,CAAC,KAAK,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAClF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IACrD,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,iBAAS,uBAAuB,CAAC,EAC/B,UAAU,EACV,OAAO,EACP,cAAc,EACd,aAAa,EACb,eAAe,EACf,UAAU,EACV,KAAa,GACd,EAAE,uBAAuB,qBAyGzB;AAGD,eAAO,MAAM,kBAAkB,2DAAgC,CAAC;AA0ChE,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"IsolatedRenderList.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/components/IsolatedRenderList.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAkE,MAAM,OAAO,CAAC;AAEvF,OAAO,EAAiB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAW9F,UAAU,uBAAuB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,YAAY,CAAC;IACtB,cAAc,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IAC5F,aAAa,EAAE,CAAC,KAAK,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAClF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IACrD,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,iBAAS,uBAAuB,CAAC,EAC/B,UAAU,EACV,OAAO,EACP,cAAc,EACd,aAAa,EACb,eAAe,EACf,UAAU,EACV,KAAa,GACd,EAAE,uBAAuB,qBAiIzB;AAGD,eAAO,MAAM,kBAAkB,2DAAgC,CAAC;AA0BhE,eAAe,kBAAkB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ModalHeaderContent.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/components/ModalHeaderContent.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAoC,MAAM,OAAO,CAAC;AACzD,OAAO,EAIL,SAAS,EAEV,MAAM,cAAc,CAAC;AAmBtB,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;CACnD;AAkDD,eAAO,MAAM,aAAa,gDAAqB,CAAC;AAMhD,UAAU,kBAAkB;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AAyHD,eAAO,MAAM,aAAa,gDAAqB,CAAC;AAMhD,UAAU,mBAAmB;IAC3B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;CACnD;AAED,eAAO,MAAM,cAAc,iDAgDzB,CAAC;AAMH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAEnD,UAAU,qBAAqB;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,gBAAgB,mDA4B3B,CAAC;AAMH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,CAAC;AAElD,UAAU,qBAAqB;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,mDAyB3B,CAAC;AAMH,UAAU,2BAA2B;IACnC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,eAAO,MAAM,sBAAsB,yDAYjC,CAAC"}
1
+ {"version":3,"file":"ModalHeaderContent.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/components/ModalHeaderContent.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAoC,MAAM,OAAO,CAAC;AACzD,OAAO,EAIL,SAAS,EAEV,MAAM,cAAc,CAAC;AAmBtB,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;CACnD;AAgCD,eAAO,MAAM,aAAa,gDAAqB,CAAC;AAMhD,UAAU,kBAAkB;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB;AAyHD,eAAO,MAAM,aAAa,gDAAqB,CAAC;AAMhD,UAAU,mBAAmB;IAC3B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;CACnD;AAED,eAAO,MAAM,cAAc,iDAgDzB,CAAC;AAMH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAEnD,UAAU,qBAAqB;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,gBAAgB,mDA4B3B,CAAC;AAMH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,CAAC;AAElD,UAAU,qBAAqB;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,EAAE,aAAa,CAAC;IACzB,WAAW,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,mDAyB3B,CAAC;AAMH,UAAU,2BAA2B;IACnC,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAED,eAAO,MAAM,sBAAsB,yDAYjC,CAAC"}
@@ -6,7 +6,7 @@
6
6
  * Shows current state view or diff view between renders.
7
7
  */
8
8
  import React from "react";
9
- import type { TrackedRender } from "../utils/RenderTracker";
9
+ import { type TrackedRender } from "../utils/RenderTracker";
10
10
  interface RenderHistoryViewerProps {
11
11
  render: TrackedRender;
12
12
  /** If true, use external footer (modal provides it) */
@@ -1 +1 @@
1
- {"version":3,"file":"RenderHistoryViewer.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/components/RenderHistoryViewer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAyC,MAAM,OAAO,CAAC;AAe9D,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,wBAAwB,CAAC;AAGzE,UAAU,wBAAwB;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,uDAAuD;IACvD,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,wCAAwC;IACxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wCAAwC;IACxC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAqBD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,qBAA6B,EAC7B,kBAAkB,EAAE,aAAa,EACjC,kBAAkB,EAAE,gBAAgB,EACpC,KAAa,GACd,EAAE,wBAAwB,qBAyM1B;AAyRD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,kBAAsB,EACtB,kBAA6B,EAC7B,KAAa,GACd,EAAE;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,4BA6CA;AA+YD,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"RenderHistoryViewer.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/components/RenderHistoryViewer.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAyC,MAAM,OAAO,CAAC;AAiB9D,OAAO,EAAiB,KAAK,aAAa,EAAoB,MAAM,wBAAwB,CAAC;AAG7F,UAAU,wBAAwB;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,uDAAuD;IACvD,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,wCAAwC;IACxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wCAAwC;IACxC,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAqBD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,qBAA6B,EAC7B,kBAAkB,EAAE,aAAa,EACjC,kBAAkB,EAAE,gBAAgB,EACpC,KAAa,GACd,EAAE,wBAAwB,qBAiN1B;AAyRD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,kBAAsB,EACtB,kBAA6B,EAC7B,KAAa,GACd,EAAE;IACD,MAAM,EAAE,aAAa,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,4BA6CA;AA+YD,eAAe,mBAAmB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RendersCopySettingsView.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/components/RendersCopySettingsView.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,wBAAwB,CAAC;AAmB7E,UAAU,4BAA4B;IACpC,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AA+ED,wBAAgB,uBAAuB,CAAC,EACtC,OAAO,GACR,EAAE,4BAA4B,+BAsb9B"}
1
+ {"version":3,"file":"RendersCopySettingsView.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/components/RendersCopySettingsView.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsBH,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,wBAAwB,CAAC;AAmB7E,UAAU,4BAA4B;IACpC,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AA+ED,wBAAgB,uBAAuB,CAAC,EACtC,OAAO,GACR,EAAE,4BAA4B,+BAuY9B"}
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Copy Settings Storage
3
3
  *
4
- * Persists the highlight-updates copy/export settings.
4
+ * Persists the highlight-updates copy/export settings through the shared
5
+ * `definePersistedSetting` (merge-over-defaults, best-effort save/clear).
5
6
  */
6
7
  import type { RendersCopySettings } from "../types/copySettings";
7
8
  export declare function saveCopySettings(settings: RendersCopySettings): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"copySettingsStorage.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/utils/copySettingsStorage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGjE,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAiB5E;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOvD"}
1
+ {"version":3,"file":"copySettingsStorage.d.ts","sourceRoot":"","sources":["../../../../src/highlight-updates/utils/copySettingsStorage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAgBjE,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnF;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAE5E;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEvD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buoy-gg/highlight-updates",
3
- "version": "7.0.32",
3
+ "version": "7.0.34",
4
4
  "description": "Render highlighter for React Native — see every render with its cause: mount, state, props, or parent. Part of Buoy devtools.",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -26,14 +26,14 @@
26
26
  ],
27
27
  "sideEffects": false,
28
28
  "dependencies": {
29
- "@buoy-gg/shared-ui": "^7.0.32",
30
- "@buoy-gg/floating-tools-core": "^7.0.32"
29
+ "@buoy-gg/shared-ui": "^7.0.34",
30
+ "@buoy-gg/floating-tools-core": "^7.0.34"
31
31
  },
32
32
  "peerDependencies": {
33
- "@buoy-gg/license": "7.0.32",
33
+ "@buoy-gg/license": "7.0.34",
34
34
  "react": "*",
35
35
  "react-native": "*",
36
- "@buoy-gg/core": "^7.0.32"
36
+ "@buoy-gg/core": "^7.0.34"
37
37
  },
38
38
  "peerDependenciesMeta": {
39
39
  "@buoy-gg/core": {
@@ -44,8 +44,8 @@
44
44
  "@types/react": "^19.1.0",
45
45
  "@types/react-native": "^0.73.0",
46
46
  "typescript": "~5.8.3",
47
- "@buoy-gg/core": "^7.0.32",
48
- "@buoy-gg/license": "^7.0.32"
47
+ "@buoy-gg/core": "^7.0.34",
48
+ "@buoy-gg/license": "^7.0.34"
49
49
  },
50
50
  "react-native-builder-bob": {
51
51
  "source": "src",