@buoy-gg/core 7.0.39 → 7.0.41

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 (140) hide show
  1. package/README.md +10 -0
  2. package/bin/buoy.js +25 -31
  3. package/lib/commonjs/browserRegister.js +48 -0
  4. package/lib/commonjs/browserRegister.server.js +10 -0
  5. package/lib/commonjs/floatingMenu/AppHost.web.js +71 -59
  6. package/lib/commonjs/floatingMenu/BrowserToolRuntime.js +150 -0
  7. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +10 -1107
  8. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.shared.js +1114 -0
  9. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +28 -1028
  10. package/lib/commonjs/floatingMenu/FloatingDevTools.js +7 -2
  11. package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +54 -40
  12. package/lib/commonjs/floatingMenu/MinimizedToolsStack.web.js +8 -2
  13. package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +10 -0
  14. package/lib/commonjs/floatingMenu/autoExternalSync.js +9 -0
  15. package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +86 -12
  16. package/lib/commonjs/floatingMenu/dial/DialIcon.js +4 -2
  17. package/lib/commonjs/floatingMenu/settingsBus.js +6 -17
  18. package/lib/commonjs/floatingMenu/useDesktopSyncStatus.web.js +14 -0
  19. package/lib/commonjs/index.web.js +92 -1
  20. package/lib/commonjs/reactDevtoolsTypes.js +1 -0
  21. package/lib/commonjs/utils/autoDiscoverPresets.web.js +5 -178
  22. package/lib/commonjs/utils/createWebTool.js +20 -0
  23. package/lib/commonjs/utils/createWebTools.js +30 -0
  24. package/lib/commonjs/version.js +1 -1
  25. package/lib/module/browserRegister.js +44 -0
  26. package/lib/module/browserRegister.server.js +6 -0
  27. package/lib/module/floatingMenu/AppHost.web.js +71 -59
  28. package/lib/module/floatingMenu/BrowserToolRuntime.js +146 -0
  29. package/lib/module/floatingMenu/DevToolsSettingsModal.js +1 -1109
  30. package/lib/module/floatingMenu/DevToolsSettingsModal.shared.js +1110 -0
  31. package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +32 -1043
  32. package/lib/module/floatingMenu/FloatingDevTools.js +7 -2
  33. package/lib/module/floatingMenu/FloatingDevTools.web.js +55 -42
  34. package/lib/module/floatingMenu/MinimizedToolsStack.web.js +8 -2
  35. package/lib/module/floatingMenu/autoDiscoverPresets.js +10 -0
  36. package/lib/module/floatingMenu/autoExternalSync.js +9 -0
  37. package/lib/module/floatingMenu/dial/DialDevTools.web.js +87 -14
  38. package/lib/module/floatingMenu/dial/DialIcon.js +4 -2
  39. package/lib/module/floatingMenu/settingsBus.js +1 -17
  40. package/lib/module/floatingMenu/useDesktopSyncStatus.web.js +10 -0
  41. package/lib/module/index.web.js +8 -1
  42. package/lib/module/reactDevtoolsTypes.js +1 -0
  43. package/lib/module/utils/autoDiscoverPresets.web.js +5 -180
  44. package/lib/module/utils/createWebTool.js +17 -0
  45. package/lib/module/utils/createWebTools.js +25 -0
  46. package/lib/module/version.js +1 -1
  47. package/lib/typescript/commonjs/browserRegister.d.ts +5 -0
  48. package/lib/typescript/commonjs/browserRegister.d.ts.map +1 -0
  49. package/lib/typescript/commonjs/browserRegister.server.d.ts +5 -0
  50. package/lib/typescript/commonjs/browserRegister.server.d.ts.map +1 -0
  51. package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts +3 -3
  52. package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/floatingMenu/BrowserToolRuntime.d.ts +14 -0
  54. package/lib/typescript/commonjs/floatingMenu/BrowserToolRuntime.d.ts.map +1 -0
  55. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts +2 -67
  56. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  57. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.shared.d.ts +71 -0
  58. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.shared.d.ts.map +1 -0
  59. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts +3 -16
  60. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  61. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  62. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts +12 -6
  63. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.web.d.ts.map +1 -1
  65. package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +1 -1
  67. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +1 -1
  68. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +1 -1
  69. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +1 -1
  71. package/lib/typescript/commonjs/floatingMenu/settingsBus.d.ts +1 -9
  72. package/lib/typescript/commonjs/floatingMenu/settingsBus.d.ts.map +1 -1
  73. package/lib/typescript/commonjs/floatingMenu/useDesktopSyncStatus.web.d.ts +3 -0
  74. package/lib/typescript/commonjs/floatingMenu/useDesktopSyncStatus.web.d.ts.map +1 -0
  75. package/lib/typescript/commonjs/index.web.d.ts +6 -0
  76. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  77. package/lib/typescript/commonjs/reactDevtoolsTypes.d.ts +8 -0
  78. package/lib/typescript/commonjs/reactDevtoolsTypes.d.ts.map +1 -0
  79. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts +3 -40
  80. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts.map +1 -1
  81. package/lib/typescript/commonjs/utils/createWebTool.d.ts +6 -0
  82. package/lib/typescript/commonjs/utils/createWebTool.d.ts.map +1 -0
  83. package/lib/typescript/commonjs/utils/createWebTools.d.ts +4 -0
  84. package/lib/typescript/commonjs/utils/createWebTools.d.ts.map +1 -0
  85. package/lib/typescript/commonjs/version.d.ts +1 -1
  86. package/lib/typescript/module/browserRegister.d.ts +5 -0
  87. package/lib/typescript/module/browserRegister.d.ts.map +1 -0
  88. package/lib/typescript/module/browserRegister.server.d.ts +5 -0
  89. package/lib/typescript/module/browserRegister.server.d.ts.map +1 -0
  90. package/lib/typescript/module/floatingMenu/AppHost.web.d.ts +3 -3
  91. package/lib/typescript/module/floatingMenu/AppHost.web.d.ts.map +1 -1
  92. package/lib/typescript/module/floatingMenu/BrowserToolRuntime.d.ts +14 -0
  93. package/lib/typescript/module/floatingMenu/BrowserToolRuntime.d.ts.map +1 -0
  94. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts +2 -67
  95. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  96. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.shared.d.ts +71 -0
  97. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.shared.d.ts.map +1 -0
  98. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts +3 -16
  99. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  100. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  101. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts +12 -6
  102. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  103. package/lib/typescript/module/floatingMenu/MinimizedToolsStack.web.d.ts.map +1 -1
  104. package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  105. package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +1 -1
  106. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +1 -1
  107. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +1 -1
  108. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  109. package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +1 -1
  110. package/lib/typescript/module/floatingMenu/settingsBus.d.ts +1 -9
  111. package/lib/typescript/module/floatingMenu/settingsBus.d.ts.map +1 -1
  112. package/lib/typescript/module/floatingMenu/useDesktopSyncStatus.web.d.ts +3 -0
  113. package/lib/typescript/module/floatingMenu/useDesktopSyncStatus.web.d.ts.map +1 -0
  114. package/lib/typescript/module/index.web.d.ts +6 -0
  115. package/lib/typescript/module/index.web.d.ts.map +1 -1
  116. package/lib/typescript/module/reactDevtoolsTypes.d.ts +8 -0
  117. package/lib/typescript/module/reactDevtoolsTypes.d.ts.map +1 -0
  118. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts +3 -40
  119. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts.map +1 -1
  120. package/lib/typescript/module/utils/createWebTool.d.ts +6 -0
  121. package/lib/typescript/module/utils/createWebTool.d.ts.map +1 -0
  122. package/lib/typescript/module/utils/createWebTools.d.ts +4 -0
  123. package/lib/typescript/module/utils/createWebTools.d.ts.map +1 -0
  124. package/lib/typescript/module/version.d.ts +1 -1
  125. package/lib/web/chunks/chunk-5NZOQR6Q.mjs +2 -0
  126. package/lib/web/chunks/chunk-CGDSLLZF.mjs +2 -0
  127. package/lib/web/chunks/chunk-DCJDUSNR.mjs +2 -0
  128. package/lib/web/chunks/chunk-IDSHFS6G.mjs +2 -0
  129. package/lib/web/chunks/chunk-JOAMJGCS.mjs +2 -0
  130. package/lib/web/chunks/chunk-KYKZ2N52.mjs +2 -0
  131. package/lib/web/chunks/chunk-NGM7JGGS.mjs +2 -0
  132. package/lib/web/chunks/chunk-QZDVCMCT.mjs +2 -0
  133. package/lib/web/chunks/chunk-R7RGRTY5.mjs +2 -0
  134. package/lib/web/chunks/chunk-Z3XWDDIO.mjs +2 -0
  135. package/lib/web/chunks/chunk-ZTGQ6TTY.mjs +2 -0
  136. package/lib/web/index.mjs +11 -0
  137. package/lib/web/register-server.mjs +2 -0
  138. package/lib/web/register.mjs +2 -0
  139. package/lib/web/toolkit.mjs +2 -0
  140. package/package.json +50 -12
@@ -515,7 +515,12 @@ export const FloatingDevTools = ({
515
515
  ,
516
516
  __buoyDevToolsRoot: true,
517
517
  children: /*#__PURE__*/_jsxs(DevToolsVisibilityProvider, {
518
- children: [/*#__PURE__*/_jsx(AppHostProvider, {
518
+ children: [ImageOverlayOverlay && /*#__PURE__*/_jsx(View, {
519
+ style: StyleSheet.absoluteFill,
520
+ pointerEvents: "box-none",
521
+ collapsable: false,
522
+ children: /*#__PURE__*/_jsx(ImageOverlayOverlay, {})
523
+ }), /*#__PURE__*/_jsx(AppHostProvider, {
519
524
  children: /*#__PURE__*/_jsxs(MinimizedToolsProvider, {
520
525
  getToolIcon: getToolIcon,
521
526
  children: [/*#__PURE__*/_jsx(FloatingMenu, {
@@ -526,7 +531,7 @@ export const FloatingDevTools = ({
526
531
  children: [/*#__PURE__*/_jsx(AppOverlay, {}), /*#__PURE__*/_jsx(FloatingToolHost, {})]
527
532
  }), /*#__PURE__*/_jsx(ToolOpenerBridge, {})]
528
533
  })
529
- }), children, DebugBordersOverlay && /*#__PURE__*/_jsx(DebugBordersOverlay, {}), HighlightUpdatesOverlay && /*#__PURE__*/_jsx(HighlightUpdatesOverlay, {}), ImageOverlayOverlay && /*#__PURE__*/_jsx(ImageOverlayOverlay, {}), PerfMonitorOverlay && /*#__PURE__*/_jsx(PerfMonitorOverlay, {}), JsTopOverlay && /*#__PURE__*/_jsx(JsTopOverlay, {}), ImpersonateOverlay && /*#__PURE__*/_jsx(ImpersonateOverlay, {}), ScenariosOverlay && /*#__PURE__*/_jsx(ScenariosOverlay, {}), ReduxAutoInstrument && /*#__PURE__*/_jsx(ReduxAutoInstrument, {}), ConsoleRoot && /*#__PURE__*/_jsx(ConsoleRoot, {}), RouteTracker && /*#__PURE__*/_jsx(RouteTracker, {}), ReactQueryTracker && /*#__PURE__*/_jsx(ReactQueryTracker, {}), toolRegistry, syncEnabled && /*#__PURE__*/_jsx(AutoExternalSync, {
534
+ }), children, DebugBordersOverlay && /*#__PURE__*/_jsx(DebugBordersOverlay, {}), HighlightUpdatesOverlay && /*#__PURE__*/_jsx(HighlightUpdatesOverlay, {}), PerfMonitorOverlay && /*#__PURE__*/_jsx(PerfMonitorOverlay, {}), JsTopOverlay && /*#__PURE__*/_jsx(JsTopOverlay, {}), ImpersonateOverlay && /*#__PURE__*/_jsx(ImpersonateOverlay, {}), ScenariosOverlay && /*#__PURE__*/_jsx(ScenariosOverlay, {}), ReduxAutoInstrument && /*#__PURE__*/_jsx(ReduxAutoInstrument, {}), ConsoleRoot && /*#__PURE__*/_jsx(ConsoleRoot, {}), RouteTracker && /*#__PURE__*/_jsx(RouteTracker, {}), ReactQueryTracker && /*#__PURE__*/_jsx(ReactQueryTracker, {}), toolRegistry, syncEnabled && /*#__PURE__*/_jsx(AutoExternalSync, {
530
535
  options: externalSyncOptions(externalSync),
531
536
  requiredEnvVars: requiredEnvVars,
532
537
  isPro: isLicensed,
@@ -3,25 +3,6 @@
3
3
  import { FloatingToolHost } from "@buoy-gg/shared-ui/floating";
4
4
  import { LicenseManager, useLicense } from "@buoy-gg/license";
5
5
  import { AccountSetup } from "@buoy-gg/shared-ui";
6
- /**
7
- * FloatingDevTools - Unified dev tools component for React DOM Web.
8
- *
9
- * Matches the mobile FloatingDevTools API exactly:
10
- * - Self-contained (doesn't wrap your app)
11
- * - Auto-discovers installed tool packages
12
- * - Manages dial menu and settings modal state internally
13
- *
14
- * Usage (same as mobile):
15
- * ```tsx
16
- * <>
17
- * <YourApp />
18
- * <FloatingDevTools environment="qa" userRole="admin" />
19
- * </>
20
- * ```
21
- *
22
- * @platform React DOM Web (Vite, CRA, Next.js, Electron)
23
- */
24
-
25
6
  import { useState, useMemo, useCallback, useEffect, useRef } from 'react';
26
7
  import { useSettings, getToolLabel, getToolDescription, getToolColor } from '@buoy-gg/floating-tools-react';
27
8
  import { persistentStorage, devToolsStorageKeys, EnvironmentIndicator, EnvironmentSelectorInline } from '@buoy-gg/shared-ui';
@@ -33,18 +14,15 @@ import { OnboardingTooltip } from "./dial/OnboardingTooltip.web.js";
33
14
  import { SettingsModal } from "./DevToolsSettingsModal.web.js";
34
15
  import { AppHostProvider, AppOverlay, useAppHost } from "./AppHost.web.js";
35
16
  import { MinimizedToolsStack } from "./MinimizedToolsStack.web.js";
17
+ import { createWebTools } from "../utils/createWebTools.js";
18
+ import { BrowserToolRuntime } from "./BrowserToolRuntime.js";
19
+ import { DevToolsVisibilityProvider, useDevToolsVisibility } from "./DevToolsVisibilityContext.js";
20
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
21
+ const EMPTY_MODULES = {};
36
22
 
37
23
  // native FloatingMenu.tsx TOOLTIP_SHOWN_KEY
38
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
39
24
  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
- };
25
+ const webSettingsStorage = persistentStorage;
48
26
 
49
27
  // =============================
50
28
  // Types
@@ -90,9 +68,11 @@ function MenuLauncherIcon({
90
68
  function AdmittedFloatingDevTools(props) {
91
69
  // The tool host wraps everything so dial presses can open tool components
92
70
  // into the AppOverlay (web twin of the native AppHostProvider/AppOverlay).
93
- return /*#__PURE__*/_jsx(AppHostProvider, {
94
- children: /*#__PURE__*/_jsx(FloatingDevToolsInner, {
95
- ...props
71
+ return /*#__PURE__*/_jsx(DevToolsVisibilityProvider, {
72
+ children: /*#__PURE__*/_jsx(AppHostProvider, {
73
+ children: /*#__PURE__*/_jsx(FloatingDevToolsInner, {
74
+ ...props
75
+ })
96
76
  })
97
77
  });
98
78
  }
@@ -102,6 +82,10 @@ function FloatingDevToolsInner({
102
82
  availableEnvironments,
103
83
  onEnvironmentSwitch,
104
84
  apps,
85
+ modules = EMPTY_MODULES,
86
+ externalSync,
87
+ requiredEnvVars,
88
+ sentryGetClient,
105
89
  disableHints = false,
106
90
  headless = false
107
91
  }) {
@@ -112,7 +96,15 @@ function FloatingDevToolsInner({
112
96
  const appHost = useAppHost();
113
97
 
114
98
  // Auto-discover tools and merge with custom apps
115
- const tools = useMemo(() => autoDiscoverWithCustom(apps), [apps]);
99
+ const tools = useMemo(() => autoDiscoverWithCustom([...createWebTools(modules), ...(apps ?? [])]), [apps, modules]);
100
+ const visibility = useDevToolsVisibility();
101
+ const toolVisible = appHost.openApps.some(app => !app.minimized);
102
+ useEffect(() => {
103
+ visibility.setDialOpen(isDialOpen);
104
+ }, [isDialOpen, visibility.setDialOpen]);
105
+ useEffect(() => {
106
+ visibility.setToolOpen(toolVisible || isSettingsOpen);
107
+ }, [toolVisible, isSettingsOpen, visibility.setToolOpen]);
116
108
 
117
109
  // Let the host restore `@react_buoy_open_apps` from the previous session
118
110
  // once it knows which tools exist (native registerApps parity).
@@ -120,7 +112,15 @@ function FloatingDevToolsInner({
120
112
  registerApps
121
113
  } = appHost;
122
114
  useEffect(() => {
123
- registerApps(tools);
115
+ registerApps(tools.map(tool => {
116
+ const icon = tool.icon;
117
+ return {
118
+ ...tool,
119
+ icon: typeof icon === 'function' ? ({
120
+ size
121
+ }) => icon(size) : icon
122
+ };
123
+ }));
124
124
  }, [registerApps, tools]);
125
125
 
126
126
  // Convert to available tools config for settings
@@ -171,6 +171,10 @@ function FloatingDevToolsInner({
171
171
  // Shared open path for dial + bubble-row tools.
172
172
  const openTool = useCallback(tool => {
173
173
  void recordToolUsage(tool.id);
174
+ if (tool.launchMode === 'toggle-only') {
175
+ tool.onPress?.();
176
+ return;
177
+ }
174
178
  if (tool.component) {
175
179
  const dockIcon = typeof tool.icon === 'function' ? tool.icon(20) : tool.icon;
176
180
  appHost.open({
@@ -178,6 +182,7 @@ function FloatingDevToolsInner({
178
182
  title: tool.name || getToolLabel(tool.id),
179
183
  component: tool.component,
180
184
  props: tool.props,
185
+ modal: tool.modal,
181
186
  launchMode: tool.launchMode || 'self-modal',
182
187
  singleton: tool.singleton ?? true,
183
188
  icon: dockIcon,
@@ -272,9 +277,9 @@ function FloatingDevToolsInner({
272
277
  // Callbacks
273
278
  const handleOpenDial = useCallback(() => {
274
279
  // Opening the dial dismisses the welcome tooltip (native handleDialOpen).
275
- if (showWelcomeTooltip) dismissWelcomeTooltip();
280
+ dismissWelcomeTooltip();
276
281
  setIsDialOpen(true);
277
- }, [showWelcomeTooltip, dismissWelcomeTooltip]);
282
+ }, [dismissWelcomeTooltip]);
278
283
  const handleCloseDial = useCallback(() => {
279
284
  setIsDialOpen(false);
280
285
  setIsSettingsOpen(false); // settings lives above the dial
@@ -289,13 +294,21 @@ function FloatingDevToolsInner({
289
294
  const environmentEnabled = settings.floatingTools.environment !== false;
290
295
  const welcomeActive = showWelcomeTooltip && !isDialOpen && !isAnyToolOpen;
291
296
  const hasMinimizedTools = appHost.openApps.some(app => app.minimized && app.launchMode !== 'toggle-only');
292
-
293
- // Headless: desktop sync is native-only, so there is nothing to mount on
294
- // web — accept the prop for API parity and render nothing. (After all
295
- // hooks so hook order is preserved.)
296
- if (headless) return null;
297
- return /*#__PURE__*/_jsxs(_Fragment, {
298
- children: [welcomeActive && /*#__PURE__*/_jsx("div", {
297
+ const runtime = /*#__PURE__*/_jsx(BrowserToolRuntime, {
298
+ modules: modules,
299
+ apps: apps,
300
+ requiredEnvVars: requiredEnvVars,
301
+ externalSync: externalSync,
302
+ headless: headless,
303
+ sentryGetClient: sentryGetClient
304
+ });
305
+ if (headless) return runtime;
306
+ return /*#__PURE__*/_jsxs("div", {
307
+ "data-buoy-root": "",
308
+ style: {
309
+ display: 'contents'
310
+ },
311
+ children: [runtime, welcomeActive && /*#__PURE__*/_jsx("div", {
299
312
  style: {
300
313
  position: 'fixed',
301
314
  inset: 0,
@@ -255,12 +255,16 @@ export function MinimizedToolsStack({
255
255
  children: [/*#__PURE__*/_jsx("div", {
256
256
  style: {
257
257
  position: 'absolute',
258
- bottom: 0,
258
+ bottom: 'var(--buoy-stack-bottom, 0px)',
259
+ top: 'var(--buoy-stack-top, auto)',
259
260
  left: 0,
260
261
  width: containerWidth,
262
+ maxHeight: 'var(--buoy-stack-space, calc(100vh - 48px))',
263
+ visibility: isExpanded ? 'visible' : 'hidden',
261
264
  height: isExpanded ? expandedHeight : 0,
262
265
  opacity: isExpanded ? 1 : 0,
263
- overflow: 'hidden',
266
+ overflowY: 'auto',
267
+ overflowX: 'hidden',
264
268
  transition: 'height 200ms ease, opacity 200ms ease',
265
269
  pointerEvents: isExpanded ? 'auto' : 'none',
266
270
  ...frame
@@ -311,6 +315,8 @@ export function MinimizedToolsStack({
311
315
  }), /*#__PURE__*/_jsxs("button", {
312
316
  type: "button",
313
317
  "aria-label": `Show ${minimized.length} minimized tools`,
318
+ tabIndex: isExpanded ? -1 : 0,
319
+ "aria-hidden": isExpanded,
314
320
  onClick: () => setIsExpanded(true),
315
321
  style: {
316
322
  position: 'absolute',
@@ -184,6 +184,16 @@ export function autoDiscoverPresets() {
184
184
  return null;
185
185
  }
186
186
  }
187
+ }, {
188
+ name: "@buoy-gg/notifications",
189
+ loader: () => {
190
+ try {
191
+ return require("@buoy-gg/notifications").notificationToolPreset;
192
+ } catch (e) {
193
+ reportOptionalRequireError("@buoy-gg/notifications", e);
194
+ return null;
195
+ }
196
+ }
187
197
  },
188
198
  // Sentry
189
199
  {
@@ -46,6 +46,12 @@ let jotaiModule = null;
46
46
  let eventsModule = null;
47
47
  let consoleModule = null;
48
48
  let sentryModule = null;
49
+ let notificationsModule = null;
50
+ try {
51
+ notificationsModule = require("@buoy-gg/notifications");
52
+ } catch (e) {
53
+ reportOptionalRequireError("@buoy-gg/notifications", e);
54
+ }
49
55
  let envModule = null;
50
56
  let highlightUpdatesModule = null;
51
57
  let debugBordersModule = null;
@@ -348,6 +354,9 @@ function useToolAdapterMapInner(queryAdapter, requiredEnvVars, customApps) {
348
354
  if (consoleModule?.consoleSyncAdapter) {
349
355
  map.console = consoleModule.consoleSyncAdapter;
350
356
  }
357
+ if (notificationsModule?.notificationSyncAdapter) {
358
+ map["push-notifications"] = notificationsModule.notificationSyncAdapter;
359
+ }
351
360
  if (sentryModule?.sentrySyncAdapter) {
352
361
  map.sentry = sentryModule.sentrySyncAdapter;
353
362
  }
@@ -14,11 +14,16 @@
14
14
 
15
15
  import { useState, useEffect, useMemo, useRef, useCallback } from 'react';
16
16
  import { getDialLayout, getAllIconPositions, getGridLineRotations, getIconStaggerInputRange, MAX_DIAL_SLOTS, DIAL_ICON_SIZE, dialAnimationConfig, getDialCSSKeyframesString, getDialCSSAnimationStyles, dialColors, dialStyles, withAlpha, floatingToolsColors } from '@buoy-gg/floating-tools-react';
17
- import { persistentStorage, monoFont } from '@buoy-gg/shared-ui';
17
+ import { persistentStorage, monoFont, ToolBackground, useToolBackground } from '@buoy-gg/shared-ui';
18
+ import { DialHyperspace } from "./DialHyperspace.js";
18
19
  import { OnboardingTooltip } from "./OnboardingTooltip.web.js";
20
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
21
+ const DIAL_BACKGROUND_FOCUS = {
22
+ x: 0.5,
23
+ y: 0.5
24
+ };
19
25
 
20
26
  // native DialDevTools.tsx SETTINGS_TOOLTIP_KEY
21
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
22
27
  const SETTINGS_TOOLTIP_KEY = '@react_buoy_settings_tooltip_shown';
23
28
 
24
29
  // Inject CSS keyframes once on module load
@@ -291,6 +296,10 @@ export function DialMenu({
291
296
  settingsOpen = false,
292
297
  hintsDisabled = false
293
298
  }) {
299
+ const {
300
+ id: backgroundId
301
+ } = useToolBackground();
302
+
294
303
  // Animation values
295
304
  const [backdropOpacity, setBackdropOpacity] = useState(0);
296
305
  const [dialScale, setDialScale] = useState(0);
@@ -305,6 +314,8 @@ export function DialMenu({
305
314
  const [entranceComplete, setEntranceComplete] = useState(false);
306
315
 
307
316
  // Refs
317
+ const dialogRef = useRef(null);
318
+ const centerRef = useRef(null);
308
319
  const animationRef = useRef(null);
309
320
  const isClosingRef = useRef(false);
310
321
 
@@ -317,9 +328,22 @@ export function DialMenu({
317
328
  const cssAnimations = getDialCSSAnimationStyles();
318
329
 
319
330
  // Layout
331
+ const [viewport, setViewport] = useState(() => ({
332
+ width: window.innerWidth,
333
+ height: window.innerHeight
334
+ }));
335
+ useEffect(() => {
336
+ const resize = () => setViewport({
337
+ width: window.innerWidth,
338
+ height: window.innerHeight
339
+ });
340
+ window.addEventListener('resize', resize);
341
+ return () => window.removeEventListener('resize', resize);
342
+ }, []);
320
343
  const layout = useMemo(() => getDialLayout({
321
- screenWidth: window.innerWidth
322
- }), []);
344
+ screenWidth: viewport.width,
345
+ maxCircleSize: Math.max(120, Math.min(320, viewport.height - 96))
346
+ }), [viewport]);
323
347
  const gridRotations = useMemo(() => getGridLineRotations(), []);
324
348
  const positions = useMemo(() => getAllIconPositions(MAX_DIAL_SLOTS, layout.iconRadius), [layout.iconRadius]);
325
349
 
@@ -466,17 +490,44 @@ export function DialMenu({
466
490
  };
467
491
  animationRef.current = requestAnimationFrame(animate);
468
492
  }, [exit, onClose]);
469
-
470
- // Document-level Escape key handler
471
493
  useEffect(() => {
472
- const handleKeyDown = e => {
473
- if (e.key === 'Escape') {
494
+ const opener = document.activeElement;
495
+ const dialog = dialogRef.current;
496
+ return () => {
497
+ if (opener?.isConnected && (document.activeElement === document.body || dialog?.contains(document.activeElement))) {
498
+ opener.focus();
499
+ }
500
+ };
501
+ }, []);
502
+ useEffect(() => {
503
+ if (settingsOpen) return;
504
+ centerRef.current?.focus();
505
+ const handleKeyDown = event => {
506
+ const dialog = dialogRef.current;
507
+ if (!dialog) return;
508
+ if (event.key === 'Escape') {
509
+ event.preventDefault();
474
510
  handleClose();
511
+ } else if (event.key === 'Tab') {
512
+ const controls = Array.from(dialog.querySelectorAll('button:not(:disabled):not([aria-disabled="true"]), [tabindex="0"]')).filter(element => element.getClientRects().length > 0);
513
+ const first = controls[0];
514
+ const last = controls[controls.length - 1];
515
+ if (!dialog.contains(document.activeElement) || (event.shiftKey ? document.activeElement === first : document.activeElement === last)) {
516
+ event.preventDefault();
517
+ (event.shiftKey ? last : first)?.focus();
518
+ }
519
+ } else if (['ArrowRight', 'ArrowDown', 'ArrowLeft', 'ArrowUp', 'Home', 'End'].includes(event.key)) {
520
+ const items = Array.from(dialog.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])'));
521
+ const current = items.indexOf(document.activeElement);
522
+ if (current < 0 || !items.length) return;
523
+ event.preventDefault();
524
+ const next = event.key === 'Home' ? 0 : event.key === 'End' ? items.length - 1 : (current + (event.key === 'ArrowRight' || event.key === 'ArrowDown' ? 1 : -1) + items.length) % items.length;
525
+ items[next].focus();
475
526
  }
476
527
  };
477
528
  document.addEventListener('keydown', handleKeyDown);
478
529
  return () => document.removeEventListener('keydown', handleKeyDown);
479
- }, [handleClose]);
530
+ }, [handleClose, settingsOpen]);
480
531
 
481
532
  // Settings onboarding tooltip — native DialDevTools.tsx:174-196: shown
482
533
  // 1200ms after the dial mounts (entrance animations settle first) if never
@@ -552,6 +603,7 @@ export function DialMenu({
552
603
  const hubClearance = layout.buttonSize * dialStyles.centerButton.containerRatio / 2 + 6;
553
604
  const isAnimating = entranceComplete && !isExiting;
554
605
  return /*#__PURE__*/_jsxs("div", {
606
+ ref: dialogRef,
555
607
  role: "dialog",
556
608
  "aria-label": "Dial Menu",
557
609
  "aria-modal": "true",
@@ -560,15 +612,16 @@ export function DialMenu({
560
612
  inset: 0,
561
613
  zIndex: 10000
562
614
  },
563
- children: [/*#__PURE__*/_jsx("div", {
564
- role: "button",
615
+ children: [/*#__PURE__*/_jsx("button", {
616
+ type: "button",
565
617
  "aria-label": "Close dial menu",
566
618
  tabIndex: 0,
567
619
  onClick: handleClose,
568
- onKeyDown: e => e.key === 'Escape' && handleClose(),
569
620
  style: {
570
621
  position: 'absolute',
571
622
  inset: 0,
623
+ border: 0,
624
+ padding: 0,
572
625
  backgroundColor: dialColors.dialBackdrop,
573
626
  opacity: backdropOpacity
574
627
  }
@@ -638,7 +691,20 @@ export function DialMenu({
638
691
  backgroundColor: dialColors.dialGridLine
639
692
  }
640
693
  }, side))
641
- }, deg)), paddedIcons.map((icon, index) => /*#__PURE__*/_jsx(DialIconItem, {
694
+ }, deg)), /*#__PURE__*/_jsx("div", {
695
+ "data-testid": "dial-background",
696
+ "data-background": backgroundId,
697
+ style: {
698
+ position: 'absolute',
699
+ inset: 0,
700
+ pointerEvents: 'none'
701
+ },
702
+ children: backgroundId === 'hyperspace' ? /*#__PURE__*/_jsx(DialHyperspace, {
703
+ size: layout.circleSize
704
+ }) : /*#__PURE__*/_jsx(ToolBackground, {
705
+ focus: DIAL_BACKGROUND_FOCUS
706
+ })
707
+ }), paddedIcons.map((icon, index) => /*#__PURE__*/_jsx(DialIconItem, {
642
708
  icon: icon,
643
709
  index: index,
644
710
  totalIcons: paddedIcons.length,
@@ -704,11 +770,18 @@ export function DialMenu({
704
770
  alignItems: 'center',
705
771
  justifyContent: 'center'
706
772
  },
707
- children: /*#__PURE__*/_jsx("div", {
773
+ children: /*#__PURE__*/_jsx("button", {
774
+ ref: centerRef,
775
+ type: "button",
776
+ "aria-label": settingsOpen ? 'Close settings' : 'Open settings',
777
+ disabled: !onCenterPress,
708
778
  onClick: onCenterPress,
709
779
  onMouseEnter: () => setIsHoveringCenter(true),
710
780
  onMouseLeave: () => setIsHoveringCenter(false),
711
781
  style: {
782
+ border: 0,
783
+ padding: 0,
784
+ background: 'transparent',
712
785
  width: layout.buttonSize,
713
786
  height: layout.buttonSize,
714
787
  borderRadius: layout.buttonSize / 2,
@@ -23,11 +23,13 @@ const DIAL_A11Y = {
23
23
  "time-machine": "Time Machine",
24
24
  "highlight-updates": "Highlight Updates",
25
25
  "debug-borders": "Debug Borders",
26
- "perf-monitor": "Perf Monitor",
26
+ // Bench (@buoy-gg/perf-monitor) has two dial entries: the HUD toggle and
27
+ // the tool. Both used to read "Perf Monitor", a name the product no longer uses.
28
+ "perf-monitor": "Bench HUD",
27
29
  "js-top": "JS Top",
28
30
  "js-top-modal": "JS Top",
29
31
  impersonate: "Impersonate",
30
- "perf-monitor-modal": "Perf Monitor"
32
+ "perf-monitor-modal": "Bench"
31
33
  };
32
34
  function dialAccessibilityLabel(id, name) {
33
35
  if (id && DIAL_A11Y[id]) return DIAL_A11Y[id];
@@ -1,19 +1,3 @@
1
1
  "use strict";
2
2
 
3
- class SimpleEventBus {
4
- listeners = new Set();
5
- emit(payload) {
6
- this.listeners.forEach(l => {
7
- try {
8
- l(payload);
9
- } catch (e) {
10
- console.error("Error emitting event:", e);
11
- }
12
- });
13
- }
14
- addListener(listener) {
15
- this.listeners.add(listener);
16
- return () => this.listeners.delete(listener);
17
- }
18
- }
19
- export const settingsBus = new SimpleEventBus();
3
+ export { settingsEventBus as settingsBus } from "@buoy-gg/floating-tools-core";
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ import { useSyncExternalStore } from "react";
4
+ import { getRegisteredToolModule } from "@buoy-gg/shared-ui";
5
+ const noopSubscribe = () => () => {};
6
+ const serverSnapshot = () => null;
7
+ export function useDesktopSyncStatus() {
8
+ const sync = getRegisteredToolModule("@buoy-gg/external-sync");
9
+ return useSyncExternalStore(sync?.subscribeSyncStatus ?? noopSubscribe, () => sync?.getSyncStatus?.() ?? null, serverSnapshot);
10
+ }
@@ -11,6 +11,8 @@
11
11
 
12
12
  // Export unified component - primary interface (web version)
13
13
  export { FloatingDevTools } from "./floatingMenu/FloatingDevTools.web.js";
14
+ export { createWebTool } from "./utils/createWebTool.js";
15
+
14
16
  // Export individual web components for advanced use cases
15
17
  export { FloatingTools, UserStatus, Divider } from "./floatingMenu/floatingTools.web.js";
16
18
  export { DialMenu } from "./floatingMenu/dial/DialDevTools.web.js";
@@ -26,4 +28,9 @@ export { autoDiscoverWebPresets, autoDiscoverWithCustom, getToolsBySlot, getEnab
26
28
  // Re-export types from floating-tools-react for convenience
27
29
 
28
30
  // Re-export commonly used utilities from floating-tools-react
29
- export { useSettings, useFloatingTools, getToolLabel, getToolDescription, getToolColor, settingsColors, settingsStyles, dialColors, dialStyles } from "@buoy-gg/floating-tools-react";
31
+ export { useSettings, useFloatingTools, getToolLabel, getToolDescription, getToolColor, settingsColors, settingsStyles, dialColors, dialStyles } from "@buoy-gg/floating-tools-react";
32
+ export { createWebTools } from "./utils/createWebTools.js";
33
+ export * from "./toolkit.js";
34
+ export { useToolHost, useToolHeader } from "./floatingMenu/ToolHost.js";
35
+ export { DevToolsVisibilityProvider, useDevToolsVisibility } from "./floatingMenu/DevToolsVisibilityContext.js";
36
+ export { appSyncAdapter } from "./floatingMenu/sync/appSyncAdapter.js";
@@ -0,0 +1 @@
1
+ "use strict";