@buoy-gg/core 7.0.15 → 7.0.16
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.
- package/lib/commonjs/floatingMenu/AppHost.web.js +359 -0
- package/lib/commonjs/floatingMenu/AppHostLogic.js +6 -0
- package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +787 -418
- package/lib/commonjs/floatingMenu/FloatingDevTools.js +1 -1
- package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +244 -36
- package/lib/commonjs/floatingMenu/FloatingMenu.js +2 -2
- package/lib/commonjs/floatingMenu/MinimizedToolsContext.js +2 -3
- package/lib/commonjs/floatingMenu/MinimizedToolsStack.web.js +287 -0
- package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +16 -0
- package/lib/commonjs/floatingMenu/autoExternalSync.js +9 -0
- package/lib/commonjs/floatingMenu/dial/DialDevTools.js +7 -4
- package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +373 -231
- package/lib/commonjs/floatingMenu/dial/DialIcon.js +25 -3
- package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.js +1 -1
- package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.web.js +154 -0
- package/lib/commonjs/floatingMenu/dial/onboardingConstants.web.js +34 -0
- package/lib/commonjs/floatingMenu/floatingTools.js +3 -3
- package/lib/commonjs/floatingMenu/floatingTools.web.js +191 -28
- package/lib/commonjs/index.js +2 -2
- package/lib/commonjs/index.web.js +19 -0
- package/lib/commonjs/utils/autoDiscoverPresets.web.js +50 -5
- package/lib/module/floatingMenu/AppHost.web.js +351 -0
- package/lib/module/floatingMenu/AppHostLogic.js +6 -0
- package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +792 -422
- package/lib/module/floatingMenu/FloatingDevTools.js +2 -2
- package/lib/module/floatingMenu/FloatingDevTools.web.js +247 -38
- package/lib/module/floatingMenu/FloatingMenu.js +2 -2
- package/lib/module/floatingMenu/MinimizedToolsContext.js +2 -3
- package/lib/module/floatingMenu/MinimizedToolsStack.web.js +284 -0
- package/lib/module/floatingMenu/autoDiscoverPresets.js +16 -0
- package/lib/module/floatingMenu/autoExternalSync.js +9 -0
- package/lib/module/floatingMenu/dial/DialDevTools.js +8 -5
- package/lib/module/floatingMenu/dial/DialDevTools.web.js +375 -233
- package/lib/module/floatingMenu/dial/DialIcon.js +26 -4
- package/lib/module/floatingMenu/dial/OnboardingTooltip.js +1 -1
- package/lib/module/floatingMenu/dial/OnboardingTooltip.web.js +149 -0
- package/lib/module/floatingMenu/dial/onboardingConstants.web.js +27 -0
- package/lib/module/floatingMenu/floatingTools.js +3 -3
- package/lib/module/floatingMenu/floatingTools.web.js +190 -28
- package/lib/module/index.js +2 -2
- package/lib/module/index.web.js +5 -0
- package/lib/module/utils/autoDiscoverPresets.web.js +53 -7
- package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts +38 -0
- package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts +21 -1
- package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts +5 -2
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts +2 -14
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts +2 -20
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.web.d.ts +21 -0
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts +16 -2
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.web.d.ts +9 -0
- package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts +13 -0
- package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts +29 -2
- package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +1 -0
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts +2 -0
- package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/AppHost.web.d.ts +38 -0
- package/lib/typescript/module/floatingMenu/AppHost.web.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts +21 -1
- package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts +5 -2
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts +2 -14
- package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts +2 -20
- package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/MinimizedToolsStack.web.d.ts +21 -0
- package/lib/typescript/module/floatingMenu/MinimizedToolsStack.web.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts +16 -2
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.web.d.ts +9 -0
- package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts +13 -0
- package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts +29 -2
- package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +1 -0
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts +2 -0
- package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useMemo, useCallback, useEffect, useState } from "react";
|
|
4
4
|
import { View, StyleSheet } from "react-native";
|
|
5
|
-
import { AppHostProvider } from "./AppHost
|
|
5
|
+
import { AppHostProvider } from "./AppHost";
|
|
6
6
|
import { FloatingMenu } from "./FloatingMenu.js";
|
|
7
|
-
import { AppOverlay } from "./AppHost
|
|
7
|
+
import { AppOverlay } from "./AppHost";
|
|
8
8
|
import { autoDiscoverPresets, autoDiscoverPresetsWithCustom } from "./autoDiscoverPresets.js";
|
|
9
9
|
import { DevToolsVisibilityProvider } from "./DevToolsVisibilityContext.js";
|
|
10
10
|
import { reportOptionalRequireError } from "./optionalRequire.js";
|
|
@@ -19,50 +19,107 @@
|
|
|
19
19
|
* @platform React DOM Web (Vite, CRA, Next.js, Electron)
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import { useState, useMemo, useCallback } from 'react';
|
|
22
|
+
import { useState, useMemo, useCallback, useEffect, useRef } from 'react';
|
|
23
23
|
import { useSettings, getToolLabel, getToolDescription, getToolColor } from '@buoy-gg/floating-tools-react';
|
|
24
|
+
import { persistentStorage, devToolsStorageKeys, EnvironmentIndicator, EnvironmentSelectorInline } from '@buoy-gg/shared-ui';
|
|
24
25
|
import { autoDiscoverWithCustom, getToolsBySlot } from "../utils/autoDiscoverPresets.web.js";
|
|
25
26
|
import { FloatingTools, UserStatus } from "./floatingTools.web.js";
|
|
26
27
|
import { DialMenu } from "./dial/DialDevTools.web.js";
|
|
27
28
|
import { getRankedToolIds, recordToolUsage } from "./dial/dialUsageStore.js";
|
|
29
|
+
import { OnboardingTooltip } from "./dial/OnboardingTooltip.web.js";
|
|
28
30
|
import { SettingsModal } from "./DevToolsSettingsModal.web.js";
|
|
31
|
+
import { AppHostProvider, AppOverlay, useAppHost } from "./AppHost.web.js";
|
|
32
|
+
import { MinimizedToolsStack } from "./MinimizedToolsStack.web.js";
|
|
33
|
+
|
|
34
|
+
// native FloatingMenu.tsx TOOLTIP_SHOWN_KEY
|
|
35
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
36
|
+
const MENU_TOOLTIP_KEY = '@react_buoy_floating_menu_tooltip_shown';
|
|
37
|
+
|
|
38
|
+
// Same localStorage adapter the settings modal uses — without it, useSettings
|
|
39
|
+
// never loads persisted settings and this instance sits on defaults across
|
|
40
|
+
// launches (live changes still arrive via the settings event bus).
|
|
41
|
+
const webSettingsStorage = {
|
|
42
|
+
getItem: key => localStorage.getItem(key),
|
|
43
|
+
setItem: (key, value) => localStorage.setItem(key, value)
|
|
44
|
+
};
|
|
29
45
|
|
|
30
46
|
// =============================
|
|
31
47
|
// Types
|
|
32
48
|
// =============================
|
|
33
|
-
|
|
49
|
+
|
|
50
|
+
// =============================
|
|
51
|
+
// MenuLauncherIcon — native FloatingMenu.tsx:446-478: 3×3 dot grid rendered
|
|
52
|
+
// when no userRole is set, so the dial/settings stay reachable.
|
|
53
|
+
// =============================
|
|
54
|
+
function MenuLauncherIcon({
|
|
55
|
+
size = 14,
|
|
56
|
+
color = '#20C997'
|
|
57
|
+
}) {
|
|
58
|
+
const dot = Math.max(2, size / 4);
|
|
59
|
+
const gap = Math.max(1, size / 16);
|
|
60
|
+
return /*#__PURE__*/_jsx("div", {
|
|
61
|
+
style: {
|
|
62
|
+
display: 'grid',
|
|
63
|
+
gridTemplateColumns: `repeat(3, ${dot}px)`,
|
|
64
|
+
gap,
|
|
65
|
+
width: size,
|
|
66
|
+
height: size,
|
|
67
|
+
alignContent: 'center',
|
|
68
|
+
justifyContent: 'center'
|
|
69
|
+
},
|
|
70
|
+
children: Array.from({
|
|
71
|
+
length: 9
|
|
72
|
+
}).map((_, i) => /*#__PURE__*/_jsx("div", {
|
|
73
|
+
style: {
|
|
74
|
+
width: dot,
|
|
75
|
+
height: dot,
|
|
76
|
+
borderRadius: dot / 2,
|
|
77
|
+
backgroundColor: color
|
|
78
|
+
}
|
|
79
|
+
}, i))
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
34
83
|
// =============================
|
|
35
84
|
// Main Component
|
|
36
85
|
// =============================
|
|
37
86
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
*/
|
|
50
|
-
export function FloatingDevTools({
|
|
51
|
-
environment: _environment,
|
|
87
|
+
export function FloatingDevTools(props) {
|
|
88
|
+
// The tool host wraps everything so dial presses can open tool components
|
|
89
|
+
// into the AppOverlay (web twin of the native AppHostProvider/AppOverlay).
|
|
90
|
+
return /*#__PURE__*/_jsx(AppHostProvider, {
|
|
91
|
+
children: /*#__PURE__*/_jsx(FloatingDevToolsInner, {
|
|
92
|
+
...props
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function FloatingDevToolsInner({
|
|
97
|
+
environment,
|
|
52
98
|
userRole,
|
|
53
|
-
availableEnvironments
|
|
54
|
-
onEnvironmentSwitch
|
|
99
|
+
availableEnvironments,
|
|
100
|
+
onEnvironmentSwitch,
|
|
55
101
|
apps,
|
|
56
|
-
disableHints
|
|
102
|
+
disableHints = false,
|
|
57
103
|
headless = false
|
|
58
104
|
}) {
|
|
59
105
|
// Internal state for dial and settings
|
|
60
106
|
const [isDialOpen, setIsDialOpen] = useState(false);
|
|
61
107
|
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
|
|
108
|
+
const stateRestoredRef = useRef(false);
|
|
109
|
+
const appHost = useAppHost();
|
|
62
110
|
|
|
63
111
|
// Auto-discover tools and merge with custom apps
|
|
64
112
|
const tools = useMemo(() => autoDiscoverWithCustom(apps), [apps]);
|
|
65
113
|
|
|
114
|
+
// Let the host restore `@react_buoy_open_apps` from the previous session
|
|
115
|
+
// once it knows which tools exist (native registerApps parity).
|
|
116
|
+
const {
|
|
117
|
+
registerApps
|
|
118
|
+
} = appHost;
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
registerApps(tools);
|
|
121
|
+
}, [registerApps, tools]);
|
|
122
|
+
|
|
66
123
|
// Convert to available tools config for settings
|
|
67
124
|
const availableToolsConfig = useMemo(() => tools.map(tool => ({
|
|
68
125
|
id: tool.id,
|
|
@@ -72,11 +129,62 @@ export function FloatingDevTools({
|
|
|
72
129
|
})), [tools]);
|
|
73
130
|
|
|
74
131
|
// Register available tools with the shared settings hook (used by the
|
|
75
|
-
// settings modal
|
|
76
|
-
|
|
77
|
-
|
|
132
|
+
// settings modal and the bubble-row visibility gating).
|
|
133
|
+
const {
|
|
134
|
+
settings
|
|
135
|
+
} = useSettings({
|
|
136
|
+
availableTools: availableToolsConfig,
|
|
137
|
+
storage: webSettingsStorage
|
|
78
138
|
});
|
|
79
139
|
|
|
140
|
+
// Dial/settings open-state persistence — native FloatingMenu.tsx:95-122 and
|
|
141
|
+
// DialDevTools.tsx:136-164 restore these across reloads.
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
let cancelled = false;
|
|
144
|
+
const restore = async () => {
|
|
145
|
+
const [dialOpen, settingsOpen] = await Promise.all([persistentStorage.getItem(devToolsStorageKeys.dial.isOpen()), persistentStorage.getItem(devToolsStorageKeys.settings.modalOpen())]);
|
|
146
|
+
if (cancelled) return;
|
|
147
|
+
if (dialOpen === 'true') setIsDialOpen(true);
|
|
148
|
+
if (settingsOpen === 'true') {
|
|
149
|
+
setIsDialOpen(true); // settings lives above the dial (native structure)
|
|
150
|
+
setIsSettingsOpen(true);
|
|
151
|
+
}
|
|
152
|
+
stateRestoredRef.current = true;
|
|
153
|
+
};
|
|
154
|
+
void restore();
|
|
155
|
+
return () => {
|
|
156
|
+
cancelled = true;
|
|
157
|
+
};
|
|
158
|
+
}, []);
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (!stateRestoredRef.current) return;
|
|
161
|
+
void persistentStorage.setItem(devToolsStorageKeys.dial.isOpen(), isDialOpen ? 'true' : 'false');
|
|
162
|
+
}, [isDialOpen]);
|
|
163
|
+
useEffect(() => {
|
|
164
|
+
if (!stateRestoredRef.current) return;
|
|
165
|
+
void persistentStorage.setItem(devToolsStorageKeys.settings.modalOpen(), isSettingsOpen ? 'true' : 'false');
|
|
166
|
+
}, [isSettingsOpen]);
|
|
167
|
+
|
|
168
|
+
// Shared open path for dial + bubble-row tools.
|
|
169
|
+
const openTool = useCallback(tool => {
|
|
170
|
+
void recordToolUsage(tool.id);
|
|
171
|
+
if (tool.component) {
|
|
172
|
+
const dockIcon = typeof tool.icon === 'function' ? tool.icon(20) : tool.icon;
|
|
173
|
+
appHost.open({
|
|
174
|
+
id: tool.id,
|
|
175
|
+
title: tool.name || getToolLabel(tool.id),
|
|
176
|
+
component: tool.component,
|
|
177
|
+
props: tool.props,
|
|
178
|
+
launchMode: tool.launchMode || 'self-modal',
|
|
179
|
+
singleton: tool.singleton ?? true,
|
|
180
|
+
icon: dockIcon,
|
|
181
|
+
color: tool.color || getToolColor(tool.id)
|
|
182
|
+
});
|
|
183
|
+
} else {
|
|
184
|
+
tool.onPress?.();
|
|
185
|
+
}
|
|
186
|
+
}, [appHost]);
|
|
187
|
+
|
|
80
188
|
// Build dial icons for every dial-eligible tool. The dial paginates and
|
|
81
189
|
// ranks them by usage, so there is no per-tool show/hide setting.
|
|
82
190
|
const dialIcons = useMemo(() => {
|
|
@@ -91,22 +199,26 @@ export function FloatingDevTools({
|
|
|
91
199
|
// It's a render function - call it with size
|
|
92
200
|
icon = tool.icon(32);
|
|
93
201
|
} else {
|
|
94
|
-
icon =
|
|
202
|
+
icon = null;
|
|
95
203
|
}
|
|
96
204
|
return {
|
|
97
205
|
id: tool.id,
|
|
98
|
-
name
|
|
206
|
+
// The tool's own name wins (native parity); the registry label is
|
|
207
|
+
// the fallback for preset tools that don't set one.
|
|
208
|
+
name: tool.name || getToolLabel(tool.id),
|
|
99
209
|
icon,
|
|
210
|
+
// Preset tools with no component and no onPress can't do anything on
|
|
211
|
+
// web — render them like native's uninstalled tools ("Unavailable"
|
|
212
|
+
// caption, non-interactive) instead of a tile that silently no-ops.
|
|
213
|
+
unavailable: !tool.component && !tool.onPress,
|
|
100
214
|
color,
|
|
101
215
|
onPress: () => {
|
|
102
|
-
|
|
103
|
-
void recordToolUsage(tool.id);
|
|
104
|
-
tool.onPress?.();
|
|
216
|
+
openTool(tool);
|
|
105
217
|
setIsDialOpen(false);
|
|
106
218
|
}
|
|
107
219
|
};
|
|
108
220
|
});
|
|
109
|
-
}, [tools]);
|
|
221
|
+
}, [tools, openTool]);
|
|
110
222
|
|
|
111
223
|
// Snapshot the usage-ranked order each time the dial opens. It stays stable
|
|
112
224
|
// while open so icons don't jump positions mid-interaction.
|
|
@@ -116,6 +228,10 @@ export function FloatingDevTools({
|
|
|
116
228
|
return getRankedToolIds(dialIcons.map(i => i.id)).map(id => byId.get(id)).filter(i => Boolean(i));
|
|
117
229
|
}, [isDialOpen, dialIcons]);
|
|
118
230
|
|
|
231
|
+
// Bubble-row tools — native FloatingMenu.tsx:349-386: slot !== 'dial',
|
|
232
|
+
// explicitly enabled in settings, rendered as small icon buttons.
|
|
233
|
+
const rowTools = useMemo(() => getToolsBySlot(tools, 'row').filter(tool => settings.floatingTools[tool.id] === true && (tool.component || tool.onPress)), [tools, settings.floatingTools]);
|
|
234
|
+
|
|
119
235
|
// Build available tools for settings modal
|
|
120
236
|
const availableTools = useMemo(() => tools.map(tool => ({
|
|
121
237
|
id: tool.id,
|
|
@@ -124,31 +240,124 @@ export function FloatingDevTools({
|
|
|
124
240
|
slot: tool.slot
|
|
125
241
|
})), [tools]);
|
|
126
242
|
|
|
243
|
+
// Welcome tooltip — native FloatingMenu.tsx:134-157: 1000ms after mount,
|
|
244
|
+
// once ever, only while nothing else is open; the bubble centers under the
|
|
245
|
+
// arrow while it shows.
|
|
246
|
+
const [showWelcomeTooltip, setShowWelcomeTooltip] = useState(false);
|
|
247
|
+
const isAnyToolOpen = appHost.openApps.some(app => !app.minimized);
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
if (disableHints) return;
|
|
250
|
+
let cancelled = false;
|
|
251
|
+
const timer = setTimeout(async () => {
|
|
252
|
+
const seen = await persistentStorage.getItem(MENU_TOOLTIP_KEY);
|
|
253
|
+
if (!cancelled && !seen) setShowWelcomeTooltip(true);
|
|
254
|
+
}, 1000);
|
|
255
|
+
return () => {
|
|
256
|
+
cancelled = true;
|
|
257
|
+
clearTimeout(timer);
|
|
258
|
+
};
|
|
259
|
+
}, [disableHints]);
|
|
260
|
+
const dismissWelcomeTooltip = useCallback(() => {
|
|
261
|
+
setShowWelcomeTooltip(false);
|
|
262
|
+
void persistentStorage.setItem(MENU_TOOLTIP_KEY, 'true');
|
|
263
|
+
}, []);
|
|
264
|
+
|
|
127
265
|
// Callbacks
|
|
128
|
-
const handleOpenDial = useCallback(() =>
|
|
129
|
-
|
|
130
|
-
|
|
266
|
+
const handleOpenDial = useCallback(() => {
|
|
267
|
+
// Opening the dial dismisses the welcome tooltip (native handleDialOpen).
|
|
268
|
+
if (showWelcomeTooltip) dismissWelcomeTooltip();
|
|
269
|
+
setIsDialOpen(true);
|
|
270
|
+
}, [showWelcomeTooltip, dismissWelcomeTooltip]);
|
|
271
|
+
const handleCloseDial = useCallback(() => {
|
|
131
272
|
setIsDialOpen(false);
|
|
132
|
-
setIsSettingsOpen(
|
|
273
|
+
setIsSettingsOpen(false); // settings lives above the dial
|
|
274
|
+
}, []);
|
|
275
|
+
// Center press toggles settings while the dial STAYS OPEN underneath —
|
|
276
|
+
// the center label flips to CLOSE/SETTINGS (native DialDevTools behavior).
|
|
277
|
+
const handleCenterPress = useCallback(() => {
|
|
278
|
+
setIsSettingsOpen(open => !open);
|
|
133
279
|
}, []);
|
|
134
280
|
const handleCloseSettings = useCallback(() => setIsSettingsOpen(false), []);
|
|
281
|
+
const showEnvironmentSelector = Boolean(availableEnvironments?.length && onEnvironmentSwitch);
|
|
282
|
+
const environmentEnabled = settings.floatingTools.environment !== false;
|
|
283
|
+
const welcomeActive = showWelcomeTooltip && !isDialOpen && !isAnyToolOpen;
|
|
284
|
+
const hasMinimizedTools = appHost.openApps.some(app => app.minimized && app.launchMode !== 'toggle-only');
|
|
135
285
|
|
|
136
286
|
// Headless: desktop sync is native-only, so there is nothing to mount on
|
|
137
287
|
// web — accept the prop for API parity and render nothing. (After all
|
|
138
288
|
// hooks so hook order is preserved.)
|
|
139
289
|
if (headless) return null;
|
|
140
290
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
141
|
-
children: [/*#__PURE__*/_jsx(
|
|
142
|
-
|
|
143
|
-
|
|
291
|
+
children: [welcomeActive && /*#__PURE__*/_jsx("div", {
|
|
292
|
+
style: {
|
|
293
|
+
position: 'fixed',
|
|
294
|
+
inset: 0,
|
|
295
|
+
backgroundColor: 'rgba(0,0,0,0.85)',
|
|
296
|
+
zIndex: 10000
|
|
297
|
+
}
|
|
298
|
+
}), /*#__PURE__*/_jsxs(FloatingTools, {
|
|
299
|
+
enablePositionPersistence: !welcomeActive,
|
|
300
|
+
pushToSide: isDialOpen || isAnyToolOpen,
|
|
301
|
+
suspendPointerEvents: isDialOpen,
|
|
302
|
+
centerOnboarding: welcomeActive,
|
|
303
|
+
minimizedStack: hasMinimizedTools ? /*#__PURE__*/_jsx(MinimizedToolsStack, {}) : undefined,
|
|
304
|
+
hasMinimizedStack: hasMinimizedTools,
|
|
305
|
+
children: [environment && environmentEnabled && !showEnvironmentSelector && /*#__PURE__*/_jsx(EnvironmentIndicator, {
|
|
306
|
+
environment: environment
|
|
307
|
+
}), showEnvironmentSelector && environmentEnabled && /*#__PURE__*/_jsx(EnvironmentSelectorInline, {
|
|
308
|
+
currentEnvironment: environment ?? 'local',
|
|
309
|
+
availableEnvironments: availableEnvironments,
|
|
310
|
+
onSelect: onEnvironmentSwitch
|
|
311
|
+
}), userRole ? /*#__PURE__*/_jsx(UserStatus, {
|
|
144
312
|
userRole: userRole,
|
|
145
313
|
onPress: handleOpenDial
|
|
146
|
-
})
|
|
314
|
+
}) :
|
|
315
|
+
/*#__PURE__*/
|
|
316
|
+
// native MenuLauncherIcon fallback: dial stays reachable without a
|
|
317
|
+
// userRole pill.
|
|
318
|
+
_jsx("button", {
|
|
319
|
+
"aria-label": "Open dev tools",
|
|
320
|
+
onClick: handleOpenDial,
|
|
321
|
+
style: {
|
|
322
|
+
display: 'flex',
|
|
323
|
+
alignItems: 'center',
|
|
324
|
+
justifyContent: 'center',
|
|
325
|
+
padding: '6px 8px',
|
|
326
|
+
background: 'none',
|
|
327
|
+
border: 'none',
|
|
328
|
+
cursor: 'pointer'
|
|
329
|
+
},
|
|
330
|
+
children: /*#__PURE__*/_jsx(MenuLauncherIcon, {})
|
|
331
|
+
}), rowTools.map(tool =>
|
|
332
|
+
/*#__PURE__*/
|
|
333
|
+
// native FloatingMenu fab: paddingH 6, paddingV 4, r6, transparent
|
|
334
|
+
_jsx("button", {
|
|
335
|
+
"aria-label": tool.name || getToolLabel(tool.id),
|
|
336
|
+
title: tool.description,
|
|
337
|
+
onClick: () => openTool(tool),
|
|
338
|
+
style: {
|
|
339
|
+
display: 'flex',
|
|
340
|
+
alignItems: 'center',
|
|
341
|
+
justifyContent: 'center',
|
|
342
|
+
padding: '4px 6px',
|
|
343
|
+
borderRadius: 6,
|
|
344
|
+
background: 'none',
|
|
345
|
+
border: 'none',
|
|
346
|
+
cursor: 'pointer'
|
|
347
|
+
},
|
|
348
|
+
children: typeof tool.icon === 'function' ? tool.icon(16) : tool.icon
|
|
349
|
+
}, tool.id))]
|
|
350
|
+
}), welcomeActive && /*#__PURE__*/_jsx(OnboardingTooltip, {
|
|
351
|
+
title: "Welcome to Buoy!",
|
|
352
|
+
message: "Grab and position this menu wherever you want, then tap the icon to open your tools.",
|
|
353
|
+
onDismiss: dismissWelcomeTooltip
|
|
147
354
|
}), isDialOpen && /*#__PURE__*/_jsx(DialMenu, {
|
|
148
355
|
icons: rankedDialIcons,
|
|
149
356
|
onClose: handleCloseDial,
|
|
150
357
|
centerLabel: "BUOY",
|
|
151
|
-
onCenterPress:
|
|
358
|
+
onCenterPress: handleCenterPress,
|
|
359
|
+
settingsOpen: isSettingsOpen,
|
|
360
|
+
hintsDisabled: disableHints
|
|
152
361
|
}), /*#__PURE__*/_jsx(SettingsModal, {
|
|
153
362
|
visible: isSettingsOpen,
|
|
154
363
|
onClose: handleCloseSettings,
|
|
@@ -156,7 +365,7 @@ export function FloatingDevTools({
|
|
|
156
365
|
onSettingsChange: _newSettings => {
|
|
157
366
|
// Settings are already saved by the hook
|
|
158
367
|
}
|
|
159
|
-
})]
|
|
368
|
+
}), /*#__PURE__*/_jsx(AppOverlay, {})]
|
|
160
369
|
});
|
|
161
370
|
}
|
|
162
371
|
|
|
@@ -7,10 +7,10 @@ import { FloatingTools, UserStatus } from "./floatingTools";
|
|
|
7
7
|
import { DialDevTools } from "./dial/DialDevTools";
|
|
8
8
|
import { EnvironmentIndicator, persistentStorage, useHintsDisabled, devToolsStorageKeys, buoyColors } from "@buoy-gg/shared-ui";
|
|
9
9
|
import { useDevToolsSettings } from "./DevToolsSettingsModal";
|
|
10
|
-
import { useAppHost } from "./AppHost
|
|
10
|
+
import { useAppHost } from "./AppHost";
|
|
11
11
|
import { useDevToolsVisibility } from "./DevToolsVisibilityContext.js";
|
|
12
12
|
import { toggleStateManager } from "./ToggleStateManager.js";
|
|
13
|
-
import { OnboardingTooltip } from "./dial/OnboardingTooltip
|
|
13
|
+
import { OnboardingTooltip } from "./dial/OnboardingTooltip";
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Props for the floating developer tools launcher. Controls which apps are shown and
|
|
@@ -8,9 +8,8 @@ import { persistentStorage, getSafeAreaInsets } from "@buoy-gg/shared-ui";
|
|
|
8
8
|
// Types
|
|
9
9
|
// ============================================================================
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*/
|
|
11
|
+
// Type moved to the platform-free AppHostLogic.ts (so the web host can use
|
|
12
|
+
// it without importing this react-native file); re-exported for back-compat.
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Represents a minimized tool that can be restored
|