@buoy-gg/core 1.7.7 → 2.1.1

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 (77) hide show
  1. package/lib/commonjs/floatingMenu/AppHost.js +3 -3
  2. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +25 -13
  3. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +746 -0
  4. package/lib/commonjs/floatingMenu/FloatingDevTools.js +16 -4
  5. package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +153 -0
  6. package/lib/commonjs/floatingMenu/FloatingMenu.js +8 -8
  7. package/lib/commonjs/floatingMenu/MinimizedToolsContext.js +2 -2
  8. package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +30 -0
  9. package/lib/commonjs/floatingMenu/defaultConfig.js +14 -7
  10. package/lib/commonjs/floatingMenu/dial/DialDevTools.js +12 -6
  11. package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +593 -0
  12. package/lib/commonjs/floatingMenu/floatingTools.js +218 -38
  13. package/lib/commonjs/floatingMenu/floatingTools.web.js +357 -0
  14. package/lib/commonjs/index.js +2 -2
  15. package/lib/commonjs/index.web.js +131 -0
  16. package/lib/commonjs/utils/autoDiscoverPresets.web.js +181 -0
  17. package/lib/module/floatingMenu/AppHost.js +4 -4
  18. package/lib/module/floatingMenu/DevToolsSettingsModal.js +28 -16
  19. package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +756 -0
  20. package/lib/module/floatingMenu/FloatingDevTools.js +17 -5
  21. package/lib/module/floatingMenu/FloatingDevTools.web.js +149 -0
  22. package/lib/module/floatingMenu/FloatingMenu.js +9 -9
  23. package/lib/module/floatingMenu/MinimizedToolsContext.js +3 -3
  24. package/lib/module/floatingMenu/autoDiscoverPresets.js +30 -0
  25. package/lib/module/floatingMenu/defaultConfig.js +14 -7
  26. package/lib/module/floatingMenu/dial/DialDevTools.js +13 -7
  27. package/lib/module/floatingMenu/dial/DialDevTools.web.js +590 -0
  28. package/lib/module/floatingMenu/floatingTools.js +219 -39
  29. package/lib/module/floatingMenu/floatingTools.web.js +357 -0
  30. package/lib/module/index.js +2 -2
  31. package/lib/module/index.web.js +24 -0
  32. package/lib/module/utils/autoDiscoverPresets.web.js +174 -0
  33. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  34. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts +23 -0
  35. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -0
  36. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts +1 -1
  37. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  38. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts +48 -0
  39. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +1 -0
  40. package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +1 -1
  41. package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  42. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +8 -7
  43. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +1 -1
  44. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  45. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts +26 -0
  46. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -0
  47. package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts +1 -1
  48. package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts.map +1 -1
  49. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts +27 -0
  50. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts.map +1 -0
  51. package/lib/typescript/commonjs/index.web.d.ts +20 -0
  52. package/lib/typescript/commonjs/index.web.d.ts.map +1 -0
  53. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts +58 -0
  54. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts.map +1 -0
  55. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  56. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts +23 -0
  57. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -0
  58. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts +1 -1
  59. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  60. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts +48 -0
  61. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +1 -0
  62. package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +1 -1
  63. package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  64. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +8 -7
  65. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +1 -1
  66. package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  67. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts +26 -0
  68. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -0
  69. package/lib/typescript/module/floatingMenu/floatingTools.d.ts +1 -1
  70. package/lib/typescript/module/floatingMenu/floatingTools.d.ts.map +1 -1
  71. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts +27 -0
  72. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts.map +1 -0
  73. package/lib/typescript/module/index.web.d.ts +20 -0
  74. package/lib/typescript/module/index.web.d.ts.map +1 -0
  75. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts +58 -0
  76. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts.map +1 -0
  77. package/package.json +5 -4
@@ -11,7 +11,7 @@ import { HintsProvider } from "@buoy-gg/shared-ui";
11
11
  import { MinimizedToolsProvider } from "./MinimizedToolsContext.js";
12
12
  import { validateDialConfig } from "./defaultConfig.js";
13
13
  import { DefaultConfigProvider } from "./DefaultConfigContext.js";
14
- import { LicenseManager } from "@buoy-gg/license";
14
+ import { LicenseManager, useIsPro } from "@buoy-gg/license";
15
15
 
16
16
  /**
17
17
  * Environment variable configuration
@@ -104,16 +104,20 @@ export const FloatingDevTools = ({
104
104
  defaultDialTools,
105
105
  ...props
106
106
  }) => {
107
+ // Check Pro status for production gating
108
+ const isPro = useIsPro();
109
+
107
110
  // Initialize license manager on mount
108
111
  useEffect(() => {
109
112
  LicenseManager.initialize();
110
113
  }, []);
111
114
 
112
- // Validate dial tools configuration on mount (development-time check)
113
- useEffect(() => {
115
+ // Normalize dial tools configuration (truncates to max 6 with warning if needed)
116
+ const normalizedDialTools = useMemo(() => {
114
117
  if (defaultDialTools) {
115
- validateDialConfig(defaultDialTools);
118
+ return validateDialConfig(defaultDialTools);
116
119
  }
120
+ return defaultDialTools;
117
121
  }, [defaultDialTools]);
118
122
 
119
123
  // Build config overrides if requiredEnvVars or requiredStorageKeys are provided
@@ -214,9 +218,17 @@ export const FloatingDevTools = ({
214
218
  }
215
219
  return tool.icon;
216
220
  }, [finalApps]);
221
+
222
+ // Gate: Free tier only works in development mode
223
+ // Pro users can use DevTools everywhere (dev + production)
224
+ const isDevelopment = typeof __DEV__ !== "undefined" && __DEV__;
225
+ if (!isDevelopment && !isPro) {
226
+ // Free user in production - don't render DevTools
227
+ return null;
228
+ }
217
229
  return /*#__PURE__*/_jsx(DefaultConfigProvider, {
218
230
  defaultFloatingTools: defaultFloatingTools,
219
- defaultDialTools: defaultDialTools,
231
+ defaultDialTools: normalizedDialTools,
220
232
  children: /*#__PURE__*/_jsx(HintsProvider, {
221
233
  disableHints: disableHints,
222
234
  children: /*#__PURE__*/_jsx(View, {
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * FloatingDevTools - Unified dev tools component for React DOM Web.
5
+ *
6
+ * Matches the mobile FloatingDevTools API exactly:
7
+ * - Self-contained (doesn't wrap your app)
8
+ * - Auto-discovers installed tool packages
9
+ * - Manages dial menu and settings modal state internally
10
+ *
11
+ * Usage (same as mobile):
12
+ * ```tsx
13
+ * <>
14
+ * <YourApp />
15
+ * <FloatingDevTools environment="qa" userRole="admin" />
16
+ * </>
17
+ * ```
18
+ *
19
+ * @platform React DOM Web (Vite, CRA, Next.js, Electron)
20
+ */
21
+
22
+ import { useState, useMemo, useCallback } from 'react';
23
+ import { useSettings, getToolLabel, getToolDescription, getToolColor } from '@buoy-gg/floating-tools-react';
24
+ import { autoDiscoverWithCustom, getToolsBySlot } from "../utils/autoDiscoverPresets.web.js";
25
+ import { FloatingTools, UserStatus } from "./floatingTools.web.js";
26
+ import { DialMenu } from "./dial/DialDevTools.web.js";
27
+ import { SettingsModal } from "./DevToolsSettingsModal.web.js";
28
+
29
+ // =============================
30
+ // Types
31
+ // =============================
32
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
33
+ // =============================
34
+ // Main Component
35
+ // =============================
36
+
37
+ /**
38
+ * Unified FloatingDevTools component - self-contained, no wrapping required.
39
+ *
40
+ * Matches mobile API exactly:
41
+ * ```tsx
42
+ * // Mobile
43
+ * <FloatingDevTools environment="qa" userRole={userRole} />
44
+ *
45
+ * // Web (this component)
46
+ * <FloatingDevTools environment="qa" userRole="admin" />
47
+ * ```
48
+ */
49
+ export function FloatingDevTools({
50
+ environment: _environment,
51
+ userRole,
52
+ availableEnvironments: _availableEnvironments,
53
+ onEnvironmentSwitch: _onEnvironmentSwitch,
54
+ apps,
55
+ disableHints: _disableHints
56
+ }) {
57
+ // Internal state for dial and settings
58
+ const [isDialOpen, setIsDialOpen] = useState(false);
59
+ const [isSettingsOpen, setIsSettingsOpen] = useState(false);
60
+
61
+ // Auto-discover tools and merge with custom apps
62
+ const tools = useMemo(() => autoDiscoverWithCustom(apps), [apps]);
63
+
64
+ // Convert to available tools config for settings
65
+ const availableToolsConfig = useMemo(() => tools.map(tool => ({
66
+ id: tool.id,
67
+ name: tool.name,
68
+ description: tool.description,
69
+ slot: tool.slot
70
+ })), [tools]);
71
+
72
+ // Use shared settings hook
73
+ const {
74
+ settings
75
+ } = useSettings({
76
+ availableTools: availableToolsConfig
77
+ });
78
+
79
+ // Build dial icons from enabled dial tools
80
+ const dialIcons = useMemo(() => {
81
+ const dialTools = getToolsBySlot(tools, 'dial');
82
+ const enabledDialIds = Object.entries(settings.dialTools).filter(([_, enabled]) => enabled).map(([id]) => id);
83
+ return dialTools.filter(tool => enabledDialIds.includes(tool.id)).map(tool => {
84
+ const color = tool.color || getToolColor(tool.id);
85
+ // Handle icon - can be string (emoji) or function (size) => ReactNode
86
+ let icon;
87
+ if (typeof tool.icon === 'string') {
88
+ icon = tool.icon;
89
+ } else if (typeof tool.icon === 'function') {
90
+ // It's a render function - call it with size
91
+ icon = tool.icon(32);
92
+ } else {
93
+ icon = '🔧';
94
+ }
95
+ return {
96
+ id: tool.id,
97
+ name: getToolLabel(tool.id),
98
+ icon,
99
+ color,
100
+ onPress: () => {
101
+ tool.onPress?.();
102
+ setIsDialOpen(false);
103
+ }
104
+ };
105
+ });
106
+ }, [tools, settings.dialTools]);
107
+
108
+ // Build available tools for settings modal
109
+ const availableTools = useMemo(() => tools.map(tool => ({
110
+ id: tool.id,
111
+ name: tool.name || getToolLabel(tool.id),
112
+ description: tool.description || getToolDescription(tool.id),
113
+ slot: tool.slot
114
+ })), [tools]);
115
+
116
+ // Callbacks
117
+ const handleOpenDial = useCallback(() => setIsDialOpen(true), []);
118
+ const handleCloseDial = useCallback(() => setIsDialOpen(false), []);
119
+ const handleOpenSettings = useCallback(() => {
120
+ setIsDialOpen(false);
121
+ setIsSettingsOpen(true);
122
+ }, []);
123
+ const handleCloseSettings = useCallback(() => setIsSettingsOpen(false), []);
124
+ return /*#__PURE__*/_jsxs(_Fragment, {
125
+ children: [/*#__PURE__*/_jsx(FloatingTools, {
126
+ enablePositionPersistence: true,
127
+ children: userRole && /*#__PURE__*/_jsx(UserStatus, {
128
+ userRole: userRole,
129
+ onPress: handleOpenDial
130
+ })
131
+ }), isDialOpen && /*#__PURE__*/_jsx(DialMenu, {
132
+ icons: dialIcons,
133
+ onClose: handleCloseDial,
134
+ centerLabel: "BUOY",
135
+ onCenterPress: handleOpenSettings
136
+ }), /*#__PURE__*/_jsx(SettingsModal, {
137
+ visible: isSettingsOpen,
138
+ onClose: handleCloseSettings,
139
+ availableTools: availableTools,
140
+ onSettingsChange: _newSettings => {
141
+ // Settings are already saved by the hook
142
+ }
143
+ })]
144
+ });
145
+ }
146
+
147
+ // =============================
148
+ // Re-exports for convenience
149
+ // =============================
@@ -2,10 +2,10 @@
2
2
 
3
3
  import React, { useEffect, useMemo, useRef, useState } from "react";
4
4
  import { TouchableOpacity, StyleSheet, View, Dimensions } from "react-native";
5
- import { FloatingTools, UserStatus } from "./floatingTools.js";
6
- import { DialDevTools } from "./dial/DialDevTools.js";
7
- import { EnvironmentIndicator, safeGetItem, safeSetItem, useHintsDisabled, devToolsStorageKeys, buoyColors } from "@buoy-gg/shared-ui";
8
- import { useDevToolsSettings } from "./DevToolsSettingsModal.js";
5
+ import { FloatingTools, UserStatus } from "./floatingTools";
6
+ import { DialDevTools } from "./dial/DialDevTools";
7
+ import { EnvironmentIndicator, persistentStorage, useHintsDisabled, devToolsStorageKeys, buoyColors } from "@buoy-gg/shared-ui";
8
+ import { useDevToolsSettings } from "./DevToolsSettingsModal";
9
9
  import { useAppHost } from "./AppHost.js";
10
10
  import { useDevToolsVisibility } from "./DevToolsVisibilityContext.js";
11
11
  import { toggleStateManager } from "./ToggleStateManager.js";
@@ -48,7 +48,7 @@ export const FloatingMenu = ({
48
48
  useEffect(() => {
49
49
  const loadDialState = async () => {
50
50
  try {
51
- const savedDialOpen = await safeGetItem(devToolsStorageKeys.dial.isOpen());
51
+ const savedDialOpen = await persistentStorage.getItem(devToolsStorageKeys.dial.isOpen());
52
52
  if (savedDialOpen === "true") {
53
53
  setShowDial(true);
54
54
  }
@@ -65,7 +65,7 @@ export const FloatingMenu = ({
65
65
  useEffect(() => {
66
66
  // Only persist after initial state is loaded to avoid overwriting with default
67
67
  if (!dialStateLoaded) return;
68
- safeSetItem(devToolsStorageKeys.dial.isOpen(), showDial ? "true" : "false").catch(error => {
68
+ persistentStorage.setItem(devToolsStorageKeys.dial.isOpen(), showDial ? "true" : "false").catch(error => {
69
69
  // Failed to save dial state - continue without persistence
70
70
  console.warn("Failed to save dial state:", error);
71
71
  });
@@ -92,7 +92,7 @@ export const FloatingMenu = ({
92
92
  }
93
93
  const checkOnboarding = async () => {
94
94
  try {
95
- const hasSeenOnboarding = await safeGetItem(FLOATING_MENU_ONBOARDING_KEY);
95
+ const hasSeenOnboarding = await persistentStorage.getItem(FLOATING_MENU_ONBOARDING_KEY);
96
96
  if (!hasSeenOnboarding) {
97
97
  // Small delay to let the UI settle before showing tooltip
98
98
  setTimeout(() => {
@@ -159,7 +159,7 @@ export const FloatingMenu = ({
159
159
  // Filter function for floating tools based on settings
160
160
  const isFloatingEnabled = id => {
161
161
  if (!devToolsSettings) return false;
162
- // Default to disabled for tools without explicit preferences
162
+ // Floating tools require explicit opt-in (unlike dial tools which auto-enable)
163
163
  return devToolsSettings.floatingTools[id] ?? false;
164
164
  };
165
165
 
@@ -197,7 +197,7 @@ export const FloatingMenu = ({
197
197
  setOnboardingStep(null);
198
198
 
199
199
  // Save to storage asynchronously in the background
200
- safeSetItem(FLOATING_MENU_ONBOARDING_KEY, "true").catch(error => {
200
+ persistentStorage.setItem(FLOATING_MENU_ONBOARDING_KEY, "true").catch(error => {
201
201
  // Silently fail - user already saw onboarding, just won't persist
202
202
  console.warn("Failed to save onboarding state:", error);
203
203
  });
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { createContext, useContext, useState, useCallback, useEffect, useRef, useMemo } from "react";
4
4
  import { Dimensions } from "react-native";
5
- import { safeGetItem, safeSetItem, getSafeAreaInsets } from "@buoy-gg/shared-ui";
5
+ import { persistentStorage, getSafeAreaInsets } from "@buoy-gg/shared-ui";
6
6
 
7
7
  // ============================================================================
8
8
  // Types
@@ -107,7 +107,7 @@ export function MinimizedToolsProvider({
107
107
  useEffect(() => {
108
108
  const restoreMinimizedTools = async () => {
109
109
  try {
110
- const saved = await safeGetItem(STORAGE_KEY);
110
+ const saved = await persistentStorage.getItem(STORAGE_KEY);
111
111
  if (saved) {
112
112
  const serialized = JSON.parse(saved);
113
113
  // Reconstruct tools with icons
@@ -137,7 +137,7 @@ export function MinimizedToolsProvider({
137
137
  icon,
138
138
  ...rest
139
139
  }) => rest);
140
- safeSetItem(STORAGE_KEY, JSON.stringify(serialized));
140
+ persistentStorage.setItem(STORAGE_KEY, JSON.stringify(serialized));
141
141
  }, PERSISTENCE_DELAY);
142
142
  return () => {
143
143
  if (persistenceTimeoutRef.current) {
@@ -174,6 +174,36 @@ export function autoDiscoverPresets() {
174
174
  return null;
175
175
  }
176
176
  }
177
+ },
178
+ // Redux DevTools
179
+ {
180
+ name: "@buoy-gg/redux",
181
+ loader: () => {
182
+ try {
183
+ // @ts-ignore - Dynamic import that may not exist
184
+ const {
185
+ reduxToolPreset
186
+ } = require("@buoy-gg/redux");
187
+ return reduxToolPreset;
188
+ } catch {
189
+ return null;
190
+ }
191
+ }
192
+ },
193
+ // Events Timeline
194
+ {
195
+ name: "@buoy-gg/events",
196
+ loader: () => {
197
+ try {
198
+ // @ts-ignore - Dynamic import that may not exist
199
+ const {
200
+ eventsToolPreset
201
+ } = require("@buoy-gg/events");
202
+ return eventsToolPreset;
203
+ } catch {
204
+ return null;
205
+ }
206
+ }
177
207
  }];
178
208
 
179
209
  // Attempt to load each preset
@@ -66,27 +66,34 @@ export const MAX_DIAL_TOOLS = 6;
66
66
  */
67
67
 
68
68
  /**
69
- * Validates that a dial configuration doesn't exceed the maximum allowed tools.
70
- * Throws an error with helpful message if validation fails.
69
+ * Validates and normalizes a dial configuration to not exceed the maximum allowed tools.
70
+ * If more than MAX_DIAL_TOOLS are provided, logs a warning and truncates to first 6 tools.
71
71
  *
72
72
  * @param tools - Array of dial tool IDs to validate
73
- * @throws Error if more than MAX_DIAL_TOOLS are provided
73
+ * @returns The original array if valid, or truncated array if too many tools
74
74
  *
75
75
  * @example
76
76
  * ```tsx
77
- * // This is valid
77
+ * // This returns as-is
78
78
  * validateDialConfig(['env', 'network', 'storage']);
79
+ * // Returns: ['env', 'network', 'storage']
79
80
  *
80
- * // This throws an error
81
+ * // This truncates and warns
81
82
  * validateDialConfig(['env', 'network', 'storage', 'query', 'route-events', 'debug-borders', 'benchmark']);
82
- * // Error: "Dial menu default configuration has 7 tools, but maximum is 6..."
83
+ * // Console warning, returns: ['env', 'network', 'storage', 'query', 'route-events', 'debug-borders']
83
84
  * ```
84
85
  */
85
86
  export function validateDialConfig(tools) {
86
87
  if (tools.length > MAX_DIAL_TOOLS) {
87
88
  const toolList = tools.map(t => `"${t}"`).join(', ');
88
- throw new Error(`Dial menu default configuration has ${tools.length} tools, but maximum is ${MAX_DIAL_TOOLS}. ` + `Tools provided: [${toolList}]. ` + `Please remove ${tools.length - MAX_DIAL_TOOLS} tool(s) from defaultDialTools.`);
89
+ // console.warn(
90
+ // `[React Buoy] Dial menu configuration has ${tools.length} tools, but maximum is ${MAX_DIAL_TOOLS}. ` +
91
+ // `Tools provided: [${toolList}]. ` +
92
+ // `Only the first ${MAX_DIAL_TOOLS} tools will be shown.`
93
+ // );
94
+ return tools.slice(0, MAX_DIAL_TOOLS);
89
95
  }
96
+ return tools;
90
97
  }
91
98
 
92
99
  /**
@@ -4,8 +4,8 @@ import { useEffect, useMemo, useRef, useState } from "react";
4
4
  import { Pressable, StyleSheet, View, Dimensions, Text, Animated, Easing } from "react-native";
5
5
  // Icons are provided by installedApps; no direct icon imports here.
6
6
  import { DialIcon } from "./DialIcon.js";
7
- import { safeGetItem, safeSetItem, useHintsDisabled, devToolsStorageKeys, buoyColors } from "@buoy-gg/shared-ui";
8
- import { DevToolsSettingsModal, useDevToolsSettings } from "../DevToolsSettingsModal.js";
7
+ import { persistentStorage, useHintsDisabled, devToolsStorageKeys, buoyColors } from "@buoy-gg/shared-ui";
8
+ import { DevToolsSettingsModal, useDevToolsSettings } from "../DevToolsSettingsModal";
9
9
  import { useIsPro } from "@buoy-gg/license";
10
10
  import { useAppHost } from "../AppHost.js";
11
11
  import { OnboardingTooltip } from "./OnboardingTooltip.js";
@@ -55,7 +55,7 @@ export const DialDevTools = ({
55
55
  useEffect(() => {
56
56
  const loadSettingsModalState = async () => {
57
57
  try {
58
- const savedModalOpen = await safeGetItem(devToolsStorageKeys.settings.modalOpen());
58
+ const savedModalOpen = await persistentStorage.getItem(devToolsStorageKeys.settings.modalOpen());
59
59
  if (savedModalOpen === "true") {
60
60
  setIsSettingsModalOpen(true);
61
61
  }
@@ -72,7 +72,7 @@ export const DialDevTools = ({
72
72
  useEffect(() => {
73
73
  // Only persist after initial state is loaded to avoid overwriting with default
74
74
  if (!settingsModalStateLoaded) return;
75
- safeSetItem(devToolsStorageKeys.settings.modalOpen(), isSettingsModalOpen ? "true" : "false").catch(error => {
75
+ persistentStorage.setItem(devToolsStorageKeys.settings.modalOpen(), isSettingsModalOpen ? "true" : "false").catch(error => {
76
76
  // Failed to save settings modal state - continue without persistence
77
77
  console.warn("Failed to save settings modal state:", error);
78
78
  });
@@ -107,7 +107,7 @@ export const DialDevTools = ({
107
107
  }
108
108
  const checkOnboarding = async () => {
109
109
  try {
110
- const hasSeenTooltip = await safeGetItem(ONBOARDING_STORAGE_KEY);
110
+ const hasSeenTooltip = await persistentStorage.getItem(ONBOARDING_STORAGE_KEY);
111
111
  if (!hasSeenTooltip) {
112
112
  // Small delay to let the entrance animations play first
113
113
  setTimeout(() => {
@@ -153,8 +153,14 @@ export const DialDevTools = ({
153
153
 
154
154
  // Map data-driven apps to dial icons, inserting empty slots for disabled items
155
155
  const dialApps = apps.filter(a => (a.slot ?? "both") !== "row");
156
+
157
+ // Check if settings are "virgin" (user hasn't customized dial tools yet)
158
+ // If no explicit settings exist, auto-enable all dial tools by default
159
+ const dialToolsKeys = settings?.dialTools ? Object.keys(settings.dialTools) : [];
160
+ const hasDialSettings = dialToolsKeys.length > 0;
156
161
  const isDialEnabled = id => {
157
- if (!settings) return false;
162
+ // No settings or empty dialTools = auto-enable all dial tools by default
163
+ if (!settings?.dialTools || !hasDialSettings) return true;
158
164
  return settings.dialTools[id] ?? false;
159
165
  };
160
166
  const createEmptySlot = slotIndex => ({
@@ -400,7 +406,7 @@ export const DialDevTools = ({
400
406
  setShowOnboardingTooltip(false);
401
407
 
402
408
  // Save to storage asynchronously in the background
403
- safeSetItem(ONBOARDING_STORAGE_KEY, "true").catch(error => {
409
+ persistentStorage.setItem(ONBOARDING_STORAGE_KEY, "true").catch(error => {
404
410
  // Silently fail - user already saw onboarding, just won't persist
405
411
  console.warn("Failed to save dial onboarding state:", error);
406
412
  });