@buoy-gg/core 7.0.40 → 7.0.42

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 (269) hide show
  1. package/README.md +14 -85
  2. package/bin/buoy.js +20 -347
  3. package/lib/commonjs/Buoy.js +1 -107
  4. package/lib/commonjs/browserRegister.js +1 -0
  5. package/lib/commonjs/browserRegister.server.js +1 -0
  6. package/lib/commonjs/earlyHookScript.js +1 -0
  7. package/lib/commonjs/earlyNetwork.js +1 -0
  8. package/lib/commonjs/floatingMenu/AppHost.js +1 -460
  9. package/lib/commonjs/floatingMenu/AppHost.web.js +1 -364
  10. package/lib/commonjs/floatingMenu/AppHostLogic.js +1 -50
  11. package/lib/commonjs/floatingMenu/AppIcon.js +1 -91
  12. package/lib/commonjs/floatingMenu/AppIcon.web.js +1 -53
  13. package/lib/commonjs/floatingMenu/BrowserToolRuntime.js +1 -0
  14. package/lib/commonjs/floatingMenu/DefaultConfigContext.js +1 -45
  15. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +1 -1119
  16. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.shared.js +1 -0
  17. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +1 -1048
  18. package/lib/commonjs/floatingMenu/DevToolsVisibilityContext.js +1 -49
  19. package/lib/commonjs/floatingMenu/FloatingDevTools.js +1 -554
  20. package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +1 -401
  21. package/lib/commonjs/floatingMenu/FloatingMenu.js +1 -371
  22. package/lib/commonjs/floatingMenu/MinimizedToolsContext.js +1 -274
  23. package/lib/commonjs/floatingMenu/MinimizedToolsStack.js +1 -288
  24. package/lib/commonjs/floatingMenu/MinimizedToolsStack.web.js +1 -371
  25. package/lib/commonjs/floatingMenu/ToggleStateManager.js +1 -36
  26. package/lib/commonjs/floatingMenu/ToolHost.js +1 -281
  27. package/lib/commonjs/floatingMenu/ToolOpenerBridge.js +1 -41
  28. package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +1 -461
  29. package/lib/commonjs/floatingMenu/autoExternalSync.js +1 -434
  30. package/lib/commonjs/floatingMenu/defaultConfig.js +1 -167
  31. package/lib/commonjs/floatingMenu/deviceIdentity.js +1 -173
  32. package/lib/commonjs/floatingMenu/dial/DialDevTools.js +1 -904
  33. package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +1 -821
  34. package/lib/commonjs/floatingMenu/dial/DialHyperspace.js +1 -177
  35. package/lib/commonjs/floatingMenu/dial/DialIcon.js +1 -302
  36. package/lib/commonjs/floatingMenu/dial/DialPagination.js +1 -165
  37. package/lib/commonjs/floatingMenu/dial/DialSnow.js +1 -92
  38. package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.js +1 -246
  39. package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.web.js +2 -147
  40. package/lib/commonjs/floatingMenu/dial/dialUsageStore.js +1 -93
  41. package/lib/commonjs/floatingMenu/dial/onboardingConstants.js +1 -42
  42. package/lib/commonjs/floatingMenu/dial/onboardingConstants.web.js +1 -42
  43. package/lib/commonjs/floatingMenu/externalSyncGate.js +1 -49
  44. package/lib/commonjs/floatingMenu/floatingTools.js +1 -42
  45. package/lib/commonjs/floatingMenu/floatingTools.web.js +1 -30
  46. package/lib/commonjs/floatingMenu/optionalRequire.js +1 -37
  47. package/lib/commonjs/floatingMenu/settingsBus.js +1 -23
  48. package/lib/commonjs/floatingMenu/sync/appSyncAdapter.js +1 -115
  49. package/lib/commonjs/floatingMenu/types.js +1 -5
  50. package/lib/commonjs/floatingMenu/useDesktopSyncStatus.js +1 -28
  51. package/lib/commonjs/floatingMenu/useDesktopSyncStatus.web.js +1 -0
  52. package/lib/commonjs/index.js +1 -291
  53. package/lib/commonjs/index.web.js +1 -150
  54. package/lib/commonjs/reactDevtoolsTypes.js +1 -0
  55. package/lib/commonjs/releaseOptIn.js +1 -0
  56. package/lib/commonjs/telemetry/installPing.js +1 -131
  57. package/lib/commonjs/toolkit.js +1 -584
  58. package/lib/commonjs/toolkitComponents.js +1 -241
  59. package/lib/commonjs/utils/autoDiscoverPresets.web.js +1 -219
  60. package/lib/commonjs/utils/createWebTool.js +1 -0
  61. package/lib/commonjs/utils/createWebTools.js +1 -0
  62. package/lib/commonjs/version.js +1 -18
  63. package/lib/module/Buoy.js +1 -102
  64. package/lib/module/browserRegister.js +1 -0
  65. package/lib/module/browserRegister.server.js +1 -0
  66. package/lib/module/earlyHookScript.js +1 -0
  67. package/lib/module/earlyNetwork.js +1 -0
  68. package/lib/module/floatingMenu/AppHost.js +1 -452
  69. package/lib/module/floatingMenu/AppHost.web.js +1 -356
  70. package/lib/module/floatingMenu/AppHostLogic.js +1 -45
  71. package/lib/module/floatingMenu/AppIcon.js +1 -84
  72. package/lib/module/floatingMenu/AppIcon.web.js +1 -47
  73. package/lib/module/floatingMenu/BrowserToolRuntime.js +1 -0
  74. package/lib/module/floatingMenu/DefaultConfigContext.js +1 -39
  75. package/lib/module/floatingMenu/DevToolsSettingsModal.js +1 -1115
  76. package/lib/module/floatingMenu/DevToolsSettingsModal.shared.js +1 -0
  77. package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +1 -1055
  78. package/lib/module/floatingMenu/DevToolsVisibilityContext.js +1 -44
  79. package/lib/module/floatingMenu/FloatingDevTools.js +1 -551
  80. package/lib/module/floatingMenu/FloatingDevTools.web.js +1 -399
  81. package/lib/module/floatingMenu/FloatingMenu.js +1 -366
  82. package/lib/module/floatingMenu/MinimizedToolsContext.js +1 -266
  83. package/lib/module/floatingMenu/MinimizedToolsStack.js +1 -285
  84. package/lib/module/floatingMenu/MinimizedToolsStack.web.js +1 -368
  85. package/lib/module/floatingMenu/ToggleStateManager.js +1 -32
  86. package/lib/module/floatingMenu/ToolHost.js +1 -273
  87. package/lib/module/floatingMenu/ToolOpenerBridge.js +1 -37
  88. package/lib/module/floatingMenu/autoDiscoverPresets.js +1 -457
  89. package/lib/module/floatingMenu/autoExternalSync.js +1 -427
  90. package/lib/module/floatingMenu/defaultConfig.js +1 -158
  91. package/lib/module/floatingMenu/deviceIdentity.js +1 -163
  92. package/lib/module/floatingMenu/dial/DialDevTools.js +1 -900
  93. package/lib/module/floatingMenu/dial/DialDevTools.web.js +1 -818
  94. package/lib/module/floatingMenu/dial/DialHyperspace.js +1 -173
  95. package/lib/module/floatingMenu/dial/DialIcon.js +1 -299
  96. package/lib/module/floatingMenu/dial/DialPagination.js +1 -160
  97. package/lib/module/floatingMenu/dial/DialSnow.js +1 -90
  98. package/lib/module/floatingMenu/dial/OnboardingTooltip.js +1 -240
  99. package/lib/module/floatingMenu/dial/OnboardingTooltip.web.js +2 -142
  100. package/lib/module/floatingMenu/dial/dialUsageStore.js +1 -85
  101. package/lib/module/floatingMenu/dial/onboardingConstants.js +1 -3
  102. package/lib/module/floatingMenu/dial/onboardingConstants.web.js +1 -3
  103. package/lib/module/floatingMenu/externalSyncGate.js +1 -44
  104. package/lib/module/floatingMenu/floatingTools.js +1 -27
  105. package/lib/module/floatingMenu/floatingTools.web.js +1 -3
  106. package/lib/module/floatingMenu/optionalRequire.js +1 -33
  107. package/lib/module/floatingMenu/settingsBus.js +1 -19
  108. package/lib/module/floatingMenu/sync/appSyncAdapter.js +1 -112
  109. package/lib/module/floatingMenu/types.js +1 -3
  110. package/lib/module/floatingMenu/useDesktopSyncStatus.js +1 -25
  111. package/lib/module/floatingMenu/useDesktopSyncStatus.web.js +1 -0
  112. package/lib/module/index.js +1 -41
  113. package/lib/module/index.web.js +1 -29
  114. package/lib/module/reactDevtoolsTypes.js +1 -0
  115. package/lib/module/releaseOptIn.js +1 -0
  116. package/lib/module/telemetry/installPing.js +1 -127
  117. package/lib/module/toolkit.js +1 -62
  118. package/lib/module/toolkitComponents.js +1 -230
  119. package/lib/module/utils/autoDiscoverPresets.web.js +1 -213
  120. package/lib/module/utils/createWebTool.js +1 -0
  121. package/lib/module/utils/createWebTools.js +1 -0
  122. package/lib/module/version.js +1 -14
  123. package/lib/typescript/commonjs/browserRegister.d.ts +13 -0
  124. package/lib/typescript/commonjs/browserRegister.server.d.ts +6 -0
  125. package/lib/typescript/commonjs/earlyHookScript.d.ts +12 -0
  126. package/lib/typescript/commonjs/earlyNetwork.d.ts +52 -0
  127. package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts +3 -3
  128. package/lib/typescript/commonjs/floatingMenu/BrowserToolRuntime.d.ts +14 -0
  129. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts +2 -67
  130. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.shared.d.ts +71 -0
  131. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts +3 -16
  132. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts +12 -6
  133. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +1 -1
  134. package/lib/typescript/commonjs/floatingMenu/settingsBus.d.ts +1 -9
  135. package/lib/typescript/commonjs/floatingMenu/useDesktopSyncStatus.web.d.ts +3 -0
  136. package/lib/typescript/commonjs/index.web.d.ts +7 -0
  137. package/lib/typescript/commonjs/reactDevtoolsTypes.d.ts +8 -0
  138. package/lib/typescript/commonjs/releaseOptIn.d.ts +4 -0
  139. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts +3 -40
  140. package/lib/typescript/commonjs/utils/createWebTool.d.ts +6 -0
  141. package/lib/typescript/commonjs/utils/createWebTools.d.ts +4 -0
  142. package/lib/typescript/commonjs/version.d.ts +1 -1
  143. package/lib/typescript/module/browserRegister.d.ts +13 -0
  144. package/lib/typescript/module/browserRegister.server.d.ts +6 -0
  145. package/lib/typescript/module/earlyHookScript.d.ts +12 -0
  146. package/lib/typescript/module/earlyNetwork.d.ts +52 -0
  147. package/lib/typescript/module/floatingMenu/AppHost.web.d.ts +3 -3
  148. package/lib/typescript/module/floatingMenu/BrowserToolRuntime.d.ts +14 -0
  149. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts +2 -67
  150. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.shared.d.ts +71 -0
  151. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts +3 -16
  152. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts +12 -6
  153. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +1 -1
  154. package/lib/typescript/module/floatingMenu/settingsBus.d.ts +1 -9
  155. package/lib/typescript/module/floatingMenu/useDesktopSyncStatus.web.d.ts +3 -0
  156. package/lib/typescript/module/index.web.d.ts +7 -0
  157. package/lib/typescript/module/reactDevtoolsTypes.d.ts +8 -0
  158. package/lib/typescript/module/releaseOptIn.d.ts +4 -0
  159. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts +3 -40
  160. package/lib/typescript/module/utils/createWebTool.d.ts +6 -0
  161. package/lib/typescript/module/utils/createWebTools.d.ts +4 -0
  162. package/lib/typescript/module/version.d.ts +1 -1
  163. package/lib/web/chunks/chunk-5SGL6QL4.mjs +1 -0
  164. package/lib/web/chunks/chunk-FROELTJH.mjs +1 -0
  165. package/lib/web/chunks/chunk-QZDVCMCT.mjs +1 -0
  166. package/lib/web/chunks/chunk-R7RGRTY5.mjs +1 -0
  167. package/lib/web/index.mjs +10 -0
  168. package/lib/web/register-server.mjs +1 -0
  169. package/lib/web/register.mjs +1 -0
  170. package/lib/web/toolkit.mjs +1 -0
  171. package/package.json +50 -12
  172. package/lib/typescript/commonjs/Buoy.d.ts.map +0 -1
  173. package/lib/typescript/commonjs/floatingMenu/AppHost.d.ts.map +0 -1
  174. package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts.map +0 -1
  175. package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts.map +0 -1
  176. package/lib/typescript/commonjs/floatingMenu/AppIcon.d.ts.map +0 -1
  177. package/lib/typescript/commonjs/floatingMenu/AppIcon.web.d.ts.map +0 -1
  178. package/lib/typescript/commonjs/floatingMenu/DefaultConfigContext.d.ts.map +0 -1
  179. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +0 -1
  180. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +0 -1
  181. package/lib/typescript/commonjs/floatingMenu/DevToolsVisibilityContext.d.ts.map +0 -1
  182. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +0 -1
  183. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +0 -1
  184. package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +0 -1
  185. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts.map +0 -1
  186. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.d.ts.map +0 -1
  187. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.web.d.ts.map +0 -1
  188. package/lib/typescript/commonjs/floatingMenu/ToggleStateManager.d.ts.map +0 -1
  189. package/lib/typescript/commonjs/floatingMenu/ToolHost.d.ts.map +0 -1
  190. package/lib/typescript/commonjs/floatingMenu/ToolOpenerBridge.d.ts.map +0 -1
  191. package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +0 -1
  192. package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +0 -1
  193. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +0 -1
  194. package/lib/typescript/commonjs/floatingMenu/deviceIdentity.d.ts.map +0 -1
  195. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +0 -1
  196. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +0 -1
  197. package/lib/typescript/commonjs/floatingMenu/dial/DialHyperspace.d.ts.map +0 -1
  198. package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +0 -1
  199. package/lib/typescript/commonjs/floatingMenu/dial/DialPagination.d.ts.map +0 -1
  200. package/lib/typescript/commonjs/floatingMenu/dial/DialSnow.d.ts.map +0 -1
  201. package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.d.ts.map +0 -1
  202. package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +0 -1
  203. package/lib/typescript/commonjs/floatingMenu/dial/dialUsageStore.d.ts.map +0 -1
  204. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.d.ts.map +0 -1
  205. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts.map +0 -1
  206. package/lib/typescript/commonjs/floatingMenu/externalSyncGate.d.ts.map +0 -1
  207. package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts.map +0 -1
  208. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts.map +0 -1
  209. package/lib/typescript/commonjs/floatingMenu/optionalRequire.d.ts.map +0 -1
  210. package/lib/typescript/commonjs/floatingMenu/settingsBus.d.ts.map +0 -1
  211. package/lib/typescript/commonjs/floatingMenu/sync/appSyncAdapter.d.ts.map +0 -1
  212. package/lib/typescript/commonjs/floatingMenu/types.d.ts.map +0 -1
  213. package/lib/typescript/commonjs/floatingMenu/useDesktopSyncStatus.d.ts.map +0 -1
  214. package/lib/typescript/commonjs/index.d.ts.map +0 -1
  215. package/lib/typescript/commonjs/index.web.d.ts.map +0 -1
  216. package/lib/typescript/commonjs/telemetry/installPing.d.ts.map +0 -1
  217. package/lib/typescript/commonjs/toolkit.d.ts.map +0 -1
  218. package/lib/typescript/commonjs/toolkitComponents.d.ts.map +0 -1
  219. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts.map +0 -1
  220. package/lib/typescript/commonjs/version.d.ts.map +0 -1
  221. package/lib/typescript/module/Buoy.d.ts.map +0 -1
  222. package/lib/typescript/module/floatingMenu/AppHost.d.ts.map +0 -1
  223. package/lib/typescript/module/floatingMenu/AppHost.web.d.ts.map +0 -1
  224. package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts.map +0 -1
  225. package/lib/typescript/module/floatingMenu/AppIcon.d.ts.map +0 -1
  226. package/lib/typescript/module/floatingMenu/AppIcon.web.d.ts.map +0 -1
  227. package/lib/typescript/module/floatingMenu/DefaultConfigContext.d.ts.map +0 -1
  228. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +0 -1
  229. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +0 -1
  230. package/lib/typescript/module/floatingMenu/DevToolsVisibilityContext.d.ts.map +0 -1
  231. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +0 -1
  232. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +0 -1
  233. package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +0 -1
  234. package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts.map +0 -1
  235. package/lib/typescript/module/floatingMenu/MinimizedToolsStack.d.ts.map +0 -1
  236. package/lib/typescript/module/floatingMenu/MinimizedToolsStack.web.d.ts.map +0 -1
  237. package/lib/typescript/module/floatingMenu/ToggleStateManager.d.ts.map +0 -1
  238. package/lib/typescript/module/floatingMenu/ToolHost.d.ts.map +0 -1
  239. package/lib/typescript/module/floatingMenu/ToolOpenerBridge.d.ts.map +0 -1
  240. package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +0 -1
  241. package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +0 -1
  242. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +0 -1
  243. package/lib/typescript/module/floatingMenu/deviceIdentity.d.ts.map +0 -1
  244. package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +0 -1
  245. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +0 -1
  246. package/lib/typescript/module/floatingMenu/dial/DialHyperspace.d.ts.map +0 -1
  247. package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +0 -1
  248. package/lib/typescript/module/floatingMenu/dial/DialPagination.d.ts.map +0 -1
  249. package/lib/typescript/module/floatingMenu/dial/DialSnow.d.ts.map +0 -1
  250. package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.d.ts.map +0 -1
  251. package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +0 -1
  252. package/lib/typescript/module/floatingMenu/dial/dialUsageStore.d.ts.map +0 -1
  253. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.d.ts.map +0 -1
  254. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts.map +0 -1
  255. package/lib/typescript/module/floatingMenu/externalSyncGate.d.ts.map +0 -1
  256. package/lib/typescript/module/floatingMenu/floatingTools.d.ts.map +0 -1
  257. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts.map +0 -1
  258. package/lib/typescript/module/floatingMenu/optionalRequire.d.ts.map +0 -1
  259. package/lib/typescript/module/floatingMenu/settingsBus.d.ts.map +0 -1
  260. package/lib/typescript/module/floatingMenu/sync/appSyncAdapter.d.ts.map +0 -1
  261. package/lib/typescript/module/floatingMenu/types.d.ts.map +0 -1
  262. package/lib/typescript/module/floatingMenu/useDesktopSyncStatus.d.ts.map +0 -1
  263. package/lib/typescript/module/index.d.ts.map +0 -1
  264. package/lib/typescript/module/index.web.d.ts.map +0 -1
  265. package/lib/typescript/module/telemetry/installPing.d.ts.map +0 -1
  266. package/lib/typescript/module/toolkit.d.ts.map +0 -1
  267. package/lib/typescript/module/toolkitComponents.d.ts.map +0 -1
  268. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts.map +0 -1
  269. package/lib/typescript/module/version.d.ts.map +0 -1
@@ -1,1115 +1 @@
1
- "use strict";
2
-
3
- import { useState, useEffect, useCallback, useMemo } from "react";
4
- import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Dimensions, Platform } from "react-native";
5
- import { settingsBus } from "./settingsBus.js";
6
- import { useDesktopSyncStatus } from "./useDesktopSyncStatus.js";
7
- import { SentryIcon, WifiCircuitIcon, ImageOverlayIcon, RenderCountIcon, Info, Layers, ChevronRightIcon, ChevronDown, getStorageBackendType, persistentStorage, Trash2, CheckCircle2, LicenseEntryModal, BackgroundSwitcher, night, NightCard, NightRows, NightSectionLabel, NightFootnote, NightSwitch, NightButton, NightSegmented, NightBadge, NightSeparator, monoFont } from "@buoy-gg/shared-ui";
8
- import { EnvIcon, StorageIcon, RoutesIcon, NetworkIcon, QueryIcon, HighlighterIcon, ReduxIcon, EventsIcon } from "@buoy-gg/floating-tools-core";
9
- import { useDefaultConfig } from "./DefaultConfigContext.js";
10
- import { renderAppIcon } from "./AppIcon";
11
- import { JsModal, devToolsStorageKeys } from "@buoy-gg/shared-ui";
12
- import { useSafeAreaInsets } from "@buoy-gg/shared-ui";
13
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
14
- const STORAGE_KEY = "@react_buoy_dev_tools_settings";
15
- const MAX_DIAL_SLOTS = 6;
16
-
17
- // Lazy load license hooks to avoid circular dependencies
18
- let _useLicense = null;
19
- function getUseLicense() {
20
- if (!_useLicense) {
21
- try {
22
- const mod = require("@buoy-gg/license");
23
- _useLicense = mod.useLicense;
24
- } catch {
25
- // License package not available
26
- }
27
- }
28
- return _useLicense;
29
- }
30
- const enforceDialLimit = dialTools => {
31
- let remaining = MAX_DIAL_SLOTS;
32
- const limited = {};
33
- for (const [id, enabled] of Object.entries(dialTools)) {
34
- if (enabled && remaining > 0) {
35
- limited[id] = true;
36
- remaining -= 1;
37
- } else {
38
- limited[id] = false;
39
- }
40
- }
41
- return limited;
42
- };
43
- const sanitizeFloating = (floating, allowedKeys) => {
44
- const {
45
- userStatus,
46
- environment,
47
- ...rest
48
- } = floating;
49
- const filteredEntries = allowedKeys ? Object.entries(rest).filter(([key]) => allowedKeys.includes(key)) : Object.entries(rest);
50
- return {
51
- ...Object.fromEntries(filteredEntries),
52
- environment: environment ?? false
53
- };
54
- };
55
- const mergeWithDefaults = (defaults, stored, options) => {
56
- if (!stored) return defaults;
57
- const combinedDial = {
58
- ...defaults.dialTools,
59
- ...(stored.dialTools ?? {})
60
- };
61
- const dialEntries = options?.allowedDialKeys ? Object.entries(combinedDial).filter(([key]) => options.allowedDialKeys?.includes(key)) : Object.entries(combinedDial);
62
- const mergedDial = enforceDialLimit(Object.fromEntries(dialEntries));
63
- return {
64
- dialTools: mergedDial,
65
- floatingTools: sanitizeFloating({
66
- ...defaults.floatingTools,
67
- ...(stored.floatingTools ?? {})
68
- }, options?.allowedFloatingKeys),
69
- globalSettings: {
70
- enableSharedModalDimensions: false,
71
- // Default to false
72
- expandableWindowControls: true,
73
- // Default to true
74
- ...(stored.globalSettings ?? {})
75
- }
76
- };
77
- };
78
-
79
- /**
80
- * Global settings that apply to all dev tools.
81
- * These settings override individual tool configurations.
82
- */
83
-
84
- /**
85
- * Serialized preferences that power the floating dev tools UI. Values persist across sessions
86
- * via AsyncStorage so teams can tailor which tools appear in the dial or floating row.
87
- */
88
-
89
- /**
90
- * The subset of InstalledApp the settings modal needs per tool. `icon`/`color`
91
- * let rows fall back to the tool's own glyph when getToolIcon() has no
92
- * night-tuned override for it.
93
- */
94
-
95
- /**
96
- * Generate default settings based on available apps and optional team default configuration.
97
- *
98
- * @param availableApps - List of available apps from auto-discovery
99
- * @param defaultFloatingTools - Optional array of tool IDs to enable by default in floating bubble
100
- * @param defaultDialTools - Optional array of tool IDs to enable by default in dial menu
101
- * If not provided, all dial-compatible tools are enabled by default (up to 6)
102
- */
103
- const generateDefaultSettings = (availableApps = [], defaultFloatingTools, defaultDialTools) => {
104
- const dialDefaults = {};
105
- const floatingDefaults = {};
106
-
107
- // Create sets for quick lookup of default-enabled tools
108
- // Cast to Set<string> to allow comparison with any tool ID (including custom tools)
109
- const enabledFloatingSet = new Set(defaultFloatingTools ?? []);
110
- const enabledDialSet = new Set(defaultDialTools ?? []);
111
-
112
- // If no defaultDialTools specified, auto-enable all dial-compatible tools
113
- const autoEnableDialTools = !defaultDialTools || defaultDialTools.length === 0;
114
- for (const app of availableApps) {
115
- const {
116
- id,
117
- slot = "both"
118
- } = app;
119
- if (slot === "dial" || slot === "both") {
120
- // Auto-enable if no defaults specified, otherwise check the set
121
- dialDefaults[id] = autoEnableDialTools ? true : enabledDialSet.has(id);
122
- }
123
- if (slot === "row" || slot === "both") {
124
- // Enable if in defaultFloatingTools, otherwise false
125
- floatingDefaults[id] = enabledFloatingSet.has(id);
126
- }
127
- }
128
- return {
129
- dialTools: enforceDialLimit(dialDefaults),
130
- floatingTools: {
131
- ...floatingDefaults,
132
- // Special: environment badge - check if 'environment' is in the floating defaults
133
- environment: enabledFloatingSet.has('environment')
134
- },
135
- globalSettings: {
136
- enableSharedModalDimensions: false,
137
- // Default to false - each modal has its own persistence
138
- expandableWindowControls: true // Default to true - expandable on touch devices
139
- }
140
- };
141
- };
142
-
143
- /**
144
- * Configurable modal surface that lets engineers pick which dev tools appear in the dial and
145
- * floating row. Persists preferences and enforces slot limits for a consistent UX.
146
- *
147
- * Styled in the "night" language (Everlights port — see shared-ui's
148
- * ui/night): section labels outside near-black cards, hairline-separated
149
- * rows, real switches, and a transparent header the star field runs through.
150
- */
151
- export const DevToolsSettingsModal = ({
152
- visible,
153
- onClose,
154
- onSettingsChange,
155
- initialSettings,
156
- availableApps = []
157
- }) => {
158
- // Get team default configuration from context
159
- const {
160
- defaultFloatingTools,
161
- defaultDialTools
162
- } = useDefaultConfig();
163
- const defaultSettings = useMemo(() => generateDefaultSettings(availableApps, defaultFloatingTools, defaultDialTools), [availableApps, defaultFloatingTools, defaultDialTools]);
164
- const allowedDialKeys = useMemo(() => Object.keys(defaultSettings.dialTools), [defaultSettings]);
165
- const allowedFloatingKeys = useMemo(() => Object.keys(defaultSettings.floatingTools).filter(key => key !== "environment"), [defaultSettings]);
166
- const [settings, setSettings] = useState(initialSettings || cachedSettings || defaultSettings);
167
- const [activeTab, setActiveTab] = useState(cachedActiveTab ?? "floating");
168
- const [activeTabLoaded, setActiveTabLoaded] = useState(cachedActiveTab !== null);
169
- const [expandedSettings, setExpandedSettings] = useState(new Set());
170
- const [showLicenseModal, setShowLicenseModal] = useState(false);
171
- /**
172
- * Tool icons are the expensive half of this modal: ~20 of them, each a
173
- * data-driven glyph that mounts one view per shape. Rendering them in the
174
- * first pass pushed the modal's first paint out to ~240ms, so the tap felt
175
- * dead. Holding them back a single frame lets the chrome and the tool rows
176
- * paint at ~100ms and the glyphs land during the entrance fade.
177
- *
178
- * There is no layout shift: `styles.toolIconSlot` is a fixed box, so it
179
- * reads as the icon's placeholder until filled.
180
- */
181
- const [iconsReady, setIconsReady] = useState(false);
182
- useEffect(() => {
183
- const frame = requestAnimationFrame(() => setIconsReady(true));
184
- return () => cancelAnimationFrame(frame);
185
- }, []);
186
-
187
- // null when external-sync isn't installed (or predates the status store);
188
- // "idle" until AutoExternalSync initializes — the row hides in both cases.
189
- const desktopSyncStatus = useDesktopSyncStatus();
190
-
191
- // Load persisted active tab on mount
192
- useEffect(() => {
193
- const loadActiveTab = async () => {
194
- try {
195
- const savedTab = await persistentStorage.getItem(devToolsStorageKeys.settings.activeTab());
196
- if (savedTab && ["floating", "settings", "pro"].includes(savedTab)) {
197
- const tab = savedTab;
198
- cachedActiveTab = tab;
199
- setActiveTab(prev => prev === tab ? prev : tab);
200
- }
201
- } catch (error) {
202
- // Failed to load active tab - use default
203
- } finally {
204
- setActiveTabLoaded(true);
205
- }
206
- };
207
- loadActiveTab();
208
- }, []);
209
-
210
- // Persist active tab when it changes
211
- useEffect(() => {
212
- // Only persist after initial state is loaded to avoid overwriting with default
213
- if (!activeTabLoaded) return;
214
- persistentStorage.setItem(devToolsStorageKeys.settings.activeTab(), activeTab).catch(error => {
215
- // Failed to save active tab - continue without persistence
216
- console.warn("Failed to save settings active tab:", error);
217
- });
218
- }, [activeTab, activeTabLoaded]);
219
-
220
- // License hooks
221
- const useLicenseHook = getUseLicense();
222
- const license = useLicenseHook?.();
223
- const isPro = license?.isPro ?? false;
224
- // A key is set but validation is failing. Without this the tab renders a bare
225
- // "Free" badge, which reads as "your key was rejected" when what actually
226
- // happened is that we never reached the license server. `errorKind` decides
227
- // which story to tell: only a transport failure gets the VPN/proxy advice — a
228
- // real verdict (suspended, expired) with that advice would send the user off
229
- // to fight their network over a key that was genuinely rejected.
230
- const licenseError = !isPro && license?.licenseKey ? license.error : null;
231
- const licenseErrorIsTransport = license?.errorKind === "transport";
232
- const [storageBackend, setStorageBackend] = useState(cachedStorageBackend);
233
- const [isClearing, setIsClearing] = useState(false);
234
- const [clearSuccess, setClearSuccess] = useState(false);
235
- const [isStorageExpanded, setIsStorageExpanded] = useState(false);
236
- const [savedKeys, setSavedKeys] = useState([]);
237
- const [savedKeysLoading, setSavedKeysLoading] = useState(false);
238
- const insets = useSafeAreaInsets();
239
- const screenHeight = Dimensions.get("window").height;
240
- const screenWidth = Dimensions.get("window").width;
241
- const modalHeight = Math.floor(screenHeight * 0.33); // 1/3 of screen height
242
- const modalWidth = Math.min(screenWidth - 32, 400); // Modal width with padding
243
-
244
- const loadSettings = useCallback(async () => {
245
- try {
246
- const savedSettings = await persistentStorage.getItem(STORAGE_KEY);
247
- if (savedSettings) {
248
- const parsed = JSON.parse(savedSettings);
249
- const merged = mergeWithDefaults(defaultSettings, parsed, {
250
- allowedDialKeys,
251
- allowedFloatingKeys
252
- });
253
- cachedSettings = merged;
254
- setSettings(prev => sameSettings(prev, merged) ? prev : merged);
255
- return;
256
- }
257
- cachedSettings = defaultSettings;
258
- setSettings(prev => sameSettings(prev, defaultSettings) ? prev : defaultSettings);
259
- } catch (error) {
260
- console.error("Failed to load dev tools settings:", error);
261
- setSettings(defaultSettings);
262
- }
263
- }, [defaultSettings, allowedDialKeys, allowedFloatingKeys]);
264
- useEffect(() => {
265
- loadSettings();
266
- }, [loadSettings]);
267
-
268
- // Load storage backend type
269
- useEffect(() => {
270
- getStorageBackendType().then(backend => {
271
- cachedStorageBackend = backend;
272
- setStorageBackend(prev => prev === backend ? prev : backend);
273
- });
274
- }, []);
275
-
276
- // Load saved keys when storage card is expanded
277
- useEffect(() => {
278
- if (isStorageExpanded) {
279
- setSavedKeysLoading(true);
280
- persistentStorage.getAllKeys().then(keys => {
281
- setSavedKeys(keys.sort());
282
- }).catch(() => {
283
- setSavedKeys([]);
284
- }).finally(() => {
285
- setSavedKeysLoading(false);
286
- });
287
- }
288
- }, [isStorageExpanded]);
289
- const saveSettings = async newSettings => {
290
- try {
291
- const limitedSettings = {
292
- ...newSettings,
293
- dialTools: enforceDialLimit(newSettings.dialTools)
294
- };
295
- await persistentStorage.setItem(STORAGE_KEY, JSON.stringify(limitedSettings));
296
- cachedSettings = limitedSettings;
297
- setSettings(limitedSettings);
298
- onSettingsChange?.(limitedSettings);
299
- // Notify listeners (e.g., floating bubble) to refresh immediately
300
- settingsBus.emit(limitedSettings);
301
- } catch (error) {
302
- console.error("Failed to save dev tools settings:", error);
303
- }
304
- };
305
- const toggleFloatingTool = tool => {
306
- const newSettings = {
307
- ...settings,
308
- floatingTools: {
309
- ...settings.floatingTools,
310
- [tool]: !settings.floatingTools[tool]
311
- }
312
- };
313
- saveSettings(newSettings);
314
- };
315
- const toggleGlobalSetting = setting => {
316
- const newSettings = {
317
- ...settings,
318
- globalSettings: {
319
- ...settings.globalSettings,
320
- [setting]: !settings.globalSettings?.[setting]
321
- }
322
- };
323
- saveSettings(newSettings);
324
- };
325
- const handleClearStorage = async () => {
326
- setIsClearing(true);
327
- setClearSuccess(false);
328
- try {
329
- await persistentStorage.clear();
330
- setClearSuccess(true);
331
- // Reset settings to defaults after clearing
332
- setSettings(defaultSettings);
333
- settingsBus.emit(defaultSettings);
334
- // Reset success state after 2 seconds
335
- setTimeout(() => setClearSuccess(false), 2000);
336
- } catch (error) {
337
- console.error("Failed to clear storage:", error);
338
- } finally {
339
- setIsClearing(false);
340
- }
341
- };
342
-
343
- // Modal is fixed to bottom sheet mode
344
- const handleModeChange = useCallback(_mode => {
345
- // Mode changes handled by JsModal
346
- }, []);
347
- const getToolDescription = tool => {
348
- // Get description from availableApps
349
- const app = availableApps.find(a => a.id === tool);
350
- if (app?.description) {
351
- return app.description;
352
- }
353
- if (tool === "environment") {
354
- return "Environment badge.";
355
- }
356
- return "";
357
- };
358
- const getToolLabel = tool => {
359
- if (tool === "environment") {
360
- return "Env Badge";
361
- }
362
- const app = availableApps.find(a => a.id === tool);
363
- return app?.name ?? tool.toUpperCase().replace(/_/g, " ");
364
- };
365
- const getToolIcon = tool => {
366
- if (!iconsReady) return null;
367
- switch (tool) {
368
- case "query":
369
- return /*#__PURE__*/_jsx(QueryIcon, {
370
- size: 18
371
- });
372
- case "env":
373
- return /*#__PURE__*/_jsx(EnvIcon, {
374
- size: 18
375
- });
376
- case "sentry":
377
- return /*#__PURE__*/_jsx(SentryIcon, {
378
- size: 18,
379
- color: "#9945FF"
380
- });
381
- case "storage":
382
- return /*#__PURE__*/_jsx(StorageIcon, {
383
- size: 18,
384
- bgColor: night.color.surface
385
- });
386
- case "wifi":
387
- case "query-wifi-toggle":
388
- // Support both IDs for wifi toggle
389
- return /*#__PURE__*/_jsx(WifiCircuitIcon, {
390
- size: 18,
391
- colorPreset: "green",
392
- strength: 4,
393
- noBackground: true
394
- });
395
- case "route-events":
396
- return /*#__PURE__*/_jsx(RoutesIcon, {
397
- size: 18,
398
- bgColor: night.color.surface
399
- });
400
- case "network":
401
- return /*#__PURE__*/_jsx(NetworkIcon, {
402
- size: 18
403
- });
404
- case "environment":
405
- return /*#__PURE__*/_jsx(EnvIcon, {
406
- size: 18
407
- });
408
- case "debug-borders":
409
- return /*#__PURE__*/_jsx(Layers, {
410
- size: 18,
411
- color: night.color.accent
412
- });
413
- case "highlight-updates":
414
- return /*#__PURE__*/_jsx(RenderCountIcon, {
415
- size: 18,
416
- color: night.color.accent
417
- });
418
- case "highlight-updates-modal":
419
- return /*#__PURE__*/_jsx(HighlighterIcon, {
420
- size: 18
421
- });
422
- case "redux":
423
- return /*#__PURE__*/_jsx(ReduxIcon, {
424
- size: 18
425
- });
426
- case "image-overlay":
427
- return /*#__PURE__*/_jsx(ImageOverlayIcon, {
428
- size: 18
429
- });
430
- case "events":
431
- return /*#__PURE__*/_jsx(EventsIcon, {
432
- size: 18
433
- });
434
- case "zustand":
435
- try {
436
- // @ts-ignore - Optional package
437
- const {
438
- ZustandIcon
439
- } = require("@buoy-gg/zustand");
440
- return /*#__PURE__*/_jsx(ZustandIcon, {
441
- size: 18
442
- });
443
- } catch {
444
- return /*#__PURE__*/_jsx(Info, {
445
- size: 18,
446
- color: night.color.textSecondary
447
- });
448
- }
449
- case "jotai":
450
- try {
451
- // @ts-ignore - Optional package
452
- const {
453
- JotaiIcon
454
- } = require("@buoy-gg/jotai");
455
- return /*#__PURE__*/_jsx(JotaiIcon, {
456
- size: 18
457
- });
458
- } catch {
459
- return /*#__PURE__*/_jsx(Info, {
460
- size: 18,
461
- color: night.color.textSecondary
462
- });
463
- }
464
- default:
465
- {
466
- // Tools without a night-tuned override (console, images, time
467
- // machine, perf monitor, custom toolkit tools, …) render their own
468
- // app icon — the same artwork the dial shows.
469
- const app = availableApps.find(a => a.id === tool);
470
- if (app?.icon != null) {
471
- return renderAppIcon(app.icon, {
472
- slot: "row",
473
- size: 18,
474
- color: app.color
475
- });
476
- }
477
- return /*#__PURE__*/_jsx(Info, {
478
- size: 18,
479
- color: night.color.textSecondary
480
- });
481
- }
482
- }
483
- };
484
-
485
- /**
486
- * One tool row: glyph, name + one-line description, switch. Lives inside a
487
- * NightCard's hairline-separated rows.
488
- */
489
- const renderToolRow = (keyName, value, disabled, onToggle) => {
490
- const description = getToolDescription(keyName);
491
- return /*#__PURE__*/_jsxs(TouchableOpacity, {
492
- activeOpacity: disabled ? 1 : 0.7,
493
- onPress: () => !disabled && onToggle(),
494
- accessibilityLabel: getToolLabel(keyName),
495
- style: [styles.toolRow, disabled && styles.rowDisabled],
496
- children: [/*#__PURE__*/_jsx(View, {
497
- style: styles.toolIconSlot,
498
- children: getToolIcon(keyName)
499
- }), /*#__PURE__*/_jsxs(View, {
500
- style: styles.rowInfo,
501
- children: [/*#__PURE__*/_jsxs(Text, {
502
- style: styles.rowLabel,
503
- children: [getToolLabel(keyName), disabled ? " · max 6" : ""]
504
- }), description ? /*#__PURE__*/_jsx(Text, {
505
- style: styles.rowCaption,
506
- numberOfLines: 1,
507
- children: description
508
- }) : null]
509
- }), /*#__PURE__*/_jsx(NightSwitch, {
510
- value: value,
511
- disabled: disabled,
512
- onValueChange: () => onToggle()
513
- })]
514
- }, keyName);
515
- };
516
-
517
- // Toggle expanded state for a setting card
518
- const toggleSettingExpanded = settingKey => {
519
- setExpandedSettings(prev => {
520
- const newSet = new Set(prev);
521
- if (newSet.has(settingKey)) {
522
- newSet.delete(settingKey);
523
- } else {
524
- newSet.add(settingKey);
525
- }
526
- return newSet;
527
- });
528
- };
529
-
530
- /**
531
- * One global-setting row: name + one-line hint, switch, and a tap-to-expand
532
- * body holding the full description and recommendation.
533
- */
534
- const renderGlobalSettingRow = (settingKey, label, shortDescription, fullDescription, recommendation) => {
535
- const value = settings.globalSettings?.[settingKey] ?? false;
536
- const isExpanded = expandedSettings.has(settingKey);
537
- return /*#__PURE__*/_jsxs(View, {
538
- children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
539
- activeOpacity: 0.7,
540
- onPress: () => toggleSettingExpanded(settingKey),
541
- accessibilityLabel: label,
542
- style: styles.settingRow,
543
- children: [/*#__PURE__*/_jsxs(View, {
544
- style: styles.rowInfo,
545
- children: [/*#__PURE__*/_jsx(Text, {
546
- style: styles.rowLabel,
547
- children: label
548
- }), /*#__PURE__*/_jsx(Text, {
549
- style: styles.rowCaption,
550
- numberOfLines: isExpanded ? 0 : 1,
551
- children: shortDescription
552
- })]
553
- }), /*#__PURE__*/_jsx(NightSwitch, {
554
- value: value,
555
- onValueChange: () => toggleGlobalSetting(settingKey)
556
- })]
557
- }), isExpanded && /*#__PURE__*/_jsxs(View, {
558
- style: styles.settingRowBody,
559
- children: [/*#__PURE__*/_jsx(Text, {
560
- style: styles.settingRowBodyText,
561
- children: fullDescription
562
- }), /*#__PURE__*/_jsx(Text, {
563
- style: styles.settingRowBodyHint,
564
- children: recommendation
565
- })]
566
- })]
567
- }, settingKey);
568
- };
569
-
570
- /** Section = uppercase label, card, optional footnote(s) under it. */
571
- const renderSection = (label, card, footnotes) => /*#__PURE__*/_jsxs(View, {
572
- children: [/*#__PURE__*/_jsx(NightSectionLabel, {
573
- children: label
574
- }), card, footnotes]
575
- });
576
- const storageBadge = storageBackend === "filesystem" ? /*#__PURE__*/_jsx(NightBadge, {
577
- label: "File System",
578
- tone: "accent"
579
- }) : storageBackend === "asyncstorage" ? /*#__PURE__*/_jsx(NightBadge, {
580
- label: "Async Storage",
581
- tone: "warning"
582
- }) : storageBackend === "memory" ? /*#__PURE__*/_jsx(NightBadge, {
583
- label: "Memory",
584
- tone: "danger"
585
- }) : /*#__PURE__*/_jsx(NightBadge, {
586
- label: "Loading\u2026",
587
- tone: "neutral"
588
- });
589
- const renderContent = () => /*#__PURE__*/_jsxs(View, {
590
- style: styles.container,
591
- children: [/*#__PURE__*/_jsxs(ScrollView, {
592
- style: styles.scrollContent,
593
- showsVerticalScrollIndicator: false,
594
- contentContainerStyle: styles.scrollContainer,
595
- children: [activeTab === "floating" && /*#__PURE__*/_jsx(_Fragment, {
596
- children: renderSection("Floating Tools", /*#__PURE__*/_jsx(NightCard, {
597
- glass: true,
598
- children: /*#__PURE__*/_jsx(NightRows, {
599
- children: Object.entries(settings.floatingTools).map(([key, value]) => renderToolRow(key, value, false, () => toggleFloatingTool(key)))
600
- })
601
- }), /*#__PURE__*/_jsx(NightFootnote, {
602
- children: "Tools switched on here appear in the floating bubble row."
603
- }))
604
- }), activeTab === "settings" && /*#__PURE__*/_jsxs(_Fragment, {
605
- children: [renderSection("Background", /*#__PURE__*/_jsx(NightCard, {
606
- glass: true,
607
- padded: true,
608
- children: /*#__PURE__*/_jsx(BackgroundSwitcher, {
609
- embedded: true
610
- })
611
- })), renderSection("Storage", /*#__PURE__*/_jsxs(NightCard, {
612
- glass: true,
613
- children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
614
- activeOpacity: 0.7,
615
- onPress: () => setIsStorageExpanded(!isStorageExpanded),
616
- accessibilityLabel: "Storage Type",
617
- style: styles.settingRow,
618
- children: [/*#__PURE__*/_jsx(View, {
619
- style: styles.rowInfo,
620
- children: /*#__PURE__*/_jsx(Text, {
621
- style: styles.rowLabel,
622
- children: "Storage Type"
623
- })
624
- }), storageBadge, isStorageExpanded ? /*#__PURE__*/_jsx(ChevronDown, {
625
- size: 16,
626
- color: night.color.textTertiary
627
- }) : /*#__PURE__*/_jsx(ChevronRightIcon, {
628
- size: 16,
629
- color: night.color.textTertiary
630
- })]
631
- }), isStorageExpanded && /*#__PURE__*/_jsxs(_Fragment, {
632
- children: [/*#__PURE__*/_jsxs(View, {
633
- style: styles.settingRowBody,
634
- children: [/*#__PURE__*/_jsx(Text, {
635
- style: styles.settingRowBodyText,
636
- children: storageBackend === "filesystem" ? "Settings persist independently and survive AsyncStorage.clear() calls during logout." : storageBackend === "asyncstorage" ? "Settings may be lost if AsyncStorage is cleared during logout." : storageBackend === "memory" ? "Settings are stored in memory only and will be lost on app restart." : "Checking storage backend…"
637
- }), storageBackend === "asyncstorage" && /*#__PURE__*/_jsx(Text, {
638
- style: [styles.settingRowBodyText, styles.bodyWarning],
639
- children: "Install expo-file-system to persist settings through logout flows."
640
- }), storageBackend === "memory" && /*#__PURE__*/_jsx(Text, {
641
- style: [styles.settingRowBodyText, styles.bodyDanger],
642
- children: "No persistent storage available \u2014 install expo-file-system (best) or @react-native-async-storage/async-storage."
643
- })]
644
- }), /*#__PURE__*/_jsx(NightSeparator, {}), /*#__PURE__*/_jsxs(View, {
645
- style: styles.storageExpanded,
646
- children: [/*#__PURE__*/_jsxs(View, {
647
- style: styles.storageExpandedHeader,
648
- children: [/*#__PURE__*/_jsx(Text, {
649
- style: styles.storageExpandedTitle,
650
- children: "SAVED SETTINGS"
651
- }), /*#__PURE__*/_jsx(Text, {
652
- style: styles.storageExpandedCount,
653
- children: savedKeysLoading ? "…" : `${savedKeys.length} keys`
654
- })]
655
- }), savedKeysLoading ? /*#__PURE__*/_jsx(Text, {
656
- style: styles.storageKeyEmpty,
657
- children: "Loading\u2026"
658
- }) : savedKeys.length === 0 ? /*#__PURE__*/_jsx(Text, {
659
- style: styles.storageKeyEmpty,
660
- children: "No settings saved yet"
661
- }) : /*#__PURE__*/_jsx(ScrollView, {
662
- style: styles.storageKeysList,
663
- nestedScrollEnabled: true,
664
- showsVerticalScrollIndicator: true,
665
- children: savedKeys.map(key => /*#__PURE__*/_jsx(View, {
666
- style: styles.storageKeyItem,
667
- children: /*#__PURE__*/_jsx(Text, {
668
- style: styles.storageKeyText,
669
- numberOfLines: 1,
670
- children: key.replace("@react_buoy_", "")
671
- })
672
- }, key))
673
- })]
674
- }), /*#__PURE__*/_jsx(View, {
675
- style: styles.cardButtonWrap,
676
- children: /*#__PURE__*/_jsx(NightButton, {
677
- label: clearSuccess ? "Cleared" : isClearing ? "Clearing…" : "Clear All Settings",
678
- variant: clearSuccess ? "secondary" : "destructive",
679
- size: "md",
680
- disabled: isClearing,
681
- onPress: handleClearStorage,
682
- icon: clearSuccess ? /*#__PURE__*/_jsx(CheckCircle2, {
683
- size: 15,
684
- color: night.color.accent
685
- }) : /*#__PURE__*/_jsx(Trash2, {
686
- size: 15,
687
- color: isClearing ? night.color.textTertiary : night.color.danger
688
- })
689
- })
690
- })]
691
- })]
692
- })), desktopSyncStatus && desktopSyncStatus.state !== "idle" && renderSection("Desktop Sync", /*#__PURE__*/_jsxs(NightCard, {
693
- glass: true,
694
- children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
695
- activeOpacity: 0.7,
696
- onPress: () => toggleSettingExpanded("desktopSync"),
697
- accessibilityLabel: "Buoy Desktop",
698
- style: styles.settingRow,
699
- children: [/*#__PURE__*/_jsx(View, {
700
- style: styles.rowInfo,
701
- children: /*#__PURE__*/_jsx(Text, {
702
- style: styles.rowLabel,
703
- children: "Buoy Desktop"
704
- })
705
- }), desktopSyncStatus.state === "connected" ? /*#__PURE__*/_jsx(NightBadge, {
706
- label: "Connected",
707
- tone: "accent"
708
- }) : desktopSyncStatus.state === "connecting" ? /*#__PURE__*/_jsx(NightBadge, {
709
- label: "Connecting\u2026",
710
- tone: "neutral"
711
- }) : /*#__PURE__*/_jsx(NightBadge, {
712
- label: "Retrying",
713
- tone: "warning"
714
- }), expandedSettings.has("desktopSync") ? /*#__PURE__*/_jsx(ChevronDown, {
715
- size: 16,
716
- color: night.color.textTertiary
717
- }) : /*#__PURE__*/_jsx(ChevronRightIcon, {
718
- size: 16,
719
- color: night.color.textTertiary
720
- })]
721
- }), expandedSettings.has("desktopSync") && /*#__PURE__*/_jsxs(View, {
722
- style: styles.settingRowBody,
723
- children: [/*#__PURE__*/_jsxs(Text, {
724
- style: styles.settingRowBodyText,
725
- children: [desktopSyncStatus.state === "connected" ? "Streaming tool data to Buoy Desktop at " : "Trying to reach Buoy Desktop at ", /*#__PURE__*/_jsx(Text, {
726
- style: styles.footnoteMono,
727
- children: desktopSyncStatus.targetURL ?? "(unknown URL)"
728
- }), desktopSyncStatus.state !== "connected" && " — is the desktop app running? Override with the externalSync socketURL option if it runs elsewhere."]
729
- }), desktopSyncStatus.state === "retrying" && desktopSyncStatus.lastError && /*#__PURE__*/_jsxs(Text, {
730
- style: [styles.settingRowBodyText, styles.bodyWarning],
731
- children: ["Last error: ", desktopSyncStatus.lastError]
732
- })]
733
- })]
734
- })), renderSection("Modal Behavior", /*#__PURE__*/_jsx(NightCard, {
735
- glass: true,
736
- children: /*#__PURE__*/_jsxs(NightRows, {
737
- children: [renderGlobalSettingRow("enableSharedModalDimensions", "Shared Modal Size", "Sync dimensions across all tools", "When enabled, all tool modals will share the same size and position. Resizing one modal will affect all others. When disabled, each tool remembers its own size and position independently.", "Keep OFF for the best experience. This allows you to customize each tool's modal size separately."), Platform.OS !== "web" ? renderGlobalSettingRow("expandableWindowControls", "Expand Controls", "iPad-style expandable window buttons", "When enabled, the window control buttons (minimize, toggle mode, close) start as small dots and expand into larger, easy-to-tap buttons when pressed. When disabled, buttons are directly tappable at their small size.", "Keep ON for touch devices where the small buttons are hard to press. Turn OFF if you prefer direct single-tap access.") : null]
738
- })
739
- }))]
740
- }), activeTab === "pro" && /*#__PURE__*/_jsxs(_Fragment, {
741
- children: [renderSection("License", /*#__PURE__*/_jsx(NightCard, {
742
- glass: true,
743
- children: /*#__PURE__*/_jsxs(View, {
744
- style: styles.settingRow,
745
- children: [/*#__PURE__*/_jsx(View, {
746
- style: styles.rowInfo,
747
- children: /*#__PURE__*/_jsx(Text, {
748
- style: styles.rowLabel,
749
- children: "License Status"
750
- })
751
- }), /*#__PURE__*/_jsx(View, {
752
- testID: "buoy-settings-license-status",
753
- accessibilityLabel: isPro ? "License: Active" : "License: Free",
754
- children: isPro ? /*#__PURE__*/_jsx(NightBadge, {
755
- label: "Active",
756
- tone: "accent"
757
- }) : /*#__PURE__*/_jsx(NightBadge, {
758
- label: "Free",
759
- tone: "neutral"
760
- })
761
- })]
762
- })
763
- }), /*#__PURE__*/_jsx(NightFootnote, {
764
- children: isPro ? "You have full access to all Buoy DevTools features." : licenseError ? licenseErrorIsTransport ? `Couldn't reach the license server (${licenseError}). A VPN or corporate proxy can block buoy.gg — turn it off and reload. Your key hasn't been rejected.` : `License check failed: ${licenseError}.` : "Upgrade to Pro to unlock all features and support development."
765
- })), !isPro && /*#__PURE__*/_jsxs(_Fragment, {
766
- children: [renderSection("Pro Features", /*#__PURE__*/_jsx(NightCard, {
767
- glass: true,
768
- children: /*#__PURE__*/_jsx(NightRows, {
769
- children: ["Advanced Settings", "Priority Support"].map(feature => /*#__PURE__*/_jsxs(View, {
770
- style: styles.featureRow,
771
- children: [/*#__PURE__*/_jsx(CheckCircle2, {
772
- size: 16,
773
- color: night.color.accent
774
- }), /*#__PURE__*/_jsx(Text, {
775
- style: styles.rowLabel,
776
- children: feature
777
- })]
778
- }, feature))
779
- })
780
- })), /*#__PURE__*/_jsx(NightButton, {
781
- label: "Upgrade to Pro",
782
- variant: "primary",
783
- size: "lg",
784
- onPress: () => setShowLicenseModal(true)
785
- })]
786
- })]
787
- })]
788
- }), /*#__PURE__*/_jsx(LicenseEntryModal, {
789
- visible: showLicenseModal,
790
- onClose: () => setShowLicenseModal(false),
791
- onSuccess: () => setShowLicenseModal(false)
792
- })]
793
- });
794
- return /*#__PURE__*/_jsx(JsModal, {
795
- visible: visible,
796
- onClose: onClose,
797
- variant: "night",
798
- header: {
799
- showToggleButton: false,
800
- customContent: /*#__PURE__*/_jsx(View, {
801
- style: styles.headerRow,
802
- children: /*#__PURE__*/_jsx(NightSegmented, {
803
- glass: true,
804
- tabs: [{
805
- key: "floating",
806
- label: "Floating"
807
- }, {
808
- key: "settings",
809
- label: "Settings"
810
- }, {
811
- key: "pro",
812
- label: "Pro"
813
- }],
814
- activeKey: activeTab,
815
- onChange: tab => setActiveTab(tab)
816
- })
817
- })
818
- },
819
- initialMode: "bottomSheet",
820
- onModeChange: handleModeChange,
821
- persistenceKey: devToolsStorageKeys.settings.root(),
822
- enablePersistence: true,
823
- maxHeight: screenHeight - insets.top,
824
- initialHeight: modalHeight,
825
- initialFloatingPosition: {
826
- x: (screenWidth - modalWidth) / 2,
827
- y: insets.top + 20
828
- },
829
- enableGlitchEffects: true,
830
- children: renderContent()
831
- });
832
- };
833
-
834
- // Basic default settings for the hook (when apps are not available and no defaults configured)
835
- const basicDefaultSettings = {
836
- dialTools: {},
837
- floatingTools: {
838
- environment: false
839
- },
840
- globalSettings: {
841
- enableSharedModalDimensions: false
842
- }
843
- };
844
-
845
- /**
846
- * Creates default settings from the team configuration arrays.
847
- * Used by the hook when no stored settings exist.
848
- *
849
- * Note: This function doesn't have access to availableApps, so it can only
850
- * enable tools that are explicitly listed in the config arrays.
851
- * For auto-enabling all dial tools, the generateDefaultSettings function
852
- * (which has access to availableApps) handles that case.
853
- */
854
- const createDefaultsFromConfig = (defaultFloatingTools, defaultDialTools) => {
855
- const floatingSet = new Set(defaultFloatingTools ?? []);
856
- const dialSet = new Set(defaultDialTools ?? []);
857
-
858
- // Build dial tools record from defaults
859
- // Note: If no defaults specified, dialTools will be empty here
860
- // but generateDefaultSettings will auto-enable all tools when it has access to availableApps
861
- const dialTools = {};
862
- for (const id of dialSet) {
863
- dialTools[id] = true;
864
- }
865
-
866
- // Build floating tools record from defaults
867
- const floatingTools = {
868
- environment: floatingSet.has('environment')
869
- };
870
- for (const id of floatingSet) {
871
- if (id !== 'environment') {
872
- floatingTools[id] = true;
873
- }
874
- }
875
- return {
876
- dialTools: enforceDialLimit(dialTools),
877
- floatingTools,
878
- globalSettings: {
879
- enableSharedModalDimensions: false
880
- }
881
- };
882
- };
883
-
884
- /**
885
- * Convenience hook for accessing persisted dev tools settings. Subscribes to the internal
886
- * event bus so all surfaces stay in sync when the modal saves new preferences.
887
- *
888
- * When no saved settings exist, the hook uses the default configuration from
889
- * the DefaultConfigProvider (if available) to determine initial tool states.
890
- */
891
- /**
892
- * Session cache for the values the settings modal loads asynchronously on mount.
893
- *
894
- * Without it every open renders three times: once with defaults, then again as
895
- * each of the persisted reads (settings, active tab, storage backend) resolves —
896
- * and each of those re-renders rebuilds the whole tool list. The values cannot
897
- * change behind our back (writes go through this module, and settingsBus
898
- * broadcasts them), so after the first open we can render the real values
899
- * immediately and only re-render if a read actually came back different.
900
- */
901
- let cachedSettings = null;
902
- let cachedActiveTab = null;
903
- let cachedStorageBackend = null;
904
-
905
- /** Cheap structural equality — these objects are small and JSON-safe. */
906
- const sameSettings = (a, b) => JSON.stringify(a) === JSON.stringify(b);
907
-
908
- // Every surface that changes settings broadcasts on the bus, so listening here
909
- // keeps the cache authoritative rather than merely last-seen — otherwise a
910
- // change made while the modal was unmounted would show stale for one frame.
911
- // Registered for the app's lifetime on purpose; there is nothing to unsubscribe.
912
- settingsBus.addListener(payload => {
913
- if (payload) cachedSettings = payload;
914
- });
915
- export const useDevToolsSettings = () => {
916
- // Get team default configuration from context
917
- const {
918
- defaultFloatingTools,
919
- defaultDialTools
920
- } = useDefaultConfig();
921
-
922
- // Compute the effective defaults based on team configuration
923
- const effectiveDefaults = useMemo(() => {
924
- if (!defaultFloatingTools && !defaultDialTools) {
925
- return basicDefaultSettings;
926
- }
927
- return createDefaultsFromConfig(defaultFloatingTools, defaultDialTools);
928
- }, [defaultFloatingTools, defaultDialTools]);
929
- const [settings, setSettings] = useState(effectiveDefaults);
930
- const loadSettings = useCallback(async () => {
931
- try {
932
- const savedSettings = await persistentStorage.getItem(STORAGE_KEY);
933
- if (savedSettings) {
934
- const parsed = JSON.parse(savedSettings);
935
- const merged = mergeWithDefaults(effectiveDefaults, parsed);
936
- setSettings(merged);
937
- return;
938
- }
939
- // No saved settings - use the effective defaults (including team config)
940
- setSettings(effectiveDefaults);
941
- } catch (error) {
942
- console.error("Failed to load dev tools settings:", error);
943
- setSettings(effectiveDefaults);
944
- }
945
- }, [effectiveDefaults]);
946
- useEffect(() => {
947
- loadSettings();
948
- // Subscribe to settings changes
949
- const unsub = settingsBus.addListener(payload => {
950
- try {
951
- if (payload) {
952
- setSettings(payload);
953
- }
954
- } catch (err) {
955
- // Listener errors are intentionally swallowed to avoid breaking subscribers
956
- }
957
- });
958
- return () => {
959
- unsub();
960
- };
961
- }, [loadSettings]);
962
-
963
- // Refresh settings when component using this hook becomes visible
964
- const refreshSettings = useCallback(() => {
965
- loadSettings();
966
- }, [loadSettings]);
967
- return {
968
- settings,
969
- refreshSettings
970
- };
971
- };
972
- const styles = StyleSheet.create({
973
- container: {
974
- flex: 1,
975
- // Transparent so JsModal's night star field shows through everything.
976
- backgroundColor: "transparent"
977
- },
978
- // Header — the segmented control. The window controls are cleared
979
- // vertically by JsModal's drag-indicator strip, so this runs full width.
980
- headerRow: {
981
- flexDirection: "row",
982
- alignItems: "center",
983
- paddingLeft: night.gutter,
984
- paddingRight: night.gutter,
985
- paddingBottom: 8
986
- },
987
- // Scroll content — labeled groups on a 24pt rhythm (Everlights create screen)
988
- scrollContent: {
989
- flex: 1
990
- },
991
- scrollContainer: {
992
- paddingHorizontal: night.gutter,
993
- paddingTop: 8,
994
- paddingBottom: 24,
995
- gap: night.groupGap
996
- },
997
- // Rows
998
- toolRow: {
999
- flexDirection: "row",
1000
- alignItems: "center",
1001
- gap: 12,
1002
- paddingHorizontal: night.rowPadH,
1003
- paddingVertical: 12
1004
- },
1005
- settingRow: {
1006
- flexDirection: "row",
1007
- alignItems: "center",
1008
- gap: 10,
1009
- paddingHorizontal: night.rowPadH,
1010
- paddingVertical: night.rowPadV,
1011
- minHeight: 52
1012
- },
1013
- featureRow: {
1014
- flexDirection: "row",
1015
- alignItems: "center",
1016
- gap: 10,
1017
- paddingHorizontal: night.rowPadH,
1018
- paddingVertical: 12
1019
- },
1020
- rowDisabled: {
1021
- opacity: 0.4
1022
- },
1023
- toolIconSlot: {
1024
- width: 24,
1025
- alignItems: "center"
1026
- },
1027
- rowInfo: {
1028
- flex: 1,
1029
- gap: 2
1030
- },
1031
- rowLabel: {
1032
- color: night.color.text,
1033
- fontSize: night.font.row,
1034
- fontWeight: "500"
1035
- },
1036
- rowCaption: {
1037
- color: night.color.textTertiary,
1038
- fontSize: night.font.label
1039
- },
1040
- // Expanded body under a global-setting row
1041
- settingRowBody: {
1042
- paddingHorizontal: night.rowPadH,
1043
- paddingBottom: night.rowPadV,
1044
- gap: 6
1045
- },
1046
- settingRowBodyText: {
1047
- color: night.color.textSecondary,
1048
- fontSize: night.font.caption,
1049
- lineHeight: night.font.caption * 1.45
1050
- },
1051
- settingRowBodyHint: {
1052
- color: night.color.textTertiary,
1053
- fontSize: night.font.caption,
1054
- lineHeight: night.font.caption * 1.45
1055
- },
1056
- bodyWarning: {
1057
- color: night.color.warning
1058
- },
1059
- bodyDanger: {
1060
- color: night.color.danger
1061
- },
1062
- // Buttons that live inside a card
1063
- cardButtonWrap: {
1064
- paddingHorizontal: night.cardPad,
1065
- paddingTop: 10,
1066
- paddingBottom: night.cardPad
1067
- },
1068
- // Storage expanded key list
1069
- storageExpanded: {
1070
- paddingHorizontal: night.rowPadH,
1071
- paddingVertical: 12,
1072
- gap: 8
1073
- },
1074
- storageExpandedHeader: {
1075
- flexDirection: "row",
1076
- alignItems: "center"
1077
- },
1078
- storageExpandedTitle: {
1079
- flex: 1,
1080
- color: night.color.textSecondary,
1081
- fontSize: night.font.micro,
1082
- fontWeight: "600",
1083
- letterSpacing: 0.5
1084
- },
1085
- storageExpandedCount: {
1086
- color: night.color.textTertiary,
1087
- fontSize: night.font.micro
1088
- },
1089
- storageKeysList: {
1090
- maxHeight: 150
1091
- },
1092
- storageKeyItem: {
1093
- backgroundColor: night.color.glassElevated,
1094
- borderRadius: night.radius.segment,
1095
- paddingHorizontal: 10,
1096
- paddingVertical: 7,
1097
- marginBottom: 4
1098
- },
1099
- storageKeyText: {
1100
- color: night.color.textSecondary,
1101
- fontSize: night.font.micro,
1102
- fontFamily: monoFont
1103
- },
1104
- storageKeyEmpty: {
1105
- color: night.color.textTertiary,
1106
- fontSize: night.font.caption,
1107
- fontStyle: "italic"
1108
- },
1109
- // Footnote inline code
1110
- footnoteMono: {
1111
- fontFamily: monoFont,
1112
- fontSize: night.font.label,
1113
- color: night.color.textSecondary
1114
- }
1115
- });
1
+ "use strict";export{DevToolsSettingsModal,useDevToolsSettings}from"./DevToolsSettingsModal.shared.js";