@buoy-gg/storage 1.7.2

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 (187) hide show
  1. package/README.md +607 -0
  2. package/lib/commonjs/index.js +34 -0
  3. package/lib/commonjs/package.json +1 -0
  4. package/lib/commonjs/preset.js +94 -0
  5. package/lib/commonjs/storage/components/DiffViewer/DiffOptionsPanel.js +356 -0
  6. package/lib/commonjs/storage/components/DiffViewer/TreeDiffViewer.js +29 -0
  7. package/lib/commonjs/storage/components/DiffViewer/components/DiffSummary.js +121 -0
  8. package/lib/commonjs/storage/components/DiffViewer/modes/ThemedSplitView.js +419 -0
  9. package/lib/commonjs/storage/components/DiffViewer/themes/diffThemes.js +122 -0
  10. package/lib/commonjs/storage/components/GameUIStorageBrowser.js +924 -0
  11. package/lib/commonjs/storage/components/GameUIStorageStats.js +746 -0
  12. package/lib/commonjs/storage/components/MMKVInstanceInfoPanel.js +257 -0
  13. package/lib/commonjs/storage/components/MMKVInstanceSelector.js +418 -0
  14. package/lib/commonjs/storage/components/SelectionActionBar.js +224 -0
  15. package/lib/commonjs/storage/components/StorageActionButtons.js +239 -0
  16. package/lib/commonjs/storage/components/StorageActions.js +192 -0
  17. package/lib/commonjs/storage/components/StorageBrowserMode.js +31 -0
  18. package/lib/commonjs/storage/components/StorageEventDetailContent.js +1025 -0
  19. package/lib/commonjs/storage/components/StorageEventFilterView.js +141 -0
  20. package/lib/commonjs/storage/components/StorageEventListener.js +357 -0
  21. package/lib/commonjs/storage/components/StorageEventsSection.js +24 -0
  22. package/lib/commonjs/storage/components/StorageFilterCards.js +345 -0
  23. package/lib/commonjs/storage/components/StorageFilterViewV2.js +42 -0
  24. package/lib/commonjs/storage/components/StorageKeyCard.js +516 -0
  25. package/lib/commonjs/storage/components/StorageKeyRow.js +356 -0
  26. package/lib/commonjs/storage/components/StorageKeySection.js +105 -0
  27. package/lib/commonjs/storage/components/StorageKeyStats.js +344 -0
  28. package/lib/commonjs/storage/components/StorageModalWithTabs.js +871 -0
  29. package/lib/commonjs/storage/components/StorageSection.js +43 -0
  30. package/lib/commonjs/storage/hooks/useAsyncStorageKeys.js +126 -0
  31. package/lib/commonjs/storage/hooks/useMMKVInstances.js +221 -0
  32. package/lib/commonjs/storage/hooks/useMMKVKeys.js +362 -0
  33. package/lib/commonjs/storage/hooks/useTickEverySecond.js +21 -0
  34. package/lib/commonjs/storage/index.js +148 -0
  35. package/lib/commonjs/storage/types.js +5 -0
  36. package/lib/commonjs/storage/utils/AsyncStorageListener.js +510 -0
  37. package/lib/commonjs/storage/utils/MMKVInstanceRegistry.js +202 -0
  38. package/lib/commonjs/storage/utils/MMKVListener.js +380 -0
  39. package/lib/commonjs/storage/utils/clearAllStorage.js +47 -0
  40. package/lib/commonjs/storage/utils/index.js +180 -0
  41. package/lib/commonjs/storage/utils/lineDiff.js +363 -0
  42. package/lib/commonjs/storage/utils/mmkvAvailability.js +62 -0
  43. package/lib/commonjs/storage/utils/mmkvTypeDetection.js +139 -0
  44. package/lib/commonjs/storage/utils/objectDiff.js +157 -0
  45. package/lib/commonjs/storage/utils/safeAsyncStorage.js +140 -0
  46. package/lib/commonjs/storage/utils/storageActionHelpers.js +46 -0
  47. package/lib/commonjs/storage/utils/storageQueryUtils.js +35 -0
  48. package/lib/commonjs/storage/utils/valueType.js +18 -0
  49. package/lib/module/index.js +7 -0
  50. package/lib/module/preset.js +89 -0
  51. package/lib/module/storage/components/DiffViewer/DiffOptionsPanel.js +352 -0
  52. package/lib/module/storage/components/DiffViewer/TreeDiffViewer.js +25 -0
  53. package/lib/module/storage/components/DiffViewer/components/DiffSummary.js +117 -0
  54. package/lib/module/storage/components/DiffViewer/modes/ThemedSplitView.js +415 -0
  55. package/lib/module/storage/components/DiffViewer/themes/diffThemes.js +118 -0
  56. package/lib/module/storage/components/GameUIStorageBrowser.js +922 -0
  57. package/lib/module/storage/components/GameUIStorageStats.js +742 -0
  58. package/lib/module/storage/components/MMKVInstanceInfoPanel.js +253 -0
  59. package/lib/module/storage/components/MMKVInstanceSelector.js +414 -0
  60. package/lib/module/storage/components/SelectionActionBar.js +221 -0
  61. package/lib/module/storage/components/StorageActionButtons.js +236 -0
  62. package/lib/module/storage/components/StorageActions.js +189 -0
  63. package/lib/module/storage/components/StorageBrowserMode.js +27 -0
  64. package/lib/module/storage/components/StorageEventDetailContent.js +1020 -0
  65. package/lib/module/storage/components/StorageEventFilterView.js +137 -0
  66. package/lib/module/storage/components/StorageEventListener.js +354 -0
  67. package/lib/module/storage/components/StorageEventsSection.js +20 -0
  68. package/lib/module/storage/components/StorageFilterCards.js +341 -0
  69. package/lib/module/storage/components/StorageFilterViewV2.js +38 -0
  70. package/lib/module/storage/components/StorageKeyCard.js +513 -0
  71. package/lib/module/storage/components/StorageKeyRow.js +353 -0
  72. package/lib/module/storage/components/StorageKeySection.js +101 -0
  73. package/lib/module/storage/components/StorageKeyStats.js +340 -0
  74. package/lib/module/storage/components/StorageModalWithTabs.js +867 -0
  75. package/lib/module/storage/components/StorageSection.js +40 -0
  76. package/lib/module/storage/hooks/useAsyncStorageKeys.js +121 -0
  77. package/lib/module/storage/hooks/useMMKVInstances.js +216 -0
  78. package/lib/module/storage/hooks/useMMKVKeys.js +359 -0
  79. package/lib/module/storage/hooks/useTickEverySecond.js +18 -0
  80. package/lib/module/storage/index.js +25 -0
  81. package/lib/module/storage/types.js +3 -0
  82. package/lib/module/storage/utils/AsyncStorageListener.js +500 -0
  83. package/lib/module/storage/utils/MMKVInstanceRegistry.js +196 -0
  84. package/lib/module/storage/utils/MMKVListener.js +367 -0
  85. package/lib/module/storage/utils/clearAllStorage.js +42 -0
  86. package/lib/module/storage/utils/index.js +22 -0
  87. package/lib/module/storage/utils/lineDiff.js +359 -0
  88. package/lib/module/storage/utils/mmkvAvailability.js +56 -0
  89. package/lib/module/storage/utils/mmkvTypeDetection.js +133 -0
  90. package/lib/module/storage/utils/objectDiff.js +153 -0
  91. package/lib/module/storage/utils/safeAsyncStorage.js +134 -0
  92. package/lib/module/storage/utils/storageActionHelpers.js +42 -0
  93. package/lib/module/storage/utils/storageQueryUtils.js +30 -0
  94. package/lib/module/storage/utils/valueType.js +14 -0
  95. package/lib/typescript/index.d.ts +3 -0
  96. package/lib/typescript/index.d.ts.map +1 -0
  97. package/lib/typescript/preset.d.ts +90 -0
  98. package/lib/typescript/preset.d.ts.map +1 -0
  99. package/lib/typescript/storage/components/DiffViewer/DiffOptionsPanel.d.ts +18 -0
  100. package/lib/typescript/storage/components/DiffViewer/DiffOptionsPanel.d.ts.map +1 -0
  101. package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts +7 -0
  102. package/lib/typescript/storage/components/DiffViewer/TreeDiffViewer.d.ts.map +1 -0
  103. package/lib/typescript/storage/components/DiffViewer/components/DiffSummary.d.ts +12 -0
  104. package/lib/typescript/storage/components/DiffViewer/components/DiffSummary.d.ts.map +1 -0
  105. package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts +13 -0
  106. package/lib/typescript/storage/components/DiffViewer/modes/ThemedSplitView.d.ts.map +1 -0
  107. package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts +64 -0
  108. package/lib/typescript/storage/components/DiffViewer/themes/diffThemes.d.ts.map +1 -0
  109. package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts +16 -0
  110. package/lib/typescript/storage/components/GameUIStorageBrowser.d.ts.map +1 -0
  111. package/lib/typescript/storage/components/GameUIStorageStats.d.ts +7 -0
  112. package/lib/typescript/storage/components/GameUIStorageStats.d.ts.map +1 -0
  113. package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts +42 -0
  114. package/lib/typescript/storage/components/MMKVInstanceInfoPanel.d.ts.map +1 -0
  115. package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts +35 -0
  116. package/lib/typescript/storage/components/MMKVInstanceSelector.d.ts.map +1 -0
  117. package/lib/typescript/storage/components/SelectionActionBar.d.ts +21 -0
  118. package/lib/typescript/storage/components/SelectionActionBar.d.ts.map +1 -0
  119. package/lib/typescript/storage/components/StorageActionButtons.d.ts +21 -0
  120. package/lib/typescript/storage/components/StorageActionButtons.d.ts.map +1 -0
  121. package/lib/typescript/storage/components/StorageActions.d.ts +10 -0
  122. package/lib/typescript/storage/components/StorageActions.d.ts.map +1 -0
  123. package/lib/typescript/storage/components/StorageBrowserMode.d.ts +18 -0
  124. package/lib/typescript/storage/components/StorageBrowserMode.d.ts.map +1 -0
  125. package/lib/typescript/storage/components/StorageEventDetailContent.d.ts +40 -0
  126. package/lib/typescript/storage/components/StorageEventDetailContent.d.ts.map +1 -0
  127. package/lib/typescript/storage/components/StorageEventFilterView.d.ts +11 -0
  128. package/lib/typescript/storage/components/StorageEventFilterView.d.ts.map +1 -0
  129. package/lib/typescript/storage/components/StorageEventListener.d.ts +6 -0
  130. package/lib/typescript/storage/components/StorageEventListener.d.ts.map +1 -0
  131. package/lib/typescript/storage/components/StorageEventsSection.d.ts +7 -0
  132. package/lib/typescript/storage/components/StorageEventsSection.d.ts.map +1 -0
  133. package/lib/typescript/storage/components/StorageFilterCards.d.ts +36 -0
  134. package/lib/typescript/storage/components/StorageFilterCards.d.ts.map +1 -0
  135. package/lib/typescript/storage/components/StorageFilterViewV2.d.ts +9 -0
  136. package/lib/typescript/storage/components/StorageFilterViewV2.d.ts.map +1 -0
  137. package/lib/typescript/storage/components/StorageKeyCard.d.ts +17 -0
  138. package/lib/typescript/storage/components/StorageKeyCard.d.ts.map +1 -0
  139. package/lib/typescript/storage/components/StorageKeyRow.d.ts +15 -0
  140. package/lib/typescript/storage/components/StorageKeyRow.d.ts.map +1 -0
  141. package/lib/typescript/storage/components/StorageKeySection.d.ts +25 -0
  142. package/lib/typescript/storage/components/StorageKeySection.d.ts.map +1 -0
  143. package/lib/typescript/storage/components/StorageKeyStats.d.ts +15 -0
  144. package/lib/typescript/storage/components/StorageKeyStats.d.ts.map +1 -0
  145. package/lib/typescript/storage/components/StorageModalWithTabs.d.ts +13 -0
  146. package/lib/typescript/storage/components/StorageModalWithTabs.d.ts.map +1 -0
  147. package/lib/typescript/storage/components/StorageSection.d.ts +10 -0
  148. package/lib/typescript/storage/components/StorageSection.d.ts.map +1 -0
  149. package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts +10 -0
  150. package/lib/typescript/storage/hooks/useAsyncStorageKeys.d.ts.map +1 -0
  151. package/lib/typescript/storage/hooks/useMMKVInstances.d.ts +114 -0
  152. package/lib/typescript/storage/hooks/useMMKVInstances.d.ts.map +1 -0
  153. package/lib/typescript/storage/hooks/useMMKVKeys.d.ts +94 -0
  154. package/lib/typescript/storage/hooks/useMMKVKeys.d.ts.map +1 -0
  155. package/lib/typescript/storage/hooks/useTickEverySecond.d.ts +6 -0
  156. package/lib/typescript/storage/hooks/useTickEverySecond.d.ts.map +1 -0
  157. package/lib/typescript/storage/index.d.ts +15 -0
  158. package/lib/typescript/storage/index.d.ts.map +1 -0
  159. package/lib/typescript/storage/types.d.ts +41 -0
  160. package/lib/typescript/storage/types.d.ts.map +1 -0
  161. package/lib/typescript/storage/utils/AsyncStorageListener.d.ts +195 -0
  162. package/lib/typescript/storage/utils/AsyncStorageListener.d.ts.map +1 -0
  163. package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts +224 -0
  164. package/lib/typescript/storage/utils/MMKVInstanceRegistry.d.ts.map +1 -0
  165. package/lib/typescript/storage/utils/MMKVListener.d.ts +218 -0
  166. package/lib/typescript/storage/utils/MMKVListener.d.ts.map +1 -0
  167. package/lib/typescript/storage/utils/clearAllStorage.d.ts +11 -0
  168. package/lib/typescript/storage/utils/clearAllStorage.d.ts.map +1 -0
  169. package/lib/typescript/storage/utils/index.d.ts +8 -0
  170. package/lib/typescript/storage/utils/index.d.ts.map +1 -0
  171. package/lib/typescript/storage/utils/lineDiff.d.ts +34 -0
  172. package/lib/typescript/storage/utils/lineDiff.d.ts.map +1 -0
  173. package/lib/typescript/storage/utils/mmkvAvailability.d.ts +23 -0
  174. package/lib/typescript/storage/utils/mmkvAvailability.d.ts.map +1 -0
  175. package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts +71 -0
  176. package/lib/typescript/storage/utils/mmkvTypeDetection.d.ts.map +1 -0
  177. package/lib/typescript/storage/utils/objectDiff.d.ts +35 -0
  178. package/lib/typescript/storage/utils/objectDiff.d.ts.map +1 -0
  179. package/lib/typescript/storage/utils/safeAsyncStorage.d.ts +56 -0
  180. package/lib/typescript/storage/utils/safeAsyncStorage.d.ts.map +1 -0
  181. package/lib/typescript/storage/utils/storageActionHelpers.d.ts +5 -0
  182. package/lib/typescript/storage/utils/storageActionHelpers.d.ts.map +1 -0
  183. package/lib/typescript/storage/utils/storageQueryUtils.d.ts +6 -0
  184. package/lib/typescript/storage/utils/storageQueryUtils.d.ts.map +1 -0
  185. package/lib/typescript/storage/utils/valueType.d.ts +3 -0
  186. package/lib/typescript/storage/utils/valueType.d.ts.map +1 -0
  187. package/package.json +68 -0
@@ -0,0 +1,1020 @@
1
+ "use strict";
2
+
3
+ import { View, Text, StyleSheet, TouchableOpacity, ScrollView } from "react-native";
4
+ import { useEffect, useState, useCallback, useRef } from "react";
5
+ import AsyncStorage from "@react-native-async-storage/async-storage";
6
+ import { formatRelativeTime, macOSColors, parseValue, devToolsStorageKeys, ChevronLeft, ChevronRight, AlertCircle, X, Database, GitBranch, EventStepperFooter, Lock } from "@buoy-gg/shared-ui";
7
+ import { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
8
+ import { ThemedSplitView } from "./DiffViewer/modes/ThemedSplitView";
9
+ import { diffThemes } from "./DiffViewer/themes/diffThemes";
10
+ import { computeLineDiff, DiffType } from "../utils/lineDiff";
11
+ import { TreeDiffViewer } from "./DiffViewer/TreeDiffViewer";
12
+ import { translateStorageAction } from "../utils/storageActionHelpers";
13
+
14
+ // Lazy load the license hooks to avoid circular dependencies
15
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
16
+ let _useIsPro = null;
17
+ let _licenseLoadAttempted = false;
18
+ function loadLicenseModule() {
19
+ if (_licenseLoadAttempted) return;
20
+ _licenseLoadAttempted = true;
21
+ try {
22
+ const mod = require("@buoy-gg/license");
23
+ if (mod) {
24
+ _useIsPro = mod.useIsPro ?? null;
25
+ }
26
+ } catch {
27
+ // License package not available
28
+ }
29
+ }
30
+ function getUseIsPro() {
31
+ loadLicenseModule();
32
+ return _useIsPro ?? (() => false);
33
+ }
34
+
35
+ // Free tier limit for event history navigation
36
+ const FREE_TIER_EVENT_HISTORY_LIMIT = 3;
37
+
38
+ // Unified storage event type (supports both AsyncStorage and MMKV)
39
+
40
+ export function StorageEventDetailContent({
41
+ conversation,
42
+ selectedEventIndex = 0,
43
+ onEventIndexChange = () => {},
44
+ disableInternalFooter = false
45
+ }) {
46
+ // Check Pro status internally
47
+ const useIsPro = getUseIsPro();
48
+ const isPro = useIsPro();
49
+ // Internal view state - now managed internally instead of via props
50
+ const [internalActiveView, setInternalActiveView] = useState("current");
51
+ // Compare-any-two state for Diff tab
52
+ const [leftIndex, setLeftIndex] = useState(Math.max(0, selectedEventIndex - 1));
53
+ const [rightIndex, setRightIndex] = useState(selectedEventIndex);
54
+ const [isLeftPickerOpen, setIsLeftPickerOpen] = useState(false);
55
+ const [isRightPickerOpen, setIsRightPickerOpen] = useState(false);
56
+ const [diffViewerTab, setDiffViewerTab] = useState("tree");
57
+
58
+ // Track if preferences have been loaded
59
+ const hasLoadedPreferences = useRef(false);
60
+
61
+ // Load saved preferences on mount
62
+ useEffect(() => {
63
+ if (hasLoadedPreferences.current) return;
64
+ const loadPreferences = async () => {
65
+ try {
66
+ // Load detail view preference (current/diff)
67
+ const savedDetailView = await AsyncStorage.getItem(devToolsStorageKeys.storage.detailView());
68
+ if (savedDetailView === "current" || savedDetailView === "diff") {
69
+ setInternalActiveView(savedDetailView);
70
+ }
71
+
72
+ // Load diff viewer mode preference (split/tree)
73
+ const savedDiffMode = await AsyncStorage.getItem(devToolsStorageKeys.storage.diffViewerMode());
74
+ if (savedDiffMode === "split" || savedDiffMode === "tree") {
75
+ setDiffViewerTab(savedDiffMode);
76
+ }
77
+ hasLoadedPreferences.current = true;
78
+ } catch (error) {
79
+ // Failed to load view preferences
80
+ }
81
+ };
82
+ loadPreferences();
83
+ }, []);
84
+
85
+ // Save detail view preference when changed
86
+ const handleViewChange = useCallback(async view => {
87
+ setInternalActiveView(view);
88
+ try {
89
+ await AsyncStorage.setItem(devToolsStorageKeys.storage.detailView(), view);
90
+ } catch (error) {
91
+ // Failed to save detail view preference
92
+ }
93
+ }, []);
94
+
95
+ // Save diff viewer mode preference when changed
96
+ const handleDiffModeChange = useCallback(async mode => {
97
+ setDiffViewerTab(mode);
98
+ try {
99
+ await AsyncStorage.setItem(devToolsStorageKeys.storage.diffViewerMode(), mode);
100
+ } catch (error) {
101
+ // Failed to save diff viewer mode preference
102
+ }
103
+ }, []);
104
+ const getActionColor = action => {
105
+ switch (action) {
106
+ case "setItem":
107
+ case "multiSet":
108
+ return macOSColors.semantic.success;
109
+ case "removeItem":
110
+ case "multiRemove":
111
+ case "clear":
112
+ return macOSColors.semantic.error;
113
+ case "mergeItem":
114
+ case "multiMerge":
115
+ return macOSColors.semantic.info;
116
+ default:
117
+ return macOSColors.text.muted;
118
+ }
119
+ };
120
+ const renderValueContent = (value, label, action) => {
121
+ const parsed = parseValue(value);
122
+ const type = parsed === null ? "null" : parsed === undefined ? "undefined" : Array.isArray(parsed) ? "array" : typeof parsed;
123
+ return /*#__PURE__*/_jsxs(View, {
124
+ style: styles.valueContent,
125
+ children: [/*#__PURE__*/_jsxs(View, {
126
+ style: styles.valueHeader,
127
+ children: [/*#__PURE__*/_jsx(Text, {
128
+ style: styles.valueLabel,
129
+ children: label
130
+ }), /*#__PURE__*/_jsxs(View, {
131
+ style: styles.valueHeaderBadges,
132
+ children: [action && /*#__PURE__*/_jsx(View, {
133
+ style: [styles.actionBadge, {
134
+ backgroundColor: `${getActionColor(action)}20`
135
+ }],
136
+ children: /*#__PURE__*/_jsx(Text, {
137
+ style: [styles.actionText, {
138
+ color: getActionColor(action)
139
+ }],
140
+ children: translateStorageAction(action)
141
+ })
142
+ }), /*#__PURE__*/_jsx(View, {
143
+ style: [styles.typeBadge],
144
+ children: /*#__PURE__*/_jsx(Text, {
145
+ style: styles.typeText,
146
+ children: type.toUpperCase()
147
+ })
148
+ })]
149
+ })]
150
+ }), /*#__PURE__*/_jsx(View, {
151
+ style: styles.valueBox,
152
+ children: type === "object" || type === "array" ? parsed && (Array.isArray(parsed) && parsed.length > 0 || typeof parsed === "object" && Object.keys(parsed).length > 0) ? /*#__PURE__*/_jsx(DataViewer, {
153
+ title: "",
154
+ data: parsed,
155
+ showTypeFilter: false
156
+ }) : /*#__PURE__*/_jsx(Text, {
157
+ style: styles.valueText,
158
+ children: type === "array" ? "[]" : "{}"
159
+ }) : /*#__PURE__*/_jsx(Text, {
160
+ style: styles.valueText,
161
+ children: parsed === null ? "null" : parsed === undefined ? "undefined" : type === "string" ? `"${parsed}"` : String(parsed)
162
+ })
163
+ })]
164
+ });
165
+ };
166
+
167
+ // Get all events sorted by time
168
+ const navigationItems = conversation.events.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
169
+ const totalEvents = navigationItems.length;
170
+
171
+ // Free tier limit - max event index accessible
172
+ const maxAccessibleEventIndex = isPro ? totalEvents - 1 : Math.min(FREE_TIER_EVENT_HISTORY_LIMIT - 1, totalEvents - 1);
173
+ const lockedEventCount = isPro ? 0 : Math.max(0, totalEvents - FREE_TIER_EVENT_HISTORY_LIMIT);
174
+
175
+ // Keep compare indices synced to selection
176
+ useEffect(() => {
177
+ const newRight = Math.min(totalEvents - 1, Math.max(0, selectedEventIndex));
178
+ const newLeft = Math.max(0, Math.min(newRight - 1, selectedEventIndex - 1));
179
+ setLeftIndex(newLeft);
180
+ setRightIndex(newRight);
181
+ }, [selectedEventIndex, totalEvents]);
182
+
183
+ // Precise time HH:MM:SS.mmm
184
+ const formatTimeWithMs = useCallback(date => {
185
+ const h = String(date.getHours()).padStart(2, "0");
186
+ const m = String(date.getMinutes()).padStart(2, "0");
187
+ const s = String(date.getSeconds()).padStart(2, "0");
188
+ const ms = String(date.getMilliseconds()).padStart(3, "0");
189
+ return `${h}:${m}:${s}.${ms}`;
190
+ }, []);
191
+ const bumpLeft = delta => {
192
+ if (totalEvents < 2) return;
193
+ const maxLeft = isPro ? totalEvents - 2 : Math.min(maxAccessibleEventIndex - 1, totalEvents - 2);
194
+ let next = Math.max(0, Math.min(maxLeft, leftIndex + delta));
195
+ if (next >= rightIndex) next = Math.max(0, rightIndex - 1);
196
+ setLeftIndex(next);
197
+ };
198
+ const bumpRight = delta => {
199
+ if (totalEvents < 2) return;
200
+ const maxRight = isPro ? totalEvents - 1 : maxAccessibleEventIndex;
201
+ let next = Math.max(1, Math.min(maxRight, rightIndex + delta));
202
+ if (next <= leftIndex) next = Math.min(maxRight, leftIndex + 1);
203
+ setRightIndex(next);
204
+ };
205
+
206
+ // Render current value tab
207
+ const renderCurrentValue = () => {
208
+ const selectedEvent = navigationItems[selectedEventIndex];
209
+ const valueToShow = selectedEvent?.data?.value ?? conversation.currentValue;
210
+ const action = selectedEvent?.action;
211
+ return /*#__PURE__*/_jsx(View, {
212
+ style: styles.fullPageSection,
213
+ children: /*#__PURE__*/_jsx(View, {
214
+ style: styles.contentCard,
215
+ children: renderValueContent(valueToShow, "CURRENT VALUE", action)
216
+ })
217
+ });
218
+ };
219
+
220
+ // Render diff tab
221
+ const renderDiff = () => {
222
+ if (navigationItems.length === 0) {
223
+ return /*#__PURE__*/_jsxs(View, {
224
+ style: styles.emptyState,
225
+ children: [/*#__PURE__*/_jsx(AlertCircle, {
226
+ size: 32,
227
+ color: macOSColors.text.muted
228
+ }), /*#__PURE__*/_jsx(Text, {
229
+ style: styles.emptyText,
230
+ children: "No changes to display"
231
+ })]
232
+ });
233
+ }
234
+ const leftEvent = navigationItems[Math.max(0, Math.min(totalEvents - 1, leftIndex))];
235
+ const rightEvent = navigationItems[Math.max(0, Math.min(totalEvents - 1, rightIndex))];
236
+ const previousValue = leftEvent?.data?.value ?? null;
237
+ const currentValue = rightEvent?.data?.value;
238
+ return /*#__PURE__*/_jsxs(View, {
239
+ style: styles.fullPageSection,
240
+ children: [/*#__PURE__*/_jsxs(View, {
241
+ style: styles.diffViewerTabs,
242
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
243
+ style: [styles.diffViewerTab, diffViewerTab === "split" && styles.diffViewerTabActive],
244
+ onPress: () => handleDiffModeChange("split"),
245
+ children: /*#__PURE__*/_jsx(Text, {
246
+ style: [styles.diffViewerTabText, diffViewerTab === "split" && styles.diffViewerTabTextActive],
247
+ children: "SPLIT VIEW"
248
+ })
249
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
250
+ style: [styles.diffViewerTab, diffViewerTab === "tree" && styles.diffViewerTabActive],
251
+ onPress: () => handleDiffModeChange("tree"),
252
+ children: /*#__PURE__*/_jsx(Text, {
253
+ style: [styles.diffViewerTabText, diffViewerTab === "tree" && styles.diffViewerTabTextActive],
254
+ children: "TREE VIEW"
255
+ })
256
+ })]
257
+ }), totalEvents > 0 && /*#__PURE__*/_jsxs(View, {
258
+ style: styles.compareBar,
259
+ children: [/*#__PURE__*/_jsxs(View, {
260
+ style: styles.compareSide,
261
+ children: [/*#__PURE__*/_jsxs(View, {
262
+ style: styles.compareLabelRow,
263
+ children: [/*#__PURE__*/_jsx(Text, {
264
+ style: [styles.compareLabel, {
265
+ color: macOSColors.semantic.debug
266
+ }],
267
+ children: "PREV"
268
+ }), /*#__PURE__*/_jsx(View, {
269
+ style: [styles.compareActionBadge, {
270
+ backgroundColor: `${getActionColor(leftEvent.action)}20`
271
+ }],
272
+ children: /*#__PURE__*/_jsx(Text, {
273
+ style: [styles.compareActionText, {
274
+ color: getActionColor(leftEvent.action)
275
+ }],
276
+ children: translateStorageAction(leftEvent.action)
277
+ })
278
+ })]
279
+ }), /*#__PURE__*/_jsxs(View, {
280
+ style: styles.compareControls,
281
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
282
+ onPress: () => bumpLeft(-1),
283
+ disabled: leftIndex <= 0,
284
+ style: [styles.compareBtn, leftIndex <= 0 && styles.compareBtnDisabled],
285
+ children: /*#__PURE__*/_jsx(ChevronLeft, {
286
+ size: 14,
287
+ color: leftIndex <= 0 ? macOSColors.text.muted : macOSColors.text.secondary
288
+ })
289
+ }), /*#__PURE__*/_jsxs(TouchableOpacity, {
290
+ style: styles.compareMeta,
291
+ onPress: () => setIsLeftPickerOpen(true),
292
+ activeOpacity: 0.8,
293
+ children: [/*#__PURE__*/_jsxs(Text, {
294
+ style: styles.compareIndex,
295
+ children: ["#", leftIndex + 1, " / ", totalEvents]
296
+ }), /*#__PURE__*/_jsx(Text, {
297
+ style: styles.compareTime,
298
+ children: formatTimeWithMs(leftEvent.timestamp)
299
+ }), /*#__PURE__*/_jsxs(Text, {
300
+ style: styles.compareRelative,
301
+ children: ["(", formatRelativeTime(leftEvent.timestamp), ")"]
302
+ })]
303
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
304
+ onPress: () => bumpLeft(1),
305
+ disabled: leftIndex >= rightIndex - 1,
306
+ style: [styles.compareBtn, leftIndex >= rightIndex - 1 && styles.compareBtnDisabled],
307
+ children: /*#__PURE__*/_jsx(ChevronRight, {
308
+ size: 14,
309
+ color: leftIndex >= rightIndex - 1 ? macOSColors.text.muted : macOSColors.text.secondary
310
+ })
311
+ })]
312
+ })]
313
+ }), /*#__PURE__*/_jsx(View, {
314
+ style: styles.compareDivider
315
+ }), /*#__PURE__*/_jsxs(View, {
316
+ style: styles.compareSide,
317
+ children: [/*#__PURE__*/_jsxs(View, {
318
+ style: styles.compareLabelRow,
319
+ children: [/*#__PURE__*/_jsx(Text, {
320
+ style: [styles.compareLabel, {
321
+ color: macOSColors.semantic.success
322
+ }],
323
+ children: "CUR"
324
+ }), /*#__PURE__*/_jsx(View, {
325
+ style: [styles.compareActionBadge, {
326
+ backgroundColor: `${getActionColor(rightEvent.action)}20`
327
+ }],
328
+ children: /*#__PURE__*/_jsx(Text, {
329
+ style: [styles.compareActionText, {
330
+ color: getActionColor(rightEvent.action)
331
+ }],
332
+ children: translateStorageAction(rightEvent.action)
333
+ })
334
+ })]
335
+ }), /*#__PURE__*/_jsxs(View, {
336
+ style: styles.compareControls,
337
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
338
+ onPress: () => bumpRight(-1),
339
+ disabled: rightIndex <= leftIndex + 1,
340
+ style: [styles.compareBtn, rightIndex <= leftIndex + 1 && styles.compareBtnDisabled],
341
+ children: /*#__PURE__*/_jsx(ChevronLeft, {
342
+ size: 14,
343
+ color: rightIndex <= leftIndex + 1 ? macOSColors.text.muted : macOSColors.text.secondary
344
+ })
345
+ }), /*#__PURE__*/_jsxs(TouchableOpacity, {
346
+ style: styles.compareMeta,
347
+ onPress: () => setIsRightPickerOpen(true),
348
+ activeOpacity: 0.8,
349
+ children: [/*#__PURE__*/_jsxs(Text, {
350
+ style: styles.compareIndex,
351
+ children: ["#", rightIndex + 1, " / ", totalEvents]
352
+ }), /*#__PURE__*/_jsx(Text, {
353
+ style: styles.compareTime,
354
+ children: formatTimeWithMs(rightEvent.timestamp)
355
+ }), /*#__PURE__*/_jsxs(Text, {
356
+ style: styles.compareRelative,
357
+ children: ["(", formatRelativeTime(rightEvent.timestamp), ")"]
358
+ })]
359
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
360
+ onPress: () => bumpRight(1),
361
+ disabled: rightIndex >= totalEvents - 1,
362
+ style: [styles.compareBtn, rightIndex >= totalEvents - 1 && styles.compareBtnDisabled],
363
+ children: /*#__PURE__*/_jsx(ChevronRight, {
364
+ size: 14,
365
+ color: rightIndex >= totalEvents - 1 ? macOSColors.text.muted : macOSColors.text.secondary
366
+ })
367
+ })]
368
+ })]
369
+ })]
370
+ }), diffViewerTab === "split" && /*#__PURE__*/_jsx(ScrollView, {
371
+ style: {
372
+ flex: 1
373
+ },
374
+ showsVerticalScrollIndicator: true,
375
+ children: /*#__PURE__*/_jsx(ThemedSplitView, {
376
+ oldValue: parseValue(previousValue),
377
+ newValue: parseValue(currentValue),
378
+ differences: [],
379
+ theme: diffThemes.devToolsDefault,
380
+ options: {
381
+ hideLineNumbers: false,
382
+ disableWordDiff: false,
383
+ showDiffOnly: false,
384
+ compareMethod: "words",
385
+ contextLines: 3,
386
+ lineOffset: 0
387
+ },
388
+ showThemeName: false
389
+ })
390
+ }), diffViewerTab === "tree" && /*#__PURE__*/_jsx(TreeDiffViewer, {
391
+ oldValue: parseValue(previousValue),
392
+ newValue: parseValue(currentValue)
393
+ })]
394
+ });
395
+ };
396
+ return /*#__PURE__*/_jsxs(_Fragment, {
397
+ children: [/*#__PURE__*/_jsxs(View, {
398
+ style: [styles.contentOnly, {
399
+ flex: 1,
400
+ paddingBottom: !disableInternalFooter && totalEvents > 1 ? 80 : 0
401
+ }],
402
+ children: [/*#__PURE__*/_jsxs(View, {
403
+ style: styles.viewToggleContainer,
404
+ children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
405
+ style: [styles.viewToggleCard, internalActiveView === "current" && styles.viewToggleCardActive],
406
+ onPress: () => handleViewChange("current"),
407
+ activeOpacity: 0.8,
408
+ children: [/*#__PURE__*/_jsxs(View, {
409
+ style: styles.viewToggleContent,
410
+ children: [/*#__PURE__*/_jsx(Database, {
411
+ size: 16,
412
+ color: internalActiveView === "current" ? macOSColors.semantic.info : macOSColors.text.secondary
413
+ }), /*#__PURE__*/_jsx(Text, {
414
+ style: [styles.viewToggleLabel, internalActiveView === "current" && styles.viewToggleLabelActive],
415
+ children: "CURRENT VALUE"
416
+ })]
417
+ }), /*#__PURE__*/_jsx(Text, {
418
+ style: [styles.viewToggleDescription, internalActiveView === "current" && {
419
+ color: macOSColors.text.primary
420
+ }],
421
+ children: "View the current stored value"
422
+ })]
423
+ }), /*#__PURE__*/_jsxs(TouchableOpacity, {
424
+ style: [styles.viewToggleCard, internalActiveView === "diff" && styles.viewToggleCardActive],
425
+ onPress: () => handleViewChange("diff"),
426
+ activeOpacity: 0.8,
427
+ children: [/*#__PURE__*/_jsxs(View, {
428
+ style: styles.viewToggleContent,
429
+ children: [/*#__PURE__*/_jsx(GitBranch, {
430
+ size: 16,
431
+ color: internalActiveView === "diff" ? macOSColors.semantic.success : macOSColors.text.secondary
432
+ }), /*#__PURE__*/_jsx(Text, {
433
+ style: [styles.viewToggleLabel, internalActiveView === "diff" && styles.viewToggleLabelActive],
434
+ children: "DIFF VIEW"
435
+ })]
436
+ }), /*#__PURE__*/_jsx(Text, {
437
+ style: [styles.viewToggleDescription, internalActiveView === "diff" && {
438
+ color: macOSColors.text.primary
439
+ }],
440
+ children: "Compare changes between versions"
441
+ })]
442
+ })]
443
+ }), lockedEventCount > 0 && /*#__PURE__*/_jsxs(View, {
444
+ style: styles.lockedEventsBannerGlobal,
445
+ children: [/*#__PURE__*/_jsx(Lock, {
446
+ size: 14,
447
+ color: macOSColors.semantic.warning
448
+ }), /*#__PURE__*/_jsxs(Text, {
449
+ style: styles.lockedEventsBannerText,
450
+ children: [lockedEventCount, " older ", lockedEventCount === 1 ? 'event' : 'events', " locked"]
451
+ }), /*#__PURE__*/_jsx(Text, {
452
+ style: styles.lockedEventsBannerSubtext,
453
+ children: "Upgrade to Pro for full history"
454
+ })]
455
+ }), internalActiveView === "current" && renderCurrentValue(), internalActiveView === "diff" && renderDiff()]
456
+ }), (isLeftPickerOpen || isRightPickerOpen) && /*#__PURE__*/_jsxs(View, {
457
+ style: styles.pickerOverlay,
458
+ children: [/*#__PURE__*/_jsx(TouchableOpacity, {
459
+ style: styles.pickerBackdrop,
460
+ activeOpacity: 1,
461
+ onPress: () => {
462
+ setIsLeftPickerOpen(false);
463
+ setIsRightPickerOpen(false);
464
+ }
465
+ }), /*#__PURE__*/_jsxs(View, {
466
+ style: [styles.pickerCard, isLeftPickerOpen && styles.pickerCardLeft, isRightPickerOpen && styles.pickerCardRight],
467
+ children: [/*#__PURE__*/_jsxs(View, {
468
+ style: styles.pickerHeader,
469
+ children: [/*#__PURE__*/_jsxs(Text, {
470
+ style: [styles.pickerTitle, isLeftPickerOpen && styles.pickerTitleLeft, isRightPickerOpen && styles.pickerTitleRight],
471
+ children: ["Select ", isLeftPickerOpen ? "PREV" : "CUR", " Event"]
472
+ }), /*#__PURE__*/_jsx(TouchableOpacity, {
473
+ onPress: () => {
474
+ setIsLeftPickerOpen(false);
475
+ setIsRightPickerOpen(false);
476
+ },
477
+ style: styles.pickerClose,
478
+ accessibilityLabel: "Close event picker",
479
+ children: /*#__PURE__*/_jsx(X, {
480
+ size: 16,
481
+ color: macOSColors.text.secondary
482
+ })
483
+ })]
484
+ }), /*#__PURE__*/_jsx(View, {
485
+ style: styles.pickerDivider
486
+ }), /*#__PURE__*/_jsx(ScrollView, {
487
+ style: styles.pickerScroll,
488
+ contentContainerStyle: styles.pickerList,
489
+ showsVerticalScrollIndicator: true,
490
+ nestedScrollEnabled: true,
491
+ children: navigationItems.slice(0, maxAccessibleEventIndex + 1).map((item, idx) => {
492
+ const disabled = isLeftPickerOpen ? idx >= rightIndex : idx <= leftIndex;
493
+ const isSelected = isLeftPickerOpen ? idx === leftIndex : idx === rightIndex;
494
+ return /*#__PURE__*/_jsxs(TouchableOpacity, {
495
+ disabled: disabled,
496
+ onPress: () => {
497
+ if (isLeftPickerOpen) {
498
+ setLeftIndex(Math.min(idx, rightIndex - 1));
499
+ setIsLeftPickerOpen(false);
500
+ } else {
501
+ setRightIndex(Math.max(idx, leftIndex + 1));
502
+ setIsRightPickerOpen(false);
503
+ }
504
+ },
505
+ style: [styles.pickerItem, isSelected && styles.pickerItemSelected, isSelected && isLeftPickerOpen && styles.pickerItemSelectedLeft, isSelected && isRightPickerOpen && styles.pickerItemSelectedRight, disabled && styles.pickerItemDisabled],
506
+ children: [/*#__PURE__*/_jsxs(Text, {
507
+ style: styles.pickerIndex,
508
+ children: ["#", idx + 1]
509
+ }), /*#__PURE__*/_jsx(Text, {
510
+ style: styles.pickerTime,
511
+ children: formatTimeWithMs(item.timestamp)
512
+ }), /*#__PURE__*/_jsxs(Text, {
513
+ style: styles.pickerRelative,
514
+ children: ["(", formatRelativeTime(item.timestamp), ")"]
515
+ }), (() => {
516
+ const targetOld = isLeftPickerOpen ? item : navigationItems[leftIndex];
517
+ const targetNew = isLeftPickerOpen ? navigationItems[rightIndex] : item;
518
+ const oldVal = parseValue(targetOld.data?.value);
519
+ const newVal = parseValue(targetNew.data?.value);
520
+ const diffs = computeLineDiff(oldVal, newVal, {
521
+ compareMethod: "words",
522
+ disableWordDiff: false,
523
+ showDiffOnly: false,
524
+ contextLines: 0
525
+ });
526
+ const added = diffs.filter(d => d.type === DiffType.ADDED).length;
527
+ const removed = diffs.filter(d => d.type === DiffType.REMOVED).length;
528
+ const modified = diffs.filter(d => d.type === DiffType.MODIFIED).length;
529
+ return /*#__PURE__*/_jsxs(View, {
530
+ style: styles.pickerCounts,
531
+ children: [/*#__PURE__*/_jsxs(Text, {
532
+ style: [styles.pickerCountText, {
533
+ color: diffThemes.devToolsDefault.summaryAddedText
534
+ }],
535
+ children: ["+", added]
536
+ }), /*#__PURE__*/_jsxs(Text, {
537
+ style: [styles.pickerCountText, {
538
+ color: diffThemes.devToolsDefault.summaryRemovedText
539
+ }],
540
+ children: ["-", removed]
541
+ }), /*#__PURE__*/_jsxs(Text, {
542
+ style: [styles.pickerCountText, {
543
+ color: diffThemes.devToolsDefault.summaryModifiedText
544
+ }],
545
+ children: ["~", modified]
546
+ })]
547
+ });
548
+ })()]
549
+ }, idx);
550
+ })
551
+ })]
552
+ })]
553
+ }), !disableInternalFooter && /*#__PURE__*/_jsx(EventStepperFooter, {
554
+ currentIndex: selectedEventIndex,
555
+ totalItems: totalEvents,
556
+ onPrevious: () => onEventIndexChange(Math.max(0, selectedEventIndex - 1)),
557
+ onNext: () => onEventIndexChange(Math.min(totalEvents - 1, selectedEventIndex + 1)),
558
+ itemLabel: "Event",
559
+ subtitle: formatRelativeTime(navigationItems[selectedEventIndex]?.timestamp),
560
+ absolute: true
561
+ })]
562
+ });
563
+ }
564
+
565
+ // External footer component to be rendered by the modal outside the ScrollView
566
+ export function StorageEventDetailFooter({
567
+ conversation,
568
+ selectedEventIndex = 0,
569
+ onEventIndexChange = () => {}
570
+ }) {
571
+ // Check Pro status internally
572
+ const useIsPro = getUseIsPro();
573
+ const isPro = useIsPro();
574
+ const navigationItems = conversation.events.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
575
+ const totalEvents = navigationItems.length;
576
+
577
+ // Free tier limit for navigation
578
+ const maxAccessibleIndex = isPro ? totalEvents - 1 : Math.min(FREE_TIER_EVENT_HISTORY_LIMIT - 1, totalEvents - 1);
579
+ const lockedCount = isPro ? 0 : Math.max(0, totalEvents - FREE_TIER_EVENT_HISTORY_LIMIT);
580
+
581
+ // Calculate display total (accessible events for free users)
582
+ const displayTotal = isPro ? totalEvents : Math.min(totalEvents, FREE_TIER_EVENT_HISTORY_LIMIT);
583
+ return /*#__PURE__*/_jsx(EventStepperFooter, {
584
+ currentIndex: selectedEventIndex,
585
+ totalItems: displayTotal,
586
+ onPrevious: () => onEventIndexChange(Math.max(0, selectedEventIndex - 1)),
587
+ onNext: () => onEventIndexChange(Math.min(maxAccessibleIndex, selectedEventIndex + 1)),
588
+ itemLabel: "Event",
589
+ subtitle: lockedCount > 0 ? `${formatRelativeTime(navigationItems[selectedEventIndex]?.timestamp)} • ${lockedCount} locked` : formatRelativeTime(navigationItems[selectedEventIndex]?.timestamp)
590
+ });
591
+ }
592
+ const styles = StyleSheet.create({
593
+ contentOnly: {
594
+ flex: 1,
595
+ backgroundColor: macOSColors.background.base
596
+ },
597
+ fullPageSection: {
598
+ flex: 1,
599
+ paddingHorizontal: 14,
600
+ paddingVertical: 10
601
+ },
602
+ emptyState: {
603
+ flex: 1,
604
+ alignItems: "center",
605
+ justifyContent: "center",
606
+ paddingVertical: 48
607
+ },
608
+ emptyText: {
609
+ marginTop: 12,
610
+ fontSize: 14,
611
+ color: macOSColors.text.secondary,
612
+ fontFamily: "monospace"
613
+ },
614
+ card: {
615
+ backgroundColor: macOSColors.background.card,
616
+ borderRadius: 14,
617
+ padding: 14,
618
+ borderWidth: 1,
619
+ borderColor: macOSColors.border.default
620
+ },
621
+ valueContent: {
622
+ marginTop: 4
623
+ },
624
+ valueHeader: {
625
+ flexDirection: "row",
626
+ alignItems: "center",
627
+ justifyContent: "space-between",
628
+ marginBottom: 4
629
+ },
630
+ valueLabel: {
631
+ fontSize: 10,
632
+ color: macOSColors.text.secondary,
633
+ fontFamily: "monospace",
634
+ letterSpacing: 0.5,
635
+ fontWeight: "600",
636
+ textTransform: "uppercase"
637
+ },
638
+ valueHeaderBadges: {
639
+ flexDirection: "row",
640
+ alignItems: "center",
641
+ gap: 6
642
+ },
643
+ actionBadge: {
644
+ paddingHorizontal: 8,
645
+ paddingVertical: 2,
646
+ borderRadius: 4,
647
+ borderWidth: 1,
648
+ borderColor: "transparent"
649
+ },
650
+ actionText: {
651
+ fontSize: 9,
652
+ fontWeight: "700",
653
+ fontFamily: "monospace",
654
+ letterSpacing: 0.3
655
+ },
656
+ typeBadge: {
657
+ paddingHorizontal: 8,
658
+ paddingVertical: 2,
659
+ borderRadius: 4,
660
+ backgroundColor: macOSColors.background.input
661
+ },
662
+ typeText: {
663
+ fontSize: 9,
664
+ fontWeight: "600",
665
+ color: macOSColors.text.muted,
666
+ fontFamily: "monospace"
667
+ },
668
+ valueBox: {
669
+ backgroundColor: macOSColors.background.card,
670
+ borderRadius: 6,
671
+ borderWidth: 1,
672
+ borderColor: macOSColors.border.input,
673
+ padding: 8
674
+ },
675
+ valueText: {
676
+ fontSize: 12,
677
+ color: macOSColors.text.primary,
678
+ fontFamily: "monospace",
679
+ lineHeight: 18
680
+ },
681
+ // Compare picker styles
682
+ compareBar: {
683
+ flexDirection: "row",
684
+ alignItems: "center",
685
+ justifyContent: "space-between",
686
+ backgroundColor: macOSColors.background.card,
687
+ borderWidth: 1,
688
+ borderColor: macOSColors.border.default,
689
+ borderRadius: 6,
690
+ paddingHorizontal: 8,
691
+ paddingVertical: 6,
692
+ marginBottom: 8,
693
+ gap: 8
694
+ },
695
+ compareSide: {
696
+ flex: 1
697
+ },
698
+ compareLabelRow: {
699
+ flexDirection: "row",
700
+ alignItems: "center",
701
+ gap: 6,
702
+ marginBottom: 2
703
+ },
704
+ compareLabel: {
705
+ fontSize: 10,
706
+ fontFamily: "monospace",
707
+ fontWeight: "700",
708
+ letterSpacing: 0.5,
709
+ textTransform: "uppercase"
710
+ },
711
+ compareActionBadge: {
712
+ paddingHorizontal: 6,
713
+ paddingVertical: 1,
714
+ borderRadius: 3
715
+ },
716
+ compareActionText: {
717
+ fontSize: 8,
718
+ fontWeight: "700",
719
+ fontFamily: "monospace",
720
+ letterSpacing: 0.3
721
+ },
722
+ compareControls: {
723
+ flexDirection: "row",
724
+ alignItems: "center",
725
+ gap: 6
726
+ },
727
+ compareBtn: {
728
+ width: 26,
729
+ height: 26,
730
+ borderRadius: 6,
731
+ backgroundColor: macOSColors.background.card,
732
+ borderWidth: 1,
733
+ borderColor: macOSColors.border.default,
734
+ alignItems: "center",
735
+ justifyContent: "center"
736
+ },
737
+ compareBtnDisabled: {
738
+ opacity: 0.4
739
+ },
740
+ compareMeta: {
741
+ flex: 1
742
+ },
743
+ compareTime: {
744
+ fontSize: 11,
745
+ color: macOSColors.text.primary,
746
+ fontFamily: "monospace"
747
+ },
748
+ compareIndex: {
749
+ fontSize: 10,
750
+ color: macOSColors.text.secondary,
751
+ fontFamily: "monospace"
752
+ },
753
+ compareRelative: {
754
+ fontSize: 10,
755
+ color: macOSColors.text.secondary,
756
+ fontFamily: "monospace"
757
+ },
758
+ compareDivider: {
759
+ width: 1,
760
+ height: 34,
761
+ backgroundColor: macOSColors.background.input
762
+ },
763
+ pickerOverlay: {
764
+ ...StyleSheet.absoluteFillObject,
765
+ zIndex: 20,
766
+ justifyContent: "center",
767
+ alignItems: "center"
768
+ },
769
+ pickerBackdrop: {
770
+ ...StyleSheet.absoluteFillObject,
771
+ backgroundColor: "rgba(0,0,0,0.65)"
772
+ },
773
+ pickerCard: {
774
+ width: "86%",
775
+ maxHeight: 320,
776
+ backgroundColor: macOSColors.background.card,
777
+ borderRadius: 16,
778
+ borderWidth: 2,
779
+ padding: 16,
780
+ shadowOffset: {
781
+ width: 0,
782
+ height: 0
783
+ },
784
+ shadowOpacity: 0.5,
785
+ shadowRadius: 40,
786
+ elevation: 15
787
+ },
788
+ pickerCardLeft: {
789
+ borderColor: macOSColors.semantic.debug,
790
+ shadowColor: macOSColors.semantic.debug
791
+ },
792
+ pickerCardRight: {
793
+ borderColor: macOSColors.semantic.success,
794
+ shadowColor: macOSColors.semantic.success
795
+ },
796
+ pickerHeader: {
797
+ flexDirection: "row",
798
+ alignItems: "center",
799
+ justifyContent: "space-between"
800
+ },
801
+ pickerClose: {
802
+ padding: 6,
803
+ borderRadius: 6,
804
+ backgroundColor: macOSColors.background.card,
805
+ borderWidth: 1,
806
+ borderColor: macOSColors.border.default
807
+ },
808
+ pickerDivider: {
809
+ height: 1,
810
+ backgroundColor: macOSColors.background.input,
811
+ marginVertical: 8
812
+ },
813
+ pickerScroll: {
814
+ maxHeight: 260
815
+ },
816
+ pickerTitle: {
817
+ fontSize: 13,
818
+ fontWeight: "700",
819
+ fontFamily: "monospace",
820
+ textTransform: "uppercase",
821
+ marginBottom: 8,
822
+ letterSpacing: 0.6
823
+ },
824
+ pickerTitleLeft: {
825
+ color: macOSColors.semantic.debug
826
+ },
827
+ pickerTitleRight: {
828
+ color: macOSColors.semantic.success
829
+ },
830
+ pickerList: {
831
+ gap: 4
832
+ },
833
+ pickerItem: {
834
+ paddingVertical: 10,
835
+ paddingHorizontal: 12,
836
+ borderRadius: 10,
837
+ backgroundColor: macOSColors.background.base,
838
+ borderWidth: 1,
839
+ borderColor: macOSColors.border.default,
840
+ flexDirection: "row",
841
+ alignItems: "center",
842
+ gap: 8,
843
+ marginBottom: 6
844
+ },
845
+ pickerItemSelected: {
846
+ borderWidth: 1.5,
847
+ shadowOffset: {
848
+ width: 0,
849
+ height: 2
850
+ },
851
+ shadowOpacity: 0.25,
852
+ shadowRadius: 12,
853
+ elevation: 4
854
+ },
855
+ pickerItemSelectedLeft: {
856
+ backgroundColor: macOSColors.semantic.debug + "1A",
857
+ borderColor: macOSColors.semantic.debug,
858
+ shadowColor: macOSColors.semantic.debug
859
+ },
860
+ pickerItemSelectedRight: {
861
+ backgroundColor: macOSColors.semantic.successBackground + "30",
862
+ borderColor: macOSColors.semantic.success,
863
+ shadowColor: macOSColors.semantic.success
864
+ },
865
+ pickerItemDisabled: {
866
+ opacity: 0.4
867
+ },
868
+ pickerIndex: {
869
+ fontSize: 10,
870
+ color: macOSColors.text.secondary,
871
+ fontFamily: "monospace",
872
+ width: 40
873
+ },
874
+ pickerTime: {
875
+ fontSize: 11,
876
+ color: macOSColors.text.primary,
877
+ fontFamily: "monospace",
878
+ flex: 1
879
+ },
880
+ pickerRelative: {
881
+ fontSize: 10,
882
+ color: macOSColors.text.secondary,
883
+ fontFamily: "monospace"
884
+ },
885
+ pickerCounts: {
886
+ flexDirection: "row",
887
+ alignItems: "center",
888
+ gap: 8,
889
+ marginLeft: "auto"
890
+ },
891
+ pickerCountText: {
892
+ fontSize: 10,
893
+ fontFamily: "monospace",
894
+ fontWeight: "700"
895
+ },
896
+ diffViewerTabs: {
897
+ flexDirection: "row",
898
+ alignItems: "center",
899
+ justifyContent: "space-around",
900
+ backgroundColor: macOSColors.background.card,
901
+ borderWidth: 1,
902
+ borderColor: macOSColors.border.default,
903
+ borderRadius: 6,
904
+ paddingHorizontal: 4,
905
+ paddingVertical: 4,
906
+ marginBottom: 8,
907
+ gap: 4
908
+ },
909
+ diffViewerTab: {
910
+ flex: 1,
911
+ paddingVertical: 8,
912
+ paddingHorizontal: 12,
913
+ borderRadius: 4,
914
+ alignItems: "center",
915
+ backgroundColor: "transparent"
916
+ },
917
+ diffViewerTabActive: {
918
+ backgroundColor: macOSColors.semantic.infoBackground,
919
+ borderWidth: 1,
920
+ borderColor: macOSColors.semantic.info + "40"
921
+ },
922
+ diffViewerTabText: {
923
+ fontSize: 11,
924
+ fontFamily: "monospace",
925
+ fontWeight: "600",
926
+ color: macOSColors.text.secondary,
927
+ letterSpacing: 0.5
928
+ },
929
+ diffViewerTabTextActive: {
930
+ color: macOSColors.text.primary
931
+ },
932
+ contentCard: {
933
+ backgroundColor: macOSColors.background.card,
934
+ borderRadius: 14,
935
+ padding: 14,
936
+ borderWidth: 1,
937
+ borderColor: macOSColors.border.default,
938
+ shadowColor: macOSColors.semantic.info,
939
+ shadowOffset: {
940
+ width: 0,
941
+ height: 2
942
+ },
943
+ shadowOpacity: 0.04,
944
+ shadowRadius: 16,
945
+ elevation: 2
946
+ },
947
+ // View Toggle Cards
948
+ viewToggleContainer: {
949
+ flexDirection: "row",
950
+ gap: 12,
951
+ padding: 14,
952
+ backgroundColor: macOSColors.background.base
953
+ },
954
+ viewToggleCard: {
955
+ flex: 1,
956
+ backgroundColor: macOSColors.background.card,
957
+ borderRadius: 14,
958
+ borderWidth: 1,
959
+ borderColor: macOSColors.border.default,
960
+ padding: 14,
961
+ gap: 8
962
+ },
963
+ viewToggleCardActive: {
964
+ borderWidth: 1.5,
965
+ borderColor: macOSColors.semantic.info,
966
+ backgroundColor: macOSColors.semantic.infoBackground + "30",
967
+ shadowColor: macOSColors.semantic.info,
968
+ shadowOffset: {
969
+ width: 0,
970
+ height: 2
971
+ },
972
+ shadowOpacity: 0.1,
973
+ shadowRadius: 8,
974
+ elevation: 3
975
+ },
976
+ viewToggleContent: {
977
+ flexDirection: "row",
978
+ alignItems: "center",
979
+ gap: 8
980
+ },
981
+ viewToggleLabel: {
982
+ fontSize: 12,
983
+ fontWeight: "700",
984
+ letterSpacing: 0.5,
985
+ color: macOSColors.text.secondary,
986
+ textTransform: "uppercase"
987
+ },
988
+ viewToggleLabelActive: {
989
+ color: macOSColors.text.primary
990
+ },
991
+ viewToggleDescription: {
992
+ fontSize: 11,
993
+ color: macOSColors.text.muted,
994
+ lineHeight: 16
995
+ },
996
+ lockedEventsBannerGlobal: {
997
+ flexDirection: "row",
998
+ alignItems: "center",
999
+ gap: 8,
1000
+ backgroundColor: macOSColors.semantic.warning + "15",
1001
+ borderWidth: 1,
1002
+ borderColor: macOSColors.semantic.warning + "30",
1003
+ borderRadius: 10,
1004
+ paddingVertical: 12,
1005
+ paddingHorizontal: 14,
1006
+ marginHorizontal: 14,
1007
+ marginBottom: 4
1008
+ },
1009
+ lockedEventsBannerText: {
1010
+ fontSize: 12,
1011
+ fontWeight: "600",
1012
+ color: macOSColors.semantic.warning,
1013
+ fontFamily: "monospace"
1014
+ },
1015
+ lockedEventsBannerSubtext: {
1016
+ fontSize: 11,
1017
+ color: macOSColors.text.secondary,
1018
+ marginLeft: "auto"
1019
+ }
1020
+ });