@buoy-gg/core 2.1.15 → 3.0.0

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 (55) hide show
  1. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +4 -34
  2. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +3 -25
  3. package/lib/commonjs/floatingMenu/FloatingDevTools.js +14 -1
  4. package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +19 -9
  5. package/lib/commonjs/floatingMenu/FloatingMenu.js +6 -6
  6. package/lib/commonjs/floatingMenu/defaultConfig.js +1 -1
  7. package/lib/commonjs/floatingMenu/dial/DialDevTools.js +206 -224
  8. package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +82 -7
  9. package/lib/commonjs/floatingMenu/dial/DialIcon.js +77 -71
  10. package/lib/commonjs/floatingMenu/dial/DialPagination.js +170 -0
  11. package/lib/commonjs/floatingMenu/dial/dialUsageStore.js +97 -0
  12. package/lib/module/floatingMenu/DevToolsSettingsModal.js +5 -35
  13. package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +4 -28
  14. package/lib/module/floatingMenu/FloatingDevTools.js +14 -1
  15. package/lib/module/floatingMenu/FloatingDevTools.web.js +19 -9
  16. package/lib/module/floatingMenu/FloatingMenu.js +7 -7
  17. package/lib/module/floatingMenu/defaultConfig.js +1 -1
  18. package/lib/module/floatingMenu/dial/DialDevTools.js +209 -226
  19. package/lib/module/floatingMenu/dial/DialDevTools.web.js +82 -7
  20. package/lib/module/floatingMenu/dial/DialIcon.js +81 -74
  21. package/lib/module/floatingMenu/dial/DialPagination.js +165 -0
  22. package/lib/module/floatingMenu/dial/dialUsageStore.js +89 -0
  23. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  24. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  25. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  26. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  27. package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +1 -1
  28. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +1 -1
  29. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +1 -1
  30. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts +0 -2
  31. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  32. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  33. package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts +7 -2
  34. package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +1 -1
  35. package/lib/typescript/commonjs/floatingMenu/dial/DialPagination.d.ts +22 -0
  36. package/lib/typescript/commonjs/floatingMenu/dial/DialPagination.d.ts.map +1 -0
  37. package/lib/typescript/commonjs/floatingMenu/dial/dialUsageStore.d.ts +34 -0
  38. package/lib/typescript/commonjs/floatingMenu/dial/dialUsageStore.d.ts.map +1 -0
  39. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  40. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  41. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  42. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  43. package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +1 -1
  44. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +1 -1
  45. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +1 -1
  46. package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts +0 -2
  47. package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  48. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  49. package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts +7 -2
  50. package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +1 -1
  51. package/lib/typescript/module/floatingMenu/dial/DialPagination.d.ts +22 -0
  52. package/lib/typescript/module/floatingMenu/dial/DialPagination.d.ts.map +1 -0
  53. package/lib/typescript/module/floatingMenu/dial/dialUsageStore.d.ts +34 -0
  54. package/lib/typescript/module/floatingMenu/dial/dialUsageStore.d.ts.map +1 -0
  55. package/package.json +5 -5
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  import { useState, useEffect, useCallback, useMemo } from "react";
4
- import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Dimensions } from "react-native";
4
+ import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Dimensions, Platform } from "react-native";
5
5
  import { settingsBus } from "./settingsBus.js";
6
6
  import { SentryBugIcon, WifiCircuitIcon, ImageOverlayIcon, RenderCountIcon, Info, Layers, ChevronRightIcon, ChevronDown, getStorageBackendType, persistentStorage, Database, Trash2, CheckCircle2, AlertTriangle, Zap, FileText, HardDrive, Copy, FileCode, copyToClipboard, LicenseEntryModal, SectionHeader } from "@buoy-gg/shared-ui";
7
7
  import { EnvIcon, StorageIcon, RoutesIcon, NetworkIcon, QueryIcon, HighlighterIcon, ReduxIcon, EventsIcon } from "@buoy-gg/floating-tools-core";
@@ -155,7 +155,7 @@ export const DevToolsSettingsModal = ({
155
155
  const allowedDialKeys = useMemo(() => Object.keys(defaultSettings.dialTools), [defaultSettings]);
156
156
  const allowedFloatingKeys = useMemo(() => Object.keys(defaultSettings.floatingTools).filter(key => key !== "environment"), [defaultSettings]);
157
157
  const [settings, setSettings] = useState(initialSettings || defaultSettings);
158
- const [activeTab, setActiveTab] = useState("dial");
158
+ const [activeTab, setActiveTab] = useState("floating");
159
159
  const [activeTabLoaded, setActiveTabLoaded] = useState(false);
160
160
  const [expandedSettings, setExpandedSettings] = useState(new Set());
161
161
  const [showLicenseModal, setShowLicenseModal] = useState(false);
@@ -165,7 +165,7 @@ export const DevToolsSettingsModal = ({
165
165
  const loadActiveTab = async () => {
166
166
  try {
167
167
  const savedTab = await persistentStorage.getItem(devToolsStorageKeys.settings.activeTab());
168
- if (savedTab && ["dial", "floating", "settings", "pro"].includes(savedTab)) {
168
+ if (savedTab && ["floating", "settings", "pro"].includes(savedTab)) {
169
169
  setActiveTab(savedTab);
170
170
  }
171
171
  } catch (error) {
@@ -263,23 +263,6 @@ export const DevToolsSettingsModal = ({
263
263
  console.error("Failed to save dev tools settings:", error);
264
264
  }
265
265
  };
266
- const toggleDialTool = tool => {
267
- const currentEnabled = Object.values(settings.dialTools).filter(v => v).length;
268
- const isCurrentlyEnabled = settings.dialTools[tool];
269
-
270
- // If trying to enable and already at 6, don't allow
271
- if (!isCurrentlyEnabled && currentEnabled >= MAX_DIAL_SLOTS) {
272
- return; // Could also show a toast/alert here
273
- }
274
- const newSettings = {
275
- ...settings,
276
- dialTools: {
277
- ...settings.dialTools,
278
- [tool]: !settings.dialTools[tool]
279
- }
280
- };
281
- saveSettings(newSettings);
282
- };
283
266
  const toggleFloatingTool = tool => {
284
267
  const newSettings = {
285
268
  ...settings,
@@ -647,17 +630,7 @@ export const DevToolsSettingsModal = ({
647
630
  style: styles.scrollContent,
648
631
  showsVerticalScrollIndicator: false,
649
632
  contentContainerStyle: styles.scrollContainer,
650
- children: [activeTab === "dial" && /*#__PURE__*/_jsx(View, {
651
- style: styles.section,
652
- children: (() => {
653
- const enabledCount = Object.values(settings.dialTools).filter(v => v).length;
654
- const isAtLimit = enabledCount >= MAX_DIAL_SLOTS;
655
- return Object.entries(settings.dialTools).map(([key, value]) => {
656
- const isDisabled = !value && isAtLimit;
657
- return renderToolCard(key, value, isDisabled, () => toggleDialTool(key));
658
- });
659
- })()
660
- }), activeTab === "floating" && /*#__PURE__*/_jsx(View, {
633
+ children: [activeTab === "floating" && /*#__PURE__*/_jsx(View, {
661
634
  style: styles.section,
662
635
  children: Object.entries(settings.floatingTools).map(([key, value]) => renderToolCard(key, value, false, () => toggleFloatingTool(key)))
663
636
  }), activeTab === "settings" && /*#__PURE__*/_jsxs(View, {
@@ -836,7 +809,7 @@ export const DevToolsSettingsModal = ({
836
809
  children: clearSuccess ? "CLEARED" : isClearing ? "CLEARING..." : "CLEAR ALL SETTINGS"
837
810
  })]
838
811
  })]
839
- }), renderGlobalSettingCard("enableSharedModalDimensions", "SHARED MODAL SIZE", "MODAL", "Sync dimensions across all tools", "When enabled, all tool modals will share the same size and position. Resizing one modal will affect all others. When disabled, each tool remembers its own size and position independently.", "Keep OFF for the best experience. This allows you to customize each tool's modal size separately. Enable only if you prefer uniform modal sizes across all dev tools."), renderGlobalSettingCard("expandableWindowControls", "EXPAND CONTROLS", "MODAL", "iPad-style expandable window buttons", "When enabled, the window control buttons (minimize, toggle mode, close) start as small dots and expand into larger, easy-to-tap buttons when pressed — similar to iPad window controls. When disabled, buttons are directly tappable at their small size.", "Keep ON for touch devices where the small buttons are hard to press. Turn OFF if you prefer direct single-tap access (e.g. when using a mouse or simulator)."), isDevelopmentMode && /*#__PURE__*/_jsxs(View, {
812
+ }), renderGlobalSettingCard("enableSharedModalDimensions", "SHARED MODAL SIZE", "MODAL", "Sync dimensions across all tools", "When enabled, all tool modals will share the same size and position. Resizing one modal will affect all others. When disabled, each tool remembers its own size and position independently.", "Keep OFF for the best experience. This allows you to customize each tool's modal size separately. Enable only if you prefer uniform modal sizes across all dev tools."), Platform.OS !== "web" && renderGlobalSettingCard("expandableWindowControls", "EXPAND CONTROLS", "MODAL", "iPad-style expandable window buttons", "When enabled, the window control buttons (minimize, toggle mode, close) start as small dots and expand into larger, easy-to-tap buttons when pressed — similar to iPad window controls. When disabled, buttons are directly tappable at their small size.", "Keep ON for touch devices where the small buttons are hard to press. Turn OFF if you prefer direct single-tap access (e.g. when using a mouse or simulator)."), isDevelopmentMode && /*#__PURE__*/_jsxs(View, {
840
813
  style: styles.exportConfigCard,
841
814
  children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
842
815
  activeOpacity: 0.85,
@@ -1112,9 +1085,6 @@ export const DevToolsSettingsModal = ({
1112
1085
  noMargin: true,
1113
1086
  children: /*#__PURE__*/_jsx(TabSelector, {
1114
1087
  tabs: [{
1115
- key: "dial",
1116
- label: "DIAL"
1117
- }, {
1118
1088
  key: "floating",
1119
1089
  label: "FLOATING"
1120
1090
  }, {
@@ -23,9 +23,7 @@ settingsColors, settingsStyles, getToolColor,
23
23
  // Tool metadata
24
24
  getToolLabel, getToolDescription,
25
25
  // Global settings config
26
- globalSettingsConfig,
27
- // Constants
28
- MAX_SETTINGS_DIAL_SLOTS
26
+ globalSettingsConfig
29
27
  // Types
30
28
  } from '@buoy-gg/floating-tools-react';
31
29
  import { ReduxIcon } from '@buoy-gg/floating-tools-core';
@@ -444,15 +442,14 @@ export function SettingsModal({
444
442
  storage = webStorageAdapter,
445
443
  onSettingsChange
446
444
  }) {
447
- const [activeTab, setActiveTab] = useState('dial');
445
+ const [activeTab, setActiveTab] = useState('floating');
448
446
  const [isExiting, setIsExiting] = useState(false);
449
447
 
450
448
  // Use the shared settings hook
451
449
  const {
452
450
  settings,
453
451
  isLoading,
454
- actions,
455
- helpers
452
+ actions
456
453
  } = useSettings({
457
454
  availableTools,
458
455
  defaultFloatingTools,
@@ -605,28 +602,7 @@ export function SettingsModal({
605
602
  },
606
603
  children: "Loading settings..."
607
604
  }) : /*#__PURE__*/_jsxs(_Fragment, {
608
- children: [activeTab === 'dial' && /*#__PURE__*/_jsxs("div", {
609
- children: [/*#__PURE__*/_jsxs("div", {
610
- style: {
611
- fontSize: settingsStyles.sectionTitle.fontSize,
612
- fontWeight: settingsStyles.sectionTitle.fontWeight,
613
- letterSpacing: settingsStyles.sectionTitle.letterSpacing,
614
- textTransform: settingsStyles.sectionTitle.textTransform,
615
- color: settingsColors.textMuted,
616
- marginBottom: settingsStyles.sectionHeader.marginBottom
617
- },
618
- children: ["SELECT UP TO ", MAX_SETTINGS_DIAL_SLOTS, " TOOLS (", helpers.dialToolCount, "/", MAX_SETTINGS_DIAL_SLOTS, ")"]
619
- }), Object.entries(settings.dialTools).map(([id, enabled]) => {
620
- const isDisabled = !enabled && helpers.isDialFull;
621
- return /*#__PURE__*/_jsx(ToolCard, {
622
- toolId: id,
623
- enabled: enabled,
624
- disabled: isDisabled,
625
- availableTools: availableTools,
626
- onToggle: () => actions.toggleDialTool(id)
627
- }, id);
628
- })]
629
- }), activeTab === 'floating' && /*#__PURE__*/_jsxs("div", {
605
+ children: [activeTab === 'floating' && /*#__PURE__*/_jsxs("div", {
630
606
  children: [/*#__PURE__*/_jsx("div", {
631
607
  style: {
632
608
  fontSize: settingsStyles.sectionTitle.fontSize,
@@ -273,6 +273,19 @@ export const FloatingDevTools = ({
273
273
  }
274
274
  }, []);
275
275
 
276
+ // Check if impersonate is installed and auto-render the floating banner
277
+ const ImpersonateOverlay = useMemo(() => {
278
+ try {
279
+ // @ts-ignore - Dynamic import that may not exist
280
+ const {
281
+ ImpersonateOverlay: Overlay
282
+ } = require("@buoy-gg/impersonate");
283
+ return Overlay;
284
+ } catch {
285
+ return null;
286
+ }
287
+ }, []);
288
+
276
289
  // Get tool icon helper for the MinimizedToolsProvider
277
290
  const getToolIcon = useCallback(id => {
278
291
  const tool = finalApps.find(app => app.id === id);
@@ -325,7 +338,7 @@ export const FloatingDevTools = ({
325
338
  environment: resolvedEnvironment
326
339
  }), /*#__PURE__*/_jsx(AppOverlay, {})]
327
340
  })
328
- }), children, DebugBordersOverlay && /*#__PURE__*/_jsx(DebugBordersOverlay, {}), HighlightUpdatesOverlay && /*#__PURE__*/_jsx(HighlightUpdatesOverlay, {}), ImageOverlayOverlay && /*#__PURE__*/_jsx(ImageOverlayOverlay, {}), PerfMonitorOverlay && /*#__PURE__*/_jsx(PerfMonitorOverlay, {}), RouteTracker && /*#__PURE__*/_jsx(RouteTracker, {})]
341
+ }), children, DebugBordersOverlay && /*#__PURE__*/_jsx(DebugBordersOverlay, {}), HighlightUpdatesOverlay && /*#__PURE__*/_jsx(HighlightUpdatesOverlay, {}), ImageOverlayOverlay && /*#__PURE__*/_jsx(ImageOverlayOverlay, {}), PerfMonitorOverlay && /*#__PURE__*/_jsx(PerfMonitorOverlay, {}), ImpersonateOverlay && /*#__PURE__*/_jsx(ImpersonateOverlay, {}), RouteTracker && /*#__PURE__*/_jsx(RouteTracker, {})]
329
342
  })
330
343
  })
331
344
  })
@@ -24,6 +24,7 @@ import { useSettings, getToolLabel, getToolDescription, getToolColor } from '@bu
24
24
  import { autoDiscoverWithCustom, getToolsBySlot } from "../utils/autoDiscoverPresets.web.js";
25
25
  import { FloatingTools, UserStatus } from "./floatingTools.web.js";
26
26
  import { DialMenu } from "./dial/DialDevTools.web.js";
27
+ import { getRankedToolIds, recordToolUsage } from "./dial/dialUsageStore.js";
27
28
  import { SettingsModal } from "./DevToolsSettingsModal.web.js";
28
29
 
29
30
  // =============================
@@ -69,18 +70,17 @@ export function FloatingDevTools({
69
70
  slot: tool.slot
70
71
  })), [tools]);
71
72
 
72
- // Use shared settings hook
73
- const {
74
- settings
75
- } = useSettings({
73
+ // Register available tools with the shared settings hook (used by the
74
+ // settings modal). The dial no longer reads per-tool show/hide state.
75
+ useSettings({
76
76
  availableTools: availableToolsConfig
77
77
  });
78
78
 
79
- // Build dial icons from enabled dial tools
79
+ // Build dial icons for every dial-eligible tool. The dial paginates and
80
+ // ranks them by usage, so there is no per-tool show/hide setting.
80
81
  const dialIcons = useMemo(() => {
81
82
  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 => {
83
+ return dialTools.map(tool => {
84
84
  const color = tool.color || getToolColor(tool.id);
85
85
  // Handle icon - can be string (emoji) or function (size) => ReactNode
86
86
  let icon;
@@ -98,12 +98,22 @@ export function FloatingDevTools({
98
98
  icon,
99
99
  color,
100
100
  onPress: () => {
101
+ // Record usage so frequently/recently used tools rank toward page 1.
102
+ void recordToolUsage(tool.id);
101
103
  tool.onPress?.();
102
104
  setIsDialOpen(false);
103
105
  }
104
106
  };
105
107
  });
106
- }, [tools, settings.dialTools]);
108
+ }, [tools]);
109
+
110
+ // Snapshot the usage-ranked order each time the dial opens. It stays stable
111
+ // while open so icons don't jump positions mid-interaction.
112
+ const rankedDialIcons = useMemo(() => {
113
+ if (!isDialOpen) return dialIcons;
114
+ const byId = new Map(dialIcons.map(i => [i.id, i]));
115
+ return getRankedToolIds(dialIcons.map(i => i.id)).map(id => byId.get(id)).filter(i => Boolean(i));
116
+ }, [isDialOpen, dialIcons]);
107
117
 
108
118
  // Build available tools for settings modal
109
119
  const availableTools = useMemo(() => tools.map(tool => ({
@@ -129,7 +139,7 @@ export function FloatingDevTools({
129
139
  onPress: handleOpenDial
130
140
  })
131
141
  }), isDialOpen && /*#__PURE__*/_jsx(DialMenu, {
132
- icons: dialIcons,
142
+ icons: rankedDialIcons,
133
143
  onClose: handleCloseDial,
134
144
  centerLabel: "BUOY",
135
145
  onCenterPress: handleOpenSettings
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  import React, { useEffect, useMemo, useRef, useState } from "react";
4
- import { TouchableOpacity, StyleSheet, View, Dimensions } from "react-native";
4
+ import { TouchableOpacity, StyleSheet, View } from "react-native";
5
5
  import { FloatingTools, UserStatus } from "./floatingTools";
6
6
  import { DialDevTools } from "./dial/DialDevTools";
7
7
  import { EnvironmentIndicator, persistentStorage, useHintsDisabled, devToolsStorageKeys, buoyColors } from "@buoy-gg/shared-ui";
@@ -22,10 +22,6 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
22
22
  */
23
23
  const FLOATING_MENU_ONBOARDING_KEY = "@react_buoy_floating_menu_tooltip_shown";
24
24
  const ONBOARDING_STEP_KEY = "@react_buoy_onboarding_step";
25
- const {
26
- width: SCREEN_WIDTH,
27
- height: SCREEN_HEIGHT
28
- } = Dimensions.get("window");
29
25
  export const FloatingMenu = ({
30
26
  apps,
31
27
  state,
@@ -227,8 +223,12 @@ export const FloatingMenu = ({
227
223
  message: "Grab and position this menu wherever you want, then tap the icon to open your tools."
228
224
  })]
229
225
  }), /*#__PURE__*/_jsx(View, {
230
- nativeID: "floating-devtools-root",
231
- pointerEvents: isCompletelyHidden ? "none" : "box-none",
226
+ nativeID: "floating-devtools-root"
227
+ // While the dial overlay is open, the floating menu underneath must be
228
+ // inert — otherwise the draggable bubble's gesture handling intercepts
229
+ // touches on dial controls that overlap it (e.g. the pager buttons).
230
+ ,
231
+ pointerEvents: isCompletelyHidden || showDial ? "none" : "box-none",
232
232
  style: {
233
233
  position: "absolute",
234
234
  top: 0,
@@ -23,7 +23,7 @@
23
23
  * This is a union type of all auto-discovered tool IDs.
24
24
  */
25
25
 
26
- // Render count analysis modal (@buoy-gg/highlight-updates)
26
+ // Benchmark recording modal (@buoy-gg/perf-monitor)
27
27
 
28
28
  /**
29
29
  * Special floating-only tool IDs that only appear in the floating bubble row.