@buoy-gg/core 7.0.15 → 7.0.17

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