@buoy-gg/core 3.0.2 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/floatingMenu/FloatingDevTools.js +20 -5
- package/lib/commonjs/floatingMenu/allToolsRegistry.js +193 -0
- package/lib/commonjs/floatingMenu/autoExternalSync.js +40 -1
- package/lib/commonjs/floatingMenu/dial/DialDevTools.js +56 -6
- package/lib/commonjs/floatingMenu/dial/DialIcon.js +41 -0
- package/lib/module/floatingMenu/FloatingDevTools.js +21 -6
- package/lib/module/floatingMenu/allToolsRegistry.js +190 -0
- package/lib/module/floatingMenu/autoExternalSync.js +41 -2
- package/lib/module/floatingMenu/dial/DialDevTools.js +58 -8
- package/lib/module/floatingMenu/dial/DialIcon.js +42 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/allToolsRegistry.d.ts +42 -0
- package/lib/typescript/commonjs/floatingMenu/allToolsRegistry.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts +5 -1
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts +7 -0
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/allToolsRegistry.d.ts +42 -0
- package/lib/typescript/module/floatingMenu/allToolsRegistry.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts +5 -1
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts +7 -0
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -118,8 +118,14 @@ const FloatingDevTools = ({
|
|
|
118
118
|
...props
|
|
119
119
|
}) => {
|
|
120
120
|
const resolvedEnvironment = environment ?? (0, _sharedUi.normalizeEnvironment)(process.env.NODE_ENV ?? "dev");
|
|
121
|
-
//
|
|
122
|
-
|
|
121
|
+
// Production gating + the device→dashboard license handshake must use a REAL
|
|
122
|
+
// license only — NOT the free Weekend Pass. Otherwise shipping Buoy would
|
|
123
|
+
// expose the devtools to end users every weekend, and the dashboard would try
|
|
124
|
+
// to adopt a non-existent key. (Feature unlocks inside the tools still honor
|
|
125
|
+
// the Weekend Pass via their own useIsPro().)
|
|
126
|
+
const {
|
|
127
|
+
isLicensed
|
|
128
|
+
} = (0, _license.useProAccess)();
|
|
123
129
|
|
|
124
130
|
// Get full license state for requireLicense gating
|
|
125
131
|
const {
|
|
@@ -128,10 +134,17 @@ const FloatingDevTools = ({
|
|
|
128
134
|
} = (0, _license.useLicense)();
|
|
129
135
|
const [showLicenseModal, setShowLicenseModal] = (0, _react.useState)(false);
|
|
130
136
|
|
|
131
|
-
// Initialize license manager on mount, and set/clear license key when prop changes
|
|
137
|
+
// Initialize license manager on mount, and set/clear license key when prop changes.
|
|
138
|
+
// The `licenseKey` prop is the source of truth WHEN PROVIDED:
|
|
139
|
+
// - non-empty → validate + activate that key
|
|
140
|
+
// - "" (blank) → EXPLICITLY clear the cached license (key was removed)
|
|
141
|
+
// - undefined → don't touch it (the app may set a key via Buoy.init())
|
|
132
142
|
(0, _react.useEffect)(() => {
|
|
133
143
|
if (licenseKeyProp && licenseKeyProp.trim() !== "") {
|
|
134
144
|
_license.LicenseManager.initialize().then(() => _license.LicenseManager.setLicenseKey(licenseKeyProp)).catch(() => {});
|
|
145
|
+
} else if (licenseKeyProp === "") {
|
|
146
|
+
// Explicit removal: wipe the 30-day cache so Pro actually turns off.
|
|
147
|
+
_license.LicenseManager.initialize().then(() => _license.LicenseManager.clearLicense()).catch(() => {});
|
|
135
148
|
} else {
|
|
136
149
|
_license.LicenseManager.initialize();
|
|
137
150
|
}
|
|
@@ -308,7 +321,7 @@ const FloatingDevTools = ({
|
|
|
308
321
|
// Gate: Free tier only works in development mode
|
|
309
322
|
// Pro users can use DevTools everywhere (dev + production)
|
|
310
323
|
const isDevelopment = typeof __DEV__ !== "undefined" && __DEV__;
|
|
311
|
-
if (!isDevelopment && !
|
|
324
|
+
if (!isDevelopment && !isLicensed) {
|
|
312
325
|
// Free user in production - don't render DevTools
|
|
313
326
|
return null;
|
|
314
327
|
}
|
|
@@ -346,7 +359,9 @@ const FloatingDevTools = ({
|
|
|
346
359
|
})
|
|
347
360
|
}), children, DebugBordersOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(DebugBordersOverlay, {}), HighlightUpdatesOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(HighlightUpdatesOverlay, {}), ImageOverlayOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(ImageOverlayOverlay, {}), PerfMonitorOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(PerfMonitorOverlay, {}), ImpersonateOverlay && /*#__PURE__*/(0, _jsxRuntime.jsx)(ImpersonateOverlay, {}), RouteTracker && /*#__PURE__*/(0, _jsxRuntime.jsx)(RouteTracker, {}), isDevelopment && externalSync !== false && (0, _autoExternalSync.isExternalSyncAvailable)() && /*#__PURE__*/(0, _jsxRuntime.jsx)(_autoExternalSync.AutoExternalSync, {
|
|
348
361
|
options: typeof externalSync === "object" ? externalSync : undefined,
|
|
349
|
-
requiredEnvVars: requiredEnvVars
|
|
362
|
+
requiredEnvVars: requiredEnvVars,
|
|
363
|
+
isPro: isLicensed,
|
|
364
|
+
licenseKey: licenseKey
|
|
350
365
|
})]
|
|
351
366
|
})
|
|
352
367
|
})
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ALL_TOOLS_REGISTRY = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _floatingToolsCore = require("@buoy-gg/floating-tools-core");
|
|
10
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
11
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
/**
|
|
14
|
+
* Canonical registry of ALL dial-eligible tools React Buoy offers on mobile.
|
|
15
|
+
*
|
|
16
|
+
* This is the single source of truth used to compute which tools are
|
|
17
|
+
* "unavailable" (offered but not installed in the current app). It lives
|
|
18
|
+
* inside the floating-menu package so nothing outside needs to be imported.
|
|
19
|
+
*
|
|
20
|
+
* Rules for this file:
|
|
21
|
+
* - Only import from REQUIRED dependencies (@buoy-gg/floating-tools-core,
|
|
22
|
+
* @buoy-gg/shared-ui, react-native) so the icons are always resolvable,
|
|
23
|
+
* even when the optional tool packages are not installed.
|
|
24
|
+
* - Only include tools whose preset slot is NOT "row" (row-only tools never
|
|
25
|
+
* appear in the dial and have no "unavailable" state to show).
|
|
26
|
+
* - Keep the order intentional: this order is the fallback when no usage
|
|
27
|
+
* data exists for new/unavailable tools.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
// ─── Color constants for tools whose icons live in optional packages ─────────
|
|
31
|
+
// Copied verbatim from the source icon components so the vendored copies below
|
|
32
|
+
// render identically to the real tool icons.
|
|
33
|
+
|
|
34
|
+
/** Zustand brand color — copied from @buoy-gg/zustand ZustandIcon.tsx */const ZUSTAND_ICON_COLOR = "#463B3F";
|
|
35
|
+
/** Jotai brand color — copied from @buoy-gg/jotai JotaiIcon.tsx */
|
|
36
|
+
const JOTAI_ICON_COLOR = "#6C47FF";
|
|
37
|
+
/** Image overlay purple — matches the preset */
|
|
38
|
+
const IMAGE_OVERLAY_ICON_COLOR = "#A855F7";
|
|
39
|
+
|
|
40
|
+
// ─── Vendored copies of optional-package icons ───────────────────────────────
|
|
41
|
+
// Zustand and Jotai ship their real icons inside their own packages (which may
|
|
42
|
+
// not be installed), so we cannot import them from a required dependency.
|
|
43
|
+
//
|
|
44
|
+
// The REAL icons in @buoy-gg/zustand and @buoy-gg/jotai are themselves a single
|
|
45
|
+
// centered letter glyph (verified — there are no SVG logos in those packages).
|
|
46
|
+
// These are faithful copies of those source components, so unavailable items
|
|
47
|
+
// render the ACTUAL tool icon (just dimmed by DialIcon), not a placeholder.
|
|
48
|
+
|
|
49
|
+
/** Faithful copy of @buoy-gg/zustand `ZustandIcon` */
|
|
50
|
+
const ZustandIcon = ({
|
|
51
|
+
size,
|
|
52
|
+
color
|
|
53
|
+
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
54
|
+
style: {
|
|
55
|
+
width: size,
|
|
56
|
+
height: size,
|
|
57
|
+
justifyContent: "center",
|
|
58
|
+
alignItems: "center"
|
|
59
|
+
},
|
|
60
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
61
|
+
style: {
|
|
62
|
+
fontSize: size * 0.75,
|
|
63
|
+
color: color || ZUSTAND_ICON_COLOR,
|
|
64
|
+
fontWeight: "700"
|
|
65
|
+
},
|
|
66
|
+
children: "Z"
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/** Faithful copy of @buoy-gg/jotai `JotaiIcon` */
|
|
71
|
+
const JotaiIcon = ({
|
|
72
|
+
size,
|
|
73
|
+
color
|
|
74
|
+
}) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
75
|
+
style: {
|
|
76
|
+
width: size,
|
|
77
|
+
height: size,
|
|
78
|
+
justifyContent: "center",
|
|
79
|
+
alignItems: "center"
|
|
80
|
+
},
|
|
81
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
82
|
+
style: {
|
|
83
|
+
fontSize: size * 0.75,
|
|
84
|
+
color: color || JOTAI_ICON_COLOR,
|
|
85
|
+
fontWeight: "700"
|
|
86
|
+
},
|
|
87
|
+
children: "J"
|
|
88
|
+
})
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// ─── Registry entry type ──────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
// ─── Canonical catalog ────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Full list of every dial-eligible tool React Buoy offers on mobile.
|
|
97
|
+
*
|
|
98
|
+
* Available (installed) tools are shown normally in the dial.
|
|
99
|
+
* Unavailable (not installed) tools are appended at the end of the dial and look
|
|
100
|
+
* like a normal item (real icon + real name) with a small muted "Unavailable"
|
|
101
|
+
* caption added; they are non-interactive.
|
|
102
|
+
*
|
|
103
|
+
* To add a new tool to Buoy:
|
|
104
|
+
* 1. Add its preset to autoDiscoverPresets.ts
|
|
105
|
+
* 2. Add an entry here so it appears in the "unavailable" section for apps
|
|
106
|
+
* that haven't installed it yet.
|
|
107
|
+
*/
|
|
108
|
+
const ALL_TOOLS_REGISTRY = exports.ALL_TOOLS_REGISTRY = [{
|
|
109
|
+
id: "env",
|
|
110
|
+
name: "ENV",
|
|
111
|
+
color: _floatingToolsCore.ENV_ICON_COLOR,
|
|
112
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.EnvIcon, {
|
|
113
|
+
size: size
|
|
114
|
+
})
|
|
115
|
+
}, {
|
|
116
|
+
id: "network",
|
|
117
|
+
name: "NETWORK",
|
|
118
|
+
color: _floatingToolsCore.NETWORK_ICON_COLOR,
|
|
119
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.NetworkIcon, {
|
|
120
|
+
size: size
|
|
121
|
+
})
|
|
122
|
+
}, {
|
|
123
|
+
id: "storage",
|
|
124
|
+
name: "STORAGE",
|
|
125
|
+
color: _floatingToolsCore.STORAGE_ICON_COLOR,
|
|
126
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.StorageIcon, {
|
|
127
|
+
size: size
|
|
128
|
+
})
|
|
129
|
+
}, {
|
|
130
|
+
id: "query",
|
|
131
|
+
name: "QUERY",
|
|
132
|
+
color: _floatingToolsCore.QUERY_ICON_COLOR,
|
|
133
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.QueryIcon, {
|
|
134
|
+
size: size
|
|
135
|
+
})
|
|
136
|
+
}, {
|
|
137
|
+
id: "route-events",
|
|
138
|
+
name: "ROUTES",
|
|
139
|
+
color: _floatingToolsCore.ROUTES_ICON_COLOR,
|
|
140
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.RoutesIcon, {
|
|
141
|
+
size: size
|
|
142
|
+
})
|
|
143
|
+
}, {
|
|
144
|
+
id: "highlight-updates-modal",
|
|
145
|
+
name: "HIGHLIGHT",
|
|
146
|
+
color: _floatingToolsCore.HIGHLIGHTER_ICON_COLOR,
|
|
147
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.HighlighterIcon, {
|
|
148
|
+
size: size
|
|
149
|
+
})
|
|
150
|
+
}, {
|
|
151
|
+
id: "redux",
|
|
152
|
+
name: "REDUX",
|
|
153
|
+
color: _floatingToolsCore.REDUX_ICON_COLOR,
|
|
154
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.ReduxIcon, {
|
|
155
|
+
size: size
|
|
156
|
+
})
|
|
157
|
+
}, {
|
|
158
|
+
id: "zustand",
|
|
159
|
+
name: "ZUSTAND",
|
|
160
|
+
color: ZUSTAND_ICON_COLOR,
|
|
161
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(ZustandIcon, {
|
|
162
|
+
size: size
|
|
163
|
+
})
|
|
164
|
+
}, {
|
|
165
|
+
id: "events",
|
|
166
|
+
name: "EVENTS",
|
|
167
|
+
color: _floatingToolsCore.EVENTS_ICON_COLOR,
|
|
168
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.EventsIcon, {
|
|
169
|
+
size: size
|
|
170
|
+
})
|
|
171
|
+
}, {
|
|
172
|
+
id: "jotai",
|
|
173
|
+
name: "JOTAI",
|
|
174
|
+
color: JOTAI_ICON_COLOR,
|
|
175
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(JotaiIcon, {
|
|
176
|
+
size: size
|
|
177
|
+
})
|
|
178
|
+
}, {
|
|
179
|
+
id: "image-overlay",
|
|
180
|
+
name: "IMG",
|
|
181
|
+
color: IMAGE_OVERLAY_ICON_COLOR,
|
|
182
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ImageOverlayIcon, {
|
|
183
|
+
size: size,
|
|
184
|
+
color: IMAGE_OVERLAY_ICON_COLOR
|
|
185
|
+
})
|
|
186
|
+
}, {
|
|
187
|
+
id: "perf-monitor-modal",
|
|
188
|
+
name: "BENCH",
|
|
189
|
+
color: _floatingToolsCore.BENCHMARK_ICON_COLOR,
|
|
190
|
+
renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.BenchmarkIcon, {
|
|
191
|
+
size: size
|
|
192
|
+
})
|
|
193
|
+
}];
|
|
@@ -40,6 +40,7 @@ let reduxModule = null;
|
|
|
40
40
|
let zustandModule = null;
|
|
41
41
|
let jotaiModule = null;
|
|
42
42
|
let eventsModule = null;
|
|
43
|
+
let consoleModule = null;
|
|
43
44
|
let envModule = null;
|
|
44
45
|
let highlightUpdatesModule = null;
|
|
45
46
|
let debugBordersModule = null;
|
|
@@ -91,6 +92,11 @@ try {
|
|
|
91
92
|
} catch {
|
|
92
93
|
// not installed
|
|
93
94
|
}
|
|
95
|
+
try {
|
|
96
|
+
consoleModule = require("@buoy-gg/console");
|
|
97
|
+
} catch {
|
|
98
|
+
// not installed
|
|
99
|
+
}
|
|
94
100
|
try {
|
|
95
101
|
envModule = require("@buoy-gg/env");
|
|
96
102
|
} catch {
|
|
@@ -140,7 +146,9 @@ function defaultIdentity() {
|
|
|
140
146
|
}
|
|
141
147
|
function AutoExternalSync({
|
|
142
148
|
options,
|
|
143
|
-
requiredEnvVars
|
|
149
|
+
requiredEnvVars,
|
|
150
|
+
isPro,
|
|
151
|
+
licenseKey
|
|
144
152
|
}) {
|
|
145
153
|
const {
|
|
146
154
|
useExternalSyncSocket,
|
|
@@ -162,6 +170,34 @@ function AutoExternalSync({
|
|
|
162
170
|
platform: _reactNative.Platform.OS,
|
|
163
171
|
enableLogs: options?.enableLogs
|
|
164
172
|
});
|
|
173
|
+
|
|
174
|
+
// The license validates asynchronously (Keygen call on mount), usually AFTER
|
|
175
|
+
// the socket handshake is already sent — so the one-shot handshake query
|
|
176
|
+
// can't carry Pro status reliably. Emit it as an event whenever it resolves
|
|
177
|
+
// or changes, and on every (re)connect. The broker stores it on the device
|
|
178
|
+
// record and rebroadcasts, so the desktop dashboard can auto-adopt the key.
|
|
179
|
+
const licenseRef = (0, _react.useRef)({
|
|
180
|
+
isPro,
|
|
181
|
+
licenseKey
|
|
182
|
+
});
|
|
183
|
+
licenseRef.current = {
|
|
184
|
+
isPro,
|
|
185
|
+
licenseKey
|
|
186
|
+
};
|
|
187
|
+
(0, _react.useEffect)(() => {
|
|
188
|
+
if (!socket) return;
|
|
189
|
+
const emitLicense = () => {
|
|
190
|
+
socket.emit("device-license", {
|
|
191
|
+
isPro: licenseRef.current.isPro ? "1" : "0",
|
|
192
|
+
licenseKey: licenseRef.current.licenseKey ?? ""
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
if (socket.connected) emitLicense();
|
|
196
|
+
socket.on("connect", emitLicense);
|
|
197
|
+
return () => {
|
|
198
|
+
socket.off("connect", emitLicense);
|
|
199
|
+
};
|
|
200
|
+
}, [socket, isPro, licenseKey]);
|
|
165
201
|
const tools = (0, _react.useMemo)(() => {
|
|
166
202
|
const map = {};
|
|
167
203
|
if (storageModule?.storageSyncAdapter) {
|
|
@@ -188,6 +224,9 @@ function AutoExternalSync({
|
|
|
188
224
|
if (eventsModule?.eventsSyncAdapter) {
|
|
189
225
|
map.events = eventsModule.eventsSyncAdapter;
|
|
190
226
|
}
|
|
227
|
+
if (consoleModule?.consoleSyncAdapter) {
|
|
228
|
+
map.console = consoleModule.consoleSyncAdapter;
|
|
229
|
+
}
|
|
191
230
|
if (envModule?.createEnvSyncAdapter) {
|
|
192
231
|
map.env = envModule.createEnvSyncAdapter(requiredEnvVars ?? []);
|
|
193
232
|
}
|
|
@@ -8,6 +8,7 @@ var _react = require("react");
|
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
9
|
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
10
|
var _DialIcon = require("./DialIcon.js");
|
|
11
|
+
var _allToolsRegistry = require("../allToolsRegistry.js");
|
|
11
12
|
var _DialPagination = require("./DialPagination.js");
|
|
12
13
|
var _dialUsageStore = require("./dialUsageStore.js");
|
|
13
14
|
var _DevToolsSettingsModal = require("../DevToolsSettingsModal");
|
|
@@ -51,7 +52,10 @@ const DialDevTools = ({
|
|
|
51
52
|
const {
|
|
52
53
|
open
|
|
53
54
|
} = (0, _AppHost.useAppHost)();
|
|
54
|
-
const
|
|
55
|
+
const {
|
|
56
|
+
isPro,
|
|
57
|
+
isWeekendFree
|
|
58
|
+
} = (0, _license.useProAccess)();
|
|
55
59
|
|
|
56
60
|
// Live window size — keeps the dial centered and sized correctly when the
|
|
57
61
|
// window resizes (Electron/web) or the device rotates.
|
|
@@ -211,6 +215,35 @@ const DialDevTools = ({
|
|
|
211
215
|
return map;
|
|
212
216
|
}, [dialApps, actions, open, onClose]);
|
|
213
217
|
|
|
218
|
+
// Tools from the global registry that are NOT installed in this app.
|
|
219
|
+
// These are appended after all available tools so paging "next" eventually
|
|
220
|
+
// reveals them. They are display-only (real icon + real name + "Unavailable").
|
|
221
|
+
const unavailableTools = (0, _react.useMemo)(() => {
|
|
222
|
+
const installedIds = new Set(dialApps.map(a => a.id));
|
|
223
|
+
return _allToolsRegistry.ALL_TOOLS_REGISTRY.filter(t => !installedIds.has(t.id));
|
|
224
|
+
}, [dialApps]);
|
|
225
|
+
|
|
226
|
+
// Build stable IconType entries for each unavailable tool.
|
|
227
|
+
const unavailableIconsById = (0, _react.useMemo)(() => {
|
|
228
|
+
const map = new Map();
|
|
229
|
+
for (const tool of unavailableTools) {
|
|
230
|
+
map.set(tool.id, {
|
|
231
|
+
id: tool.id,
|
|
232
|
+
name: tool.name,
|
|
233
|
+
// Pre-render the icon at the standard dial slot size so it looks correct.
|
|
234
|
+
icon: tool.renderIcon(_floatingToolsCore.DIAL_ICON_SIZE),
|
|
235
|
+
iconComponent: undefined,
|
|
236
|
+
color: tool.color,
|
|
237
|
+
unavailable: true,
|
|
238
|
+
// Tapping an unavailable tool is intentionally a no-op: the dial stays
|
|
239
|
+
// open and no modal launches, signalling the tool is not installed.
|
|
240
|
+
// Future: add a brief Toast with an install link here.
|
|
241
|
+
onPress: () => {}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return map;
|
|
245
|
+
}, [unavailableTools]);
|
|
246
|
+
|
|
214
247
|
// Snapshot the usage-ranked order when the dial opens. It stays stable while
|
|
215
248
|
// open so icons don't jump positions mid-interaction.
|
|
216
249
|
const [rankedIds, setRankedIds] = (0, _react.useState)(() => (0, _dialUsageStore.getRankedToolIds)(dialApps.map(a => a.id)));
|
|
@@ -229,7 +262,9 @@ const DialDevTools = ({
|
|
|
229
262
|
cancelled = true;
|
|
230
263
|
};
|
|
231
264
|
}, [dialApps]);
|
|
232
|
-
|
|
265
|
+
|
|
266
|
+
// Page count spans available tools (usage-ranked) + unavailable tools (appended).
|
|
267
|
+
const pageCount = Math.max(1, Math.ceil((rankedIds.length + unavailableTools.length) / _floatingToolsCore.MAX_DIAL_SLOTS));
|
|
233
268
|
const [currentPage, setCurrentPage] = (0, _react.useState)(0);
|
|
234
269
|
const safePage = Math.min(currentPage, pageCount - 1);
|
|
235
270
|
|
|
@@ -237,13 +272,18 @@ const DialDevTools = ({
|
|
|
237
272
|
// snapshotted on open, so each icon's page and slot are fixed for the
|
|
238
273
|
// session — which lets us mount all icons once and paginate purely by
|
|
239
274
|
// toggling visibility (no remounts on page change).
|
|
275
|
+
//
|
|
276
|
+
// Order: usage-ranked available tools first, unavailable tools appended at
|
|
277
|
+
// the very end. This guarantees unavailable items always appear on the last
|
|
278
|
+
// pages and never displace available tools.
|
|
240
279
|
const allDialIcons = (0, _react.useMemo)(() => {
|
|
241
|
-
|
|
280
|
+
const allIds = [...rankedIds, ...unavailableTools.map(t => t.id)];
|
|
281
|
+
return allIds.map(id => iconsById.get(id) ?? unavailableIconsById.get(id)).filter(icon => Boolean(icon)).map((icon, i) => ({
|
|
242
282
|
icon,
|
|
243
283
|
page: Math.floor(i / _floatingToolsCore.MAX_DIAL_SLOTS),
|
|
244
284
|
slot: i % _floatingToolsCore.MAX_DIAL_SLOTS
|
|
245
285
|
}));
|
|
246
|
-
}, [rankedIds, iconsById]);
|
|
286
|
+
}, [rankedIds, iconsById, unavailableTools, unavailableIconsById]);
|
|
247
287
|
|
|
248
288
|
// Empty slot indices for the current page (only the last page can be
|
|
249
289
|
// partial). These are cheap placeholder dots.
|
|
@@ -445,6 +485,10 @@ const DialDevTools = ({
|
|
|
445
485
|
});
|
|
446
486
|
};
|
|
447
487
|
const handleIconPress = icon => {
|
|
488
|
+
// Unavailable tools are display-only. Return early so the dial stays open
|
|
489
|
+
// and no modal or animation is triggered. The dimmed appearance already
|
|
490
|
+
// communicates that the tool is not installed.
|
|
491
|
+
if (icon.unavailable) return;
|
|
448
492
|
setSelectedIcon(1);
|
|
449
493
|
const interaction = _floatingToolsCore.dialAnimationConfig?.interaction ?? {
|
|
450
494
|
iconSelect: {
|
|
@@ -612,8 +656,8 @@ const DialDevTools = ({
|
|
|
612
656
|
style: styles.centerText,
|
|
613
657
|
children: "BUOY"
|
|
614
658
|
}), isPro && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
615
|
-
style: styles.proText,
|
|
616
|
-
children: "PRO"
|
|
659
|
+
style: [styles.proText, isWeekendFree && styles.weekendText],
|
|
660
|
+
children: isWeekendFree ? "WEEKEND" : "PRO"
|
|
617
661
|
})]
|
|
618
662
|
})
|
|
619
663
|
})
|
|
@@ -819,5 +863,11 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
819
863
|
height: 0
|
|
820
864
|
},
|
|
821
865
|
textShadowRadius: 4
|
|
866
|
+
},
|
|
867
|
+
// Weekend Pass variant — violet, tighter spacing so "WEEKEND" fits the dial.
|
|
868
|
+
weekendText: {
|
|
869
|
+
color: "#BF5AF2",
|
|
870
|
+
letterSpacing: 1,
|
|
871
|
+
textShadowColor: "#BF5AF2"
|
|
822
872
|
}
|
|
823
873
|
});
|
|
@@ -157,6 +157,32 @@ const DialIcon = ({
|
|
|
157
157
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
158
158
|
style: styles.emptyDot
|
|
159
159
|
})
|
|
160
|
+
}) : icon.unavailable ?
|
|
161
|
+
/*#__PURE__*/
|
|
162
|
+
// ── Unavailable tool ──────────────────────────────────────────────────
|
|
163
|
+
// Renders the real icon + real name at NORMAL styling (visually identical
|
|
164
|
+
// to an installed tool). The ONLY signal that it's unavailable is the small
|
|
165
|
+
// muted "Unavailable" caption under the name. It's non-interactive: no
|
|
166
|
+
// Pressable, and the dial stays open when tapped because
|
|
167
|
+
// DialDevTools.handleIconPress returns early for unavailable icons.
|
|
168
|
+
(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
169
|
+
style: styles.pressable,
|
|
170
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
171
|
+
style: styles.iconWrapper,
|
|
172
|
+
children: icon.icon
|
|
173
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
174
|
+
style: styles.label,
|
|
175
|
+
numberOfLines: 1,
|
|
176
|
+
adjustsFontSizeToFit: true,
|
|
177
|
+
minimumFontScale: 0.7,
|
|
178
|
+
children: icon.name.toUpperCase()
|
|
179
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
180
|
+
style: styles.unavailableCaption,
|
|
181
|
+
numberOfLines: 1,
|
|
182
|
+
adjustsFontSizeToFit: true,
|
|
183
|
+
minimumFontScale: 0.6,
|
|
184
|
+
children: "Unavailable"
|
|
185
|
+
})]
|
|
160
186
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
161
187
|
onPress: () => onPress(icon),
|
|
162
188
|
onPressIn: handlePressIn,
|
|
@@ -248,5 +274,20 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
248
274
|
backgroundColor: _floatingToolsCore.dialColors.emptyDotBackground,
|
|
249
275
|
borderWidth: _floatingToolsCore.dialStyles.emptySlot.borderWidth,
|
|
250
276
|
borderColor: _floatingToolsCore.dialColors.emptyDotBorder
|
|
277
|
+
},
|
|
278
|
+
// ── Unavailable tool styles ────────────────────────────────────────────────
|
|
279
|
+
/**
|
|
280
|
+
* Small muted caption shown under the (normal-styled) tool name — the only
|
|
281
|
+
* signal that the tool is not installed. Kept compact (smaller than the label)
|
|
282
|
+
* so the extra line doesn't disturb the arc layout. Uses the shared muted
|
|
283
|
+
* theme token rather than a hardcoded color.
|
|
284
|
+
*/
|
|
285
|
+
unavailableCaption: {
|
|
286
|
+
fontSize: _floatingToolsCore.dialStyles.icon.label.fontSize - 1,
|
|
287
|
+
fontWeight: _floatingToolsCore.dialStyles.icon.label.fontWeight,
|
|
288
|
+
letterSpacing: _floatingToolsCore.dialStyles.icon.label.letterSpacing,
|
|
289
|
+
fontFamily: _floatingToolsCore.dialStyles.icon.label.fontFamily,
|
|
290
|
+
color: _floatingToolsCore.floatingToolsColors.muted,
|
|
291
|
+
textTransform: "uppercase"
|
|
251
292
|
}
|
|
252
293
|
});
|
|
@@ -11,7 +11,7 @@ import { HintsProvider, LicenseEntryModal, normalizeEnvironment } from "@buoy-gg
|
|
|
11
11
|
import { MinimizedToolsProvider } from "./MinimizedToolsContext.js";
|
|
12
12
|
import { validateDialConfig } from "./defaultConfig.js";
|
|
13
13
|
import { DefaultConfigProvider } from "./DefaultConfigContext.js";
|
|
14
|
-
import { LicenseManager,
|
|
14
|
+
import { LicenseManager, useProAccess, useLicense } from "@buoy-gg/license";
|
|
15
15
|
import { AutoExternalSync, isExternalSyncAvailable } from "./autoExternalSync.js";
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -114,8 +114,14 @@ export const FloatingDevTools = ({
|
|
|
114
114
|
...props
|
|
115
115
|
}) => {
|
|
116
116
|
const resolvedEnvironment = environment ?? normalizeEnvironment(process.env.NODE_ENV ?? "dev");
|
|
117
|
-
//
|
|
118
|
-
|
|
117
|
+
// Production gating + the device→dashboard license handshake must use a REAL
|
|
118
|
+
// license only — NOT the free Weekend Pass. Otherwise shipping Buoy would
|
|
119
|
+
// expose the devtools to end users every weekend, and the dashboard would try
|
|
120
|
+
// to adopt a non-existent key. (Feature unlocks inside the tools still honor
|
|
121
|
+
// the Weekend Pass via their own useIsPro().)
|
|
122
|
+
const {
|
|
123
|
+
isLicensed
|
|
124
|
+
} = useProAccess();
|
|
119
125
|
|
|
120
126
|
// Get full license state for requireLicense gating
|
|
121
127
|
const {
|
|
@@ -124,10 +130,17 @@ export const FloatingDevTools = ({
|
|
|
124
130
|
} = useLicense();
|
|
125
131
|
const [showLicenseModal, setShowLicenseModal] = useState(false);
|
|
126
132
|
|
|
127
|
-
// Initialize license manager on mount, and set/clear license key when prop changes
|
|
133
|
+
// Initialize license manager on mount, and set/clear license key when prop changes.
|
|
134
|
+
// The `licenseKey` prop is the source of truth WHEN PROVIDED:
|
|
135
|
+
// - non-empty → validate + activate that key
|
|
136
|
+
// - "" (blank) → EXPLICITLY clear the cached license (key was removed)
|
|
137
|
+
// - undefined → don't touch it (the app may set a key via Buoy.init())
|
|
128
138
|
useEffect(() => {
|
|
129
139
|
if (licenseKeyProp && licenseKeyProp.trim() !== "") {
|
|
130
140
|
LicenseManager.initialize().then(() => LicenseManager.setLicenseKey(licenseKeyProp)).catch(() => {});
|
|
141
|
+
} else if (licenseKeyProp === "") {
|
|
142
|
+
// Explicit removal: wipe the 30-day cache so Pro actually turns off.
|
|
143
|
+
LicenseManager.initialize().then(() => LicenseManager.clearLicense()).catch(() => {});
|
|
131
144
|
} else {
|
|
132
145
|
LicenseManager.initialize();
|
|
133
146
|
}
|
|
@@ -304,7 +317,7 @@ export const FloatingDevTools = ({
|
|
|
304
317
|
// Gate: Free tier only works in development mode
|
|
305
318
|
// Pro users can use DevTools everywhere (dev + production)
|
|
306
319
|
const isDevelopment = typeof __DEV__ !== "undefined" && __DEV__;
|
|
307
|
-
if (!isDevelopment && !
|
|
320
|
+
if (!isDevelopment && !isLicensed) {
|
|
308
321
|
// Free user in production - don't render DevTools
|
|
309
322
|
return null;
|
|
310
323
|
}
|
|
@@ -342,7 +355,9 @@ export const FloatingDevTools = ({
|
|
|
342
355
|
})
|
|
343
356
|
}), 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, {}), isDevelopment && externalSync !== false && isExternalSyncAvailable() && /*#__PURE__*/_jsx(AutoExternalSync, {
|
|
344
357
|
options: typeof externalSync === "object" ? externalSync : undefined,
|
|
345
|
-
requiredEnvVars: requiredEnvVars
|
|
358
|
+
requiredEnvVars: requiredEnvVars,
|
|
359
|
+
isPro: isLicensed,
|
|
360
|
+
licenseKey: licenseKey
|
|
346
361
|
})]
|
|
347
362
|
})
|
|
348
363
|
})
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Canonical registry of ALL dial-eligible tools React Buoy offers on mobile.
|
|
5
|
+
*
|
|
6
|
+
* This is the single source of truth used to compute which tools are
|
|
7
|
+
* "unavailable" (offered but not installed in the current app). It lives
|
|
8
|
+
* inside the floating-menu package so nothing outside needs to be imported.
|
|
9
|
+
*
|
|
10
|
+
* Rules for this file:
|
|
11
|
+
* - Only import from REQUIRED dependencies (@buoy-gg/floating-tools-core,
|
|
12
|
+
* @buoy-gg/shared-ui, react-native) so the icons are always resolvable,
|
|
13
|
+
* even when the optional tool packages are not installed.
|
|
14
|
+
* - Only include tools whose preset slot is NOT "row" (row-only tools never
|
|
15
|
+
* appear in the dial and have no "unavailable" state to show).
|
|
16
|
+
* - Keep the order intentional: this order is the fallback when no usage
|
|
17
|
+
* data exists for new/unavailable tools.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import React from "react";
|
|
21
|
+
import { View, Text } from "react-native";
|
|
22
|
+
import { EnvIcon, ENV_ICON_COLOR, NetworkIcon, NETWORK_ICON_COLOR, StorageIcon, STORAGE_ICON_COLOR, QueryIcon, QUERY_ICON_COLOR, RoutesIcon, ROUTES_ICON_COLOR, HighlighterIcon, HIGHLIGHTER_ICON_COLOR, ReduxIcon, REDUX_ICON_COLOR, EventsIcon, EVENTS_ICON_COLOR, BenchmarkIcon, BENCHMARK_ICON_COLOR } from "@buoy-gg/floating-tools-core";
|
|
23
|
+
import { ImageOverlayIcon } from "@buoy-gg/shared-ui";
|
|
24
|
+
|
|
25
|
+
// ─── Color constants for tools whose icons live in optional packages ─────────
|
|
26
|
+
// Copied verbatim from the source icon components so the vendored copies below
|
|
27
|
+
// render identically to the real tool icons.
|
|
28
|
+
|
|
29
|
+
/** Zustand brand color — copied from @buoy-gg/zustand ZustandIcon.tsx */
|
|
30
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
31
|
+
const ZUSTAND_ICON_COLOR = "#463B3F";
|
|
32
|
+
/** Jotai brand color — copied from @buoy-gg/jotai JotaiIcon.tsx */
|
|
33
|
+
const JOTAI_ICON_COLOR = "#6C47FF";
|
|
34
|
+
/** Image overlay purple — matches the preset */
|
|
35
|
+
const IMAGE_OVERLAY_ICON_COLOR = "#A855F7";
|
|
36
|
+
|
|
37
|
+
// ─── Vendored copies of optional-package icons ───────────────────────────────
|
|
38
|
+
// Zustand and Jotai ship their real icons inside their own packages (which may
|
|
39
|
+
// not be installed), so we cannot import them from a required dependency.
|
|
40
|
+
//
|
|
41
|
+
// The REAL icons in @buoy-gg/zustand and @buoy-gg/jotai are themselves a single
|
|
42
|
+
// centered letter glyph (verified — there are no SVG logos in those packages).
|
|
43
|
+
// These are faithful copies of those source components, so unavailable items
|
|
44
|
+
// render the ACTUAL tool icon (just dimmed by DialIcon), not a placeholder.
|
|
45
|
+
|
|
46
|
+
/** Faithful copy of @buoy-gg/zustand `ZustandIcon` */
|
|
47
|
+
const ZustandIcon = ({
|
|
48
|
+
size,
|
|
49
|
+
color
|
|
50
|
+
}) => /*#__PURE__*/_jsx(View, {
|
|
51
|
+
style: {
|
|
52
|
+
width: size,
|
|
53
|
+
height: size,
|
|
54
|
+
justifyContent: "center",
|
|
55
|
+
alignItems: "center"
|
|
56
|
+
},
|
|
57
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
58
|
+
style: {
|
|
59
|
+
fontSize: size * 0.75,
|
|
60
|
+
color: color || ZUSTAND_ICON_COLOR,
|
|
61
|
+
fontWeight: "700"
|
|
62
|
+
},
|
|
63
|
+
children: "Z"
|
|
64
|
+
})
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/** Faithful copy of @buoy-gg/jotai `JotaiIcon` */
|
|
68
|
+
const JotaiIcon = ({
|
|
69
|
+
size,
|
|
70
|
+
color
|
|
71
|
+
}) => /*#__PURE__*/_jsx(View, {
|
|
72
|
+
style: {
|
|
73
|
+
width: size,
|
|
74
|
+
height: size,
|
|
75
|
+
justifyContent: "center",
|
|
76
|
+
alignItems: "center"
|
|
77
|
+
},
|
|
78
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
79
|
+
style: {
|
|
80
|
+
fontSize: size * 0.75,
|
|
81
|
+
color: color || JOTAI_ICON_COLOR,
|
|
82
|
+
fontWeight: "700"
|
|
83
|
+
},
|
|
84
|
+
children: "J"
|
|
85
|
+
})
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// ─── Registry entry type ──────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
// ─── Canonical catalog ────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Full list of every dial-eligible tool React Buoy offers on mobile.
|
|
94
|
+
*
|
|
95
|
+
* Available (installed) tools are shown normally in the dial.
|
|
96
|
+
* Unavailable (not installed) tools are appended at the end of the dial and look
|
|
97
|
+
* like a normal item (real icon + real name) with a small muted "Unavailable"
|
|
98
|
+
* caption added; they are non-interactive.
|
|
99
|
+
*
|
|
100
|
+
* To add a new tool to Buoy:
|
|
101
|
+
* 1. Add its preset to autoDiscoverPresets.ts
|
|
102
|
+
* 2. Add an entry here so it appears in the "unavailable" section for apps
|
|
103
|
+
* that haven't installed it yet.
|
|
104
|
+
*/
|
|
105
|
+
export const ALL_TOOLS_REGISTRY = [{
|
|
106
|
+
id: "env",
|
|
107
|
+
name: "ENV",
|
|
108
|
+
color: ENV_ICON_COLOR,
|
|
109
|
+
renderIcon: size => /*#__PURE__*/_jsx(EnvIcon, {
|
|
110
|
+
size: size
|
|
111
|
+
})
|
|
112
|
+
}, {
|
|
113
|
+
id: "network",
|
|
114
|
+
name: "NETWORK",
|
|
115
|
+
color: NETWORK_ICON_COLOR,
|
|
116
|
+
renderIcon: size => /*#__PURE__*/_jsx(NetworkIcon, {
|
|
117
|
+
size: size
|
|
118
|
+
})
|
|
119
|
+
}, {
|
|
120
|
+
id: "storage",
|
|
121
|
+
name: "STORAGE",
|
|
122
|
+
color: STORAGE_ICON_COLOR,
|
|
123
|
+
renderIcon: size => /*#__PURE__*/_jsx(StorageIcon, {
|
|
124
|
+
size: size
|
|
125
|
+
})
|
|
126
|
+
}, {
|
|
127
|
+
id: "query",
|
|
128
|
+
name: "QUERY",
|
|
129
|
+
color: QUERY_ICON_COLOR,
|
|
130
|
+
renderIcon: size => /*#__PURE__*/_jsx(QueryIcon, {
|
|
131
|
+
size: size
|
|
132
|
+
})
|
|
133
|
+
}, {
|
|
134
|
+
id: "route-events",
|
|
135
|
+
name: "ROUTES",
|
|
136
|
+
color: ROUTES_ICON_COLOR,
|
|
137
|
+
renderIcon: size => /*#__PURE__*/_jsx(RoutesIcon, {
|
|
138
|
+
size: size
|
|
139
|
+
})
|
|
140
|
+
}, {
|
|
141
|
+
id: "highlight-updates-modal",
|
|
142
|
+
name: "HIGHLIGHT",
|
|
143
|
+
color: HIGHLIGHTER_ICON_COLOR,
|
|
144
|
+
renderIcon: size => /*#__PURE__*/_jsx(HighlighterIcon, {
|
|
145
|
+
size: size
|
|
146
|
+
})
|
|
147
|
+
}, {
|
|
148
|
+
id: "redux",
|
|
149
|
+
name: "REDUX",
|
|
150
|
+
color: REDUX_ICON_COLOR,
|
|
151
|
+
renderIcon: size => /*#__PURE__*/_jsx(ReduxIcon, {
|
|
152
|
+
size: size
|
|
153
|
+
})
|
|
154
|
+
}, {
|
|
155
|
+
id: "zustand",
|
|
156
|
+
name: "ZUSTAND",
|
|
157
|
+
color: ZUSTAND_ICON_COLOR,
|
|
158
|
+
renderIcon: size => /*#__PURE__*/_jsx(ZustandIcon, {
|
|
159
|
+
size: size
|
|
160
|
+
})
|
|
161
|
+
}, {
|
|
162
|
+
id: "events",
|
|
163
|
+
name: "EVENTS",
|
|
164
|
+
color: EVENTS_ICON_COLOR,
|
|
165
|
+
renderIcon: size => /*#__PURE__*/_jsx(EventsIcon, {
|
|
166
|
+
size: size
|
|
167
|
+
})
|
|
168
|
+
}, {
|
|
169
|
+
id: "jotai",
|
|
170
|
+
name: "JOTAI",
|
|
171
|
+
color: JOTAI_ICON_COLOR,
|
|
172
|
+
renderIcon: size => /*#__PURE__*/_jsx(JotaiIcon, {
|
|
173
|
+
size: size
|
|
174
|
+
})
|
|
175
|
+
}, {
|
|
176
|
+
id: "image-overlay",
|
|
177
|
+
name: "IMG",
|
|
178
|
+
color: IMAGE_OVERLAY_ICON_COLOR,
|
|
179
|
+
renderIcon: size => /*#__PURE__*/_jsx(ImageOverlayIcon, {
|
|
180
|
+
size: size,
|
|
181
|
+
color: IMAGE_OVERLAY_ICON_COLOR
|
|
182
|
+
})
|
|
183
|
+
}, {
|
|
184
|
+
id: "perf-monitor-modal",
|
|
185
|
+
name: "BENCH",
|
|
186
|
+
color: BENCHMARK_ICON_COLOR,
|
|
187
|
+
renderIcon: size => /*#__PURE__*/_jsx(BenchmarkIcon, {
|
|
188
|
+
size: size
|
|
189
|
+
})
|
|
190
|
+
}];
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* Identity defaults come from expo-constants when available (app name →
|
|
14
14
|
* "MyApp (ios)" / "myapp-ios"), overridable via the `externalSync` prop.
|
|
15
15
|
*/
|
|
16
|
-
import { useMemo } from "react";
|
|
16
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
17
17
|
import { Platform } from "react-native";
|
|
18
18
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
19
19
|
|
|
@@ -34,6 +34,7 @@ let reduxModule = null;
|
|
|
34
34
|
let zustandModule = null;
|
|
35
35
|
let jotaiModule = null;
|
|
36
36
|
let eventsModule = null;
|
|
37
|
+
let consoleModule = null;
|
|
37
38
|
let envModule = null;
|
|
38
39
|
let highlightUpdatesModule = null;
|
|
39
40
|
let debugBordersModule = null;
|
|
@@ -85,6 +86,11 @@ try {
|
|
|
85
86
|
} catch {
|
|
86
87
|
// not installed
|
|
87
88
|
}
|
|
89
|
+
try {
|
|
90
|
+
consoleModule = require("@buoy-gg/console");
|
|
91
|
+
} catch {
|
|
92
|
+
// not installed
|
|
93
|
+
}
|
|
88
94
|
try {
|
|
89
95
|
envModule = require("@buoy-gg/env");
|
|
90
96
|
} catch {
|
|
@@ -134,7 +140,9 @@ function defaultIdentity() {
|
|
|
134
140
|
}
|
|
135
141
|
export function AutoExternalSync({
|
|
136
142
|
options,
|
|
137
|
-
requiredEnvVars
|
|
143
|
+
requiredEnvVars,
|
|
144
|
+
isPro,
|
|
145
|
+
licenseKey
|
|
138
146
|
}) {
|
|
139
147
|
const {
|
|
140
148
|
useExternalSyncSocket,
|
|
@@ -156,6 +164,34 @@ export function AutoExternalSync({
|
|
|
156
164
|
platform: Platform.OS,
|
|
157
165
|
enableLogs: options?.enableLogs
|
|
158
166
|
});
|
|
167
|
+
|
|
168
|
+
// The license validates asynchronously (Keygen call on mount), usually AFTER
|
|
169
|
+
// the socket handshake is already sent — so the one-shot handshake query
|
|
170
|
+
// can't carry Pro status reliably. Emit it as an event whenever it resolves
|
|
171
|
+
// or changes, and on every (re)connect. The broker stores it on the device
|
|
172
|
+
// record and rebroadcasts, so the desktop dashboard can auto-adopt the key.
|
|
173
|
+
const licenseRef = useRef({
|
|
174
|
+
isPro,
|
|
175
|
+
licenseKey
|
|
176
|
+
});
|
|
177
|
+
licenseRef.current = {
|
|
178
|
+
isPro,
|
|
179
|
+
licenseKey
|
|
180
|
+
};
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
if (!socket) return;
|
|
183
|
+
const emitLicense = () => {
|
|
184
|
+
socket.emit("device-license", {
|
|
185
|
+
isPro: licenseRef.current.isPro ? "1" : "0",
|
|
186
|
+
licenseKey: licenseRef.current.licenseKey ?? ""
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
if (socket.connected) emitLicense();
|
|
190
|
+
socket.on("connect", emitLicense);
|
|
191
|
+
return () => {
|
|
192
|
+
socket.off("connect", emitLicense);
|
|
193
|
+
};
|
|
194
|
+
}, [socket, isPro, licenseKey]);
|
|
159
195
|
const tools = useMemo(() => {
|
|
160
196
|
const map = {};
|
|
161
197
|
if (storageModule?.storageSyncAdapter) {
|
|
@@ -182,6 +218,9 @@ export function AutoExternalSync({
|
|
|
182
218
|
if (eventsModule?.eventsSyncAdapter) {
|
|
183
219
|
map.events = eventsModule.eventsSyncAdapter;
|
|
184
220
|
}
|
|
221
|
+
if (consoleModule?.consoleSyncAdapter) {
|
|
222
|
+
map.console = consoleModule.consoleSyncAdapter;
|
|
223
|
+
}
|
|
185
224
|
if (envModule?.createEnvSyncAdapter) {
|
|
186
225
|
map.env = envModule.createEnvSyncAdapter(requiredEnvVars ?? []);
|
|
187
226
|
}
|
|
@@ -5,14 +5,15 @@ import { Pressable, StyleSheet, View, useWindowDimensions, Text, Animated, Easin
|
|
|
5
5
|
import { absoluteFill } from "@buoy-gg/shared-ui";
|
|
6
6
|
// Icons are provided by installedApps; no direct icon imports here.
|
|
7
7
|
import { DialIcon } from "./DialIcon.js";
|
|
8
|
+
import { ALL_TOOLS_REGISTRY } from "../allToolsRegistry.js";
|
|
8
9
|
import { DialPagination } from "./DialPagination.js";
|
|
9
10
|
import { getRankedToolIds, isDialUsageLoaded, loadDialUsage, recordToolUsage } from "./dialUsageStore.js";
|
|
10
11
|
import { persistentStorage, useHintsDisabled, devToolsStorageKeys, buoyColors } from "@buoy-gg/shared-ui";
|
|
11
12
|
import { DevToolsSettingsModal, useDevToolsSettings } from "../DevToolsSettingsModal";
|
|
12
|
-
import {
|
|
13
|
+
import { useProAccess } from "@buoy-gg/license";
|
|
13
14
|
import { useAppHost } from "../AppHost.js";
|
|
14
15
|
import { OnboardingTooltip } from "./OnboardingTooltip.js";
|
|
15
|
-
import { getDialLayout, MAX_DIAL_SLOTS, DIAL_BUTTON_SIZE, dialAnimationConfig, dialColors } from "@buoy-gg/floating-tools-core";
|
|
16
|
+
import { getDialLayout, MAX_DIAL_SLOTS, DIAL_BUTTON_SIZE, DIAL_ICON_SIZE, dialAnimationConfig, dialColors } from "@buoy-gg/floating-tools-core";
|
|
16
17
|
|
|
17
18
|
// The circle size depends on the live window width, so it's computed inside
|
|
18
19
|
// the component via useWindowDimensions — a module-scope Dimensions.get
|
|
@@ -48,7 +49,10 @@ export const DialDevTools = ({
|
|
|
48
49
|
const {
|
|
49
50
|
open
|
|
50
51
|
} = useAppHost();
|
|
51
|
-
const
|
|
52
|
+
const {
|
|
53
|
+
isPro,
|
|
54
|
+
isWeekendFree
|
|
55
|
+
} = useProAccess();
|
|
52
56
|
|
|
53
57
|
// Live window size — keeps the dial centered and sized correctly when the
|
|
54
58
|
// window resizes (Electron/web) or the device rotates.
|
|
@@ -208,6 +212,35 @@ export const DialDevTools = ({
|
|
|
208
212
|
return map;
|
|
209
213
|
}, [dialApps, actions, open, onClose]);
|
|
210
214
|
|
|
215
|
+
// Tools from the global registry that are NOT installed in this app.
|
|
216
|
+
// These are appended after all available tools so paging "next" eventually
|
|
217
|
+
// reveals them. They are display-only (real icon + real name + "Unavailable").
|
|
218
|
+
const unavailableTools = useMemo(() => {
|
|
219
|
+
const installedIds = new Set(dialApps.map(a => a.id));
|
|
220
|
+
return ALL_TOOLS_REGISTRY.filter(t => !installedIds.has(t.id));
|
|
221
|
+
}, [dialApps]);
|
|
222
|
+
|
|
223
|
+
// Build stable IconType entries for each unavailable tool.
|
|
224
|
+
const unavailableIconsById = useMemo(() => {
|
|
225
|
+
const map = new Map();
|
|
226
|
+
for (const tool of unavailableTools) {
|
|
227
|
+
map.set(tool.id, {
|
|
228
|
+
id: tool.id,
|
|
229
|
+
name: tool.name,
|
|
230
|
+
// Pre-render the icon at the standard dial slot size so it looks correct.
|
|
231
|
+
icon: tool.renderIcon(DIAL_ICON_SIZE),
|
|
232
|
+
iconComponent: undefined,
|
|
233
|
+
color: tool.color,
|
|
234
|
+
unavailable: true,
|
|
235
|
+
// Tapping an unavailable tool is intentionally a no-op: the dial stays
|
|
236
|
+
// open and no modal launches, signalling the tool is not installed.
|
|
237
|
+
// Future: add a brief Toast with an install link here.
|
|
238
|
+
onPress: () => {}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
return map;
|
|
242
|
+
}, [unavailableTools]);
|
|
243
|
+
|
|
211
244
|
// Snapshot the usage-ranked order when the dial opens. It stays stable while
|
|
212
245
|
// open so icons don't jump positions mid-interaction.
|
|
213
246
|
const [rankedIds, setRankedIds] = useState(() => getRankedToolIds(dialApps.map(a => a.id)));
|
|
@@ -226,7 +259,9 @@ export const DialDevTools = ({
|
|
|
226
259
|
cancelled = true;
|
|
227
260
|
};
|
|
228
261
|
}, [dialApps]);
|
|
229
|
-
|
|
262
|
+
|
|
263
|
+
// Page count spans available tools (usage-ranked) + unavailable tools (appended).
|
|
264
|
+
const pageCount = Math.max(1, Math.ceil((rankedIds.length + unavailableTools.length) / MAX_DIAL_SLOTS));
|
|
230
265
|
const [currentPage, setCurrentPage] = useState(0);
|
|
231
266
|
const safePage = Math.min(currentPage, pageCount - 1);
|
|
232
267
|
|
|
@@ -234,13 +269,18 @@ export const DialDevTools = ({
|
|
|
234
269
|
// snapshotted on open, so each icon's page and slot are fixed for the
|
|
235
270
|
// session — which lets us mount all icons once and paginate purely by
|
|
236
271
|
// toggling visibility (no remounts on page change).
|
|
272
|
+
//
|
|
273
|
+
// Order: usage-ranked available tools first, unavailable tools appended at
|
|
274
|
+
// the very end. This guarantees unavailable items always appear on the last
|
|
275
|
+
// pages and never displace available tools.
|
|
237
276
|
const allDialIcons = useMemo(() => {
|
|
238
|
-
|
|
277
|
+
const allIds = [...rankedIds, ...unavailableTools.map(t => t.id)];
|
|
278
|
+
return allIds.map(id => iconsById.get(id) ?? unavailableIconsById.get(id)).filter(icon => Boolean(icon)).map((icon, i) => ({
|
|
239
279
|
icon,
|
|
240
280
|
page: Math.floor(i / MAX_DIAL_SLOTS),
|
|
241
281
|
slot: i % MAX_DIAL_SLOTS
|
|
242
282
|
}));
|
|
243
|
-
}, [rankedIds, iconsById]);
|
|
283
|
+
}, [rankedIds, iconsById, unavailableTools, unavailableIconsById]);
|
|
244
284
|
|
|
245
285
|
// Empty slot indices for the current page (only the last page can be
|
|
246
286
|
// partial). These are cheap placeholder dots.
|
|
@@ -442,6 +482,10 @@ export const DialDevTools = ({
|
|
|
442
482
|
});
|
|
443
483
|
};
|
|
444
484
|
const handleIconPress = icon => {
|
|
485
|
+
// Unavailable tools are display-only. Return early so the dial stays open
|
|
486
|
+
// and no modal or animation is triggered. The dimmed appearance already
|
|
487
|
+
// communicates that the tool is not installed.
|
|
488
|
+
if (icon.unavailable) return;
|
|
445
489
|
setSelectedIcon(1);
|
|
446
490
|
const interaction = dialAnimationConfig?.interaction ?? {
|
|
447
491
|
iconSelect: {
|
|
@@ -609,8 +653,8 @@ export const DialDevTools = ({
|
|
|
609
653
|
style: styles.centerText,
|
|
610
654
|
children: "BUOY"
|
|
611
655
|
}), isPro && /*#__PURE__*/_jsx(Text, {
|
|
612
|
-
style: styles.proText,
|
|
613
|
-
children: "PRO"
|
|
656
|
+
style: [styles.proText, isWeekendFree && styles.weekendText],
|
|
657
|
+
children: isWeekendFree ? "WEEKEND" : "PRO"
|
|
614
658
|
})]
|
|
615
659
|
})
|
|
616
660
|
})
|
|
@@ -815,5 +859,11 @@ const styles = StyleSheet.create({
|
|
|
815
859
|
height: 0
|
|
816
860
|
},
|
|
817
861
|
textShadowRadius: 4
|
|
862
|
+
},
|
|
863
|
+
// Weekend Pass variant — violet, tighter spacing so "WEEKEND" fits the dial.
|
|
864
|
+
weekendText: {
|
|
865
|
+
color: "#BF5AF2",
|
|
866
|
+
letterSpacing: 1,
|
|
867
|
+
textShadowColor: "#BF5AF2"
|
|
818
868
|
}
|
|
819
869
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useMemo, useRef } from "react";
|
|
4
4
|
import { StyleSheet, Pressable, View, Text, useWindowDimensions, Animated } from "react-native";
|
|
5
|
-
import { getDialLayout, getIconPosition, getIconStaggerInputRange, DIAL_START_ANGLE, DIAL_ICON_SIZE, dialColors, dialStyles, dialAnimationConfig } from "@buoy-gg/floating-tools-core";
|
|
5
|
+
import { getDialLayout, getIconPosition, getIconStaggerInputRange, DIAL_START_ANGLE, DIAL_ICON_SIZE, dialColors, dialStyles, dialAnimationConfig, floatingToolsColors } from "@buoy-gg/floating-tools-core";
|
|
6
6
|
|
|
7
7
|
// The circle radius depends on the live window width and is computed inside
|
|
8
8
|
// the component (must match DialDevTools' circle, which does the same).
|
|
@@ -154,6 +154,32 @@ export const DialIcon = ({
|
|
|
154
154
|
children: /*#__PURE__*/_jsx(View, {
|
|
155
155
|
style: styles.emptyDot
|
|
156
156
|
})
|
|
157
|
+
}) : icon.unavailable ?
|
|
158
|
+
/*#__PURE__*/
|
|
159
|
+
// ── Unavailable tool ──────────────────────────────────────────────────
|
|
160
|
+
// Renders the real icon + real name at NORMAL styling (visually identical
|
|
161
|
+
// to an installed tool). The ONLY signal that it's unavailable is the small
|
|
162
|
+
// muted "Unavailable" caption under the name. It's non-interactive: no
|
|
163
|
+
// Pressable, and the dial stays open when tapped because
|
|
164
|
+
// DialDevTools.handleIconPress returns early for unavailable icons.
|
|
165
|
+
_jsxs(View, {
|
|
166
|
+
style: styles.pressable,
|
|
167
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
168
|
+
style: styles.iconWrapper,
|
|
169
|
+
children: icon.icon
|
|
170
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
171
|
+
style: styles.label,
|
|
172
|
+
numberOfLines: 1,
|
|
173
|
+
adjustsFontSizeToFit: true,
|
|
174
|
+
minimumFontScale: 0.7,
|
|
175
|
+
children: icon.name.toUpperCase()
|
|
176
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
177
|
+
style: styles.unavailableCaption,
|
|
178
|
+
numberOfLines: 1,
|
|
179
|
+
adjustsFontSizeToFit: true,
|
|
180
|
+
minimumFontScale: 0.6,
|
|
181
|
+
children: "Unavailable"
|
|
182
|
+
})]
|
|
157
183
|
}) : /*#__PURE__*/_jsxs(Pressable, {
|
|
158
184
|
onPress: () => onPress(icon),
|
|
159
185
|
onPressIn: handlePressIn,
|
|
@@ -244,5 +270,20 @@ const styles = StyleSheet.create({
|
|
|
244
270
|
backgroundColor: dialColors.emptyDotBackground,
|
|
245
271
|
borderWidth: dialStyles.emptySlot.borderWidth,
|
|
246
272
|
borderColor: dialColors.emptyDotBorder
|
|
273
|
+
},
|
|
274
|
+
// ── Unavailable tool styles ────────────────────────────────────────────────
|
|
275
|
+
/**
|
|
276
|
+
* Small muted caption shown under the (normal-styled) tool name — the only
|
|
277
|
+
* signal that the tool is not installed. Kept compact (smaller than the label)
|
|
278
|
+
* so the extra line doesn't disturb the arc layout. Uses the shared muted
|
|
279
|
+
* theme token rather than a hardcoded color.
|
|
280
|
+
*/
|
|
281
|
+
unavailableCaption: {
|
|
282
|
+
fontSize: dialStyles.icon.label.fontSize - 1,
|
|
283
|
+
fontWeight: dialStyles.icon.label.fontWeight,
|
|
284
|
+
letterSpacing: dialStyles.icon.label.letterSpacing,
|
|
285
|
+
fontFamily: dialStyles.icon.label.fontFamily,
|
|
286
|
+
color: floatingToolsColors.muted,
|
|
287
|
+
textTransform: "uppercase"
|
|
247
288
|
}
|
|
248
289
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingDevTools.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/FloatingDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+D,MAAM,OAAO,CAAC;AAGpF,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAMtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GACpB,MAAM,GACN;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACD;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EACR,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,GACP,KAAK,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC5E;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;IAEtB;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;IAEjC;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAEzC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3B;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAAC,EAAE,qBAAqB,CAAC;IAE7C;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IAErC;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,OAAO,oBAAoB,EAAE,WAAW,EAAE,CAAC;IAEnE;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,oBAAoB,EAAE,WAAW,KAAK,IAAI,CAAC;IAEtF;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEpC;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,gBAAgB,GAAI,gNAc9B,qBAAqB,
|
|
1
|
+
{"version":3,"file":"FloatingDevTools.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/FloatingDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+D,MAAM,OAAO,CAAC;AAGpF,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAMtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GACpB,MAAM,GACN;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACD;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EACR,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,GACP,KAAK,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC5E;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;IAEtB;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;IAEjC;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAEzC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3B;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAAC,EAAE,qBAAqB,CAAC;IAE7C;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IAErC;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,OAAO,oBAAoB,EAAE,WAAW,EAAE,CAAC;IAEnE;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,oBAAoB,EAAE,WAAW,KAAK,IAAI,CAAC;IAEtF;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEpC;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,gBAAgB,GAAI,gNAc9B,qBAAqB,6BAoQvB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical registry of ALL dial-eligible tools React Buoy offers on mobile.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth used to compute which tools are
|
|
5
|
+
* "unavailable" (offered but not installed in the current app). It lives
|
|
6
|
+
* inside the floating-menu package so nothing outside needs to be imported.
|
|
7
|
+
*
|
|
8
|
+
* Rules for this file:
|
|
9
|
+
* - Only import from REQUIRED dependencies (@buoy-gg/floating-tools-core,
|
|
10
|
+
* @buoy-gg/shared-ui, react-native) so the icons are always resolvable,
|
|
11
|
+
* even when the optional tool packages are not installed.
|
|
12
|
+
* - Only include tools whose preset slot is NOT "row" (row-only tools never
|
|
13
|
+
* appear in the dial and have no "unavailable" state to show).
|
|
14
|
+
* - Keep the order intentional: this order is the fallback when no usage
|
|
15
|
+
* data exists for new/unavailable tools.
|
|
16
|
+
*/
|
|
17
|
+
import React from "react";
|
|
18
|
+
export interface AllToolsEntry {
|
|
19
|
+
/** Unique tool ID — must match the preset id from the tool's package */
|
|
20
|
+
id: string;
|
|
21
|
+
/** Display name (shown in the dial + unavailable label) */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Accent color */
|
|
24
|
+
color: string;
|
|
25
|
+
/** Icon render function — receives the requested pixel size */
|
|
26
|
+
renderIcon: (size: number) => React.ReactNode;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Full list of every dial-eligible tool React Buoy offers on mobile.
|
|
30
|
+
*
|
|
31
|
+
* Available (installed) tools are shown normally in the dial.
|
|
32
|
+
* Unavailable (not installed) tools are appended at the end of the dial and look
|
|
33
|
+
* like a normal item (real icon + real name) with a small muted "Unavailable"
|
|
34
|
+
* caption added; they are non-interactive.
|
|
35
|
+
*
|
|
36
|
+
* To add a new tool to Buoy:
|
|
37
|
+
* 1. Add its preset to autoDiscoverPresets.ts
|
|
38
|
+
* 2. Add an entry here so it appears in the "unavailable" section for apps
|
|
39
|
+
* that haven't installed it yet.
|
|
40
|
+
*/
|
|
41
|
+
export declare const ALL_TOOLS_REGISTRY: AllToolsEntry[];
|
|
42
|
+
//# sourceMappingURL=allToolsRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allToolsRegistry.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/allToolsRegistry.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAgE1B,MAAM,WAAW,aAAa;IAC5B,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;CAC/C;AAID;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAAa,EAyE7C,CAAC"}
|
|
@@ -15,7 +15,11 @@ interface AutoExternalSyncProps {
|
|
|
15
15
|
options?: ExternalSyncOptions;
|
|
16
16
|
/** FloatingDevTools' requiredEnvVars — reused for the env tool's adapter. */
|
|
17
17
|
requiredEnvVars?: EnvVarConfig[];
|
|
18
|
+
/** Pro status, forwarded into the handshake so the dashboard can adopt it. */
|
|
19
|
+
isPro?: boolean;
|
|
20
|
+
/** Pro license key, forwarded into the handshake alongside `isPro`. */
|
|
21
|
+
licenseKey?: string | null;
|
|
18
22
|
}
|
|
19
|
-
export declare function AutoExternalSync({ options, requiredEnvVars, }: AutoExternalSyncProps): null;
|
|
23
|
+
export declare function AutoExternalSync({ options, requiredEnvVars, isPro, licenseKey, }: AutoExternalSyncProps): null;
|
|
20
24
|
export {};
|
|
21
25
|
//# sourceMappingURL=autoExternalSync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoExternalSync.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/autoExternalSync.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"autoExternalSync.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/autoExternalSync.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA8GvD,iFAAiF;AACjF,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AAED,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAuBD,UAAU,qBAAqB;IAC7B,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;IACjC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,eAAe,EACf,KAAK,EACL,UAAU,GACX,EAAE,qBAAqB,QAqGvB"}
|
|
@@ -19,6 +19,13 @@ export type IconType = {
|
|
|
19
19
|
}) => ReactNode;
|
|
20
20
|
color: string;
|
|
21
21
|
onPress: () => void;
|
|
22
|
+
/**
|
|
23
|
+
* True for tools that React Buoy offers but the current app has not installed.
|
|
24
|
+
* Unavailable items render like a normal item (real icon + real name at full
|
|
25
|
+
* styling) plus a small muted "Unavailable" caption, and are non-interactive
|
|
26
|
+
* (tapping does nothing and keeps the dial open).
|
|
27
|
+
*/
|
|
28
|
+
unavailable?: boolean;
|
|
22
29
|
};
|
|
23
30
|
interface DialDevToolsProps {
|
|
24
31
|
onClose?: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialDevTools.d.ts","sourceRoot":"","sources":["../../../../../src/floatingMenu/dial/DialDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAwC,SAAS,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"DialDevTools.d.ts","sourceRoot":"","sources":["../../../../../src/floatingMenu/dial/DialDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAwC,SAAS,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAgC5E,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAqBlB,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,iBAAiB,CAAC;QAAC,OAAO,CAAC,EAAE,mBAAmB,CAAA;KAAE,KAAK,SAAS,CAAC;IAC/H,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAWF,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAmrB9C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialIcon.d.ts","sourceRoot":"","sources":["../../../../../src/floatingMenu/dial/DialIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,EAAE,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAML,QAAQ,EACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"DialIcon.d.ts","sourceRoot":"","sources":["../../../../../src/floatingMenu/dial/DialIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,EAAE,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAML,QAAQ,EACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAiB1C,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,KAAK,CAwO9B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingDevTools.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/FloatingDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+D,MAAM,OAAO,CAAC;AAGpF,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAMtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GACpB,MAAM,GACN;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACD;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EACR,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,GACP,KAAK,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC5E;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;IAEtB;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;IAEjC;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAEzC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3B;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAAC,EAAE,qBAAqB,CAAC;IAE7C;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IAErC;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,OAAO,oBAAoB,EAAE,WAAW,EAAE,CAAC;IAEnE;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,oBAAoB,EAAE,WAAW,KAAK,IAAI,CAAC;IAEtF;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEpC;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,gBAAgB,GAAI,gNAc9B,qBAAqB,
|
|
1
|
+
{"version":3,"file":"FloatingDevTools.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/FloatingDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+D,MAAM,OAAO,CAAC;AAGpF,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAMtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EAEvB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,YAAY,GACpB,MAAM,GACN;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACD;IACE,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EACR,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,GACP,KAAK,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEN;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC5E;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC;IAEtB;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;IAEjC;;;;;;;;;;;;OAYG;IACH,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAEzC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE3B;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;;;;;;;;;;OAaG;IACH,oBAAoB,CAAC,EAAE,qBAAqB,CAAC;IAE7C;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IAErC;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,OAAO,oBAAoB,EAAE,WAAW,EAAE,CAAC;IAEnE;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,oBAAoB,EAAE,WAAW,KAAK,IAAI,CAAC;IAEtF;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEpC;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAC;CAC9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,eAAO,MAAM,gBAAgB,GAAI,gNAc9B,qBAAqB,6BAoQvB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical registry of ALL dial-eligible tools React Buoy offers on mobile.
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth used to compute which tools are
|
|
5
|
+
* "unavailable" (offered but not installed in the current app). It lives
|
|
6
|
+
* inside the floating-menu package so nothing outside needs to be imported.
|
|
7
|
+
*
|
|
8
|
+
* Rules for this file:
|
|
9
|
+
* - Only import from REQUIRED dependencies (@buoy-gg/floating-tools-core,
|
|
10
|
+
* @buoy-gg/shared-ui, react-native) so the icons are always resolvable,
|
|
11
|
+
* even when the optional tool packages are not installed.
|
|
12
|
+
* - Only include tools whose preset slot is NOT "row" (row-only tools never
|
|
13
|
+
* appear in the dial and have no "unavailable" state to show).
|
|
14
|
+
* - Keep the order intentional: this order is the fallback when no usage
|
|
15
|
+
* data exists for new/unavailable tools.
|
|
16
|
+
*/
|
|
17
|
+
import React from "react";
|
|
18
|
+
export interface AllToolsEntry {
|
|
19
|
+
/** Unique tool ID — must match the preset id from the tool's package */
|
|
20
|
+
id: string;
|
|
21
|
+
/** Display name (shown in the dial + unavailable label) */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Accent color */
|
|
24
|
+
color: string;
|
|
25
|
+
/** Icon render function — receives the requested pixel size */
|
|
26
|
+
renderIcon: (size: number) => React.ReactNode;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Full list of every dial-eligible tool React Buoy offers on mobile.
|
|
30
|
+
*
|
|
31
|
+
* Available (installed) tools are shown normally in the dial.
|
|
32
|
+
* Unavailable (not installed) tools are appended at the end of the dial and look
|
|
33
|
+
* like a normal item (real icon + real name) with a small muted "Unavailable"
|
|
34
|
+
* caption added; they are non-interactive.
|
|
35
|
+
*
|
|
36
|
+
* To add a new tool to Buoy:
|
|
37
|
+
* 1. Add its preset to autoDiscoverPresets.ts
|
|
38
|
+
* 2. Add an entry here so it appears in the "unavailable" section for apps
|
|
39
|
+
* that haven't installed it yet.
|
|
40
|
+
*/
|
|
41
|
+
export declare const ALL_TOOLS_REGISTRY: AllToolsEntry[];
|
|
42
|
+
//# sourceMappingURL=allToolsRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allToolsRegistry.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/allToolsRegistry.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAgE1B,MAAM,WAAW,aAAa;IAC5B,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;CAC/C;AAID;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kBAAkB,EAAE,aAAa,EAyE7C,CAAC"}
|
|
@@ -15,7 +15,11 @@ interface AutoExternalSyncProps {
|
|
|
15
15
|
options?: ExternalSyncOptions;
|
|
16
16
|
/** FloatingDevTools' requiredEnvVars — reused for the env tool's adapter. */
|
|
17
17
|
requiredEnvVars?: EnvVarConfig[];
|
|
18
|
+
/** Pro status, forwarded into the handshake so the dashboard can adopt it. */
|
|
19
|
+
isPro?: boolean;
|
|
20
|
+
/** Pro license key, forwarded into the handshake alongside `isPro`. */
|
|
21
|
+
licenseKey?: string | null;
|
|
18
22
|
}
|
|
19
|
-
export declare function AutoExternalSync({ options, requiredEnvVars, }: AutoExternalSyncProps): null;
|
|
23
|
+
export declare function AutoExternalSync({ options, requiredEnvVars, isPro, licenseKey, }: AutoExternalSyncProps): null;
|
|
20
24
|
export {};
|
|
21
25
|
//# sourceMappingURL=autoExternalSync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoExternalSync.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/autoExternalSync.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"autoExternalSync.d.ts","sourceRoot":"","sources":["../../../../src/floatingMenu/autoExternalSync.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA8GvD,iFAAiF;AACjF,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AAED,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qBAAqB;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAuBD,UAAU,qBAAqB;IAC7B,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;IACjC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,eAAe,EACf,KAAK,EACL,UAAU,GACX,EAAE,qBAAqB,QAqGvB"}
|
|
@@ -19,6 +19,13 @@ export type IconType = {
|
|
|
19
19
|
}) => ReactNode;
|
|
20
20
|
color: string;
|
|
21
21
|
onPress: () => void;
|
|
22
|
+
/**
|
|
23
|
+
* True for tools that React Buoy offers but the current app has not installed.
|
|
24
|
+
* Unavailable items render like a normal item (real icon + real name at full
|
|
25
|
+
* styling) plus a small muted "Unavailable" caption, and are non-interactive
|
|
26
|
+
* (tapping does nothing and keeps the dial open).
|
|
27
|
+
*/
|
|
28
|
+
unavailable?: boolean;
|
|
22
29
|
};
|
|
23
30
|
interface DialDevToolsProps {
|
|
24
31
|
onClose?: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialDevTools.d.ts","sourceRoot":"","sources":["../../../../../src/floatingMenu/dial/DialDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAwC,SAAS,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"DialDevTools.d.ts","sourceRoot":"","sources":["../../../../../src/floatingMenu/dial/DialDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAwC,SAAS,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAgC5E,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAqBlB,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,iBAAiB,CAAC;QAAC,OAAO,CAAC,EAAE,mBAAmB,CAAA;KAAE,KAAK,SAAS,CAAC;IAC/H,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAWF,UAAU,iBAAiB;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAmrB9C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialIcon.d.ts","sourceRoot":"","sources":["../../../../../src/floatingMenu/dial/DialIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,EAAE,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAML,QAAQ,EACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"DialIcon.d.ts","sourceRoot":"","sources":["../../../../../src/floatingMenu/dial/DialIcon.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,EAAE,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAML,QAAQ,EACT,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAiB1C,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,EAAE,QAAQ,CAAC,KAAK,CAAC;IAC9B,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,KAAK,CAwO9B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "Floating dev tools launcher and AppHost",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
],
|
|
23
23
|
"sideEffects": false,
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@buoy-gg/shared-ui": "
|
|
26
|
-
"@buoy-gg/floating-tools-
|
|
27
|
-
"@buoy-gg/license": "
|
|
28
|
-
"@buoy-gg/floating-tools-
|
|
25
|
+
"@buoy-gg/shared-ui": "4.0.1",
|
|
26
|
+
"@buoy-gg/floating-tools-core": "4.0.1",
|
|
27
|
+
"@buoy-gg/license": "4.0.1",
|
|
28
|
+
"@buoy-gg/floating-tools-react": "4.0.1"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"react": "*",
|