@buoy-gg/core 7.0.16 → 7.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/floatingMenu/AppHost.js +23 -3
- package/lib/commonjs/floatingMenu/AppHost.web.js +6 -1
- package/lib/commonjs/floatingMenu/AppIcon.js +91 -0
- package/lib/commonjs/floatingMenu/FloatingDevTools.js +15 -9
- package/lib/commonjs/floatingMenu/FloatingMenu.js +14 -7
- package/lib/commonjs/floatingMenu/ToolHost.js +274 -0
- package/lib/commonjs/floatingMenu/allToolsRegistry.js +7 -0
- package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +16 -0
- package/lib/commonjs/floatingMenu/autoExternalSync.js +21 -2
- package/lib/commonjs/floatingMenu/dial/DialDevTools.js +15 -7
- package/lib/commonjs/index.js +27 -0
- package/lib/commonjs/toolkit.js +584 -0
- package/lib/commonjs/toolkitComponents.js +241 -0
- package/lib/module/floatingMenu/AppHost.js +23 -3
- package/lib/module/floatingMenu/AppHost.web.js +6 -1
- package/lib/module/floatingMenu/AppIcon.js +84 -0
- package/lib/module/floatingMenu/FloatingDevTools.js +15 -9
- package/lib/module/floatingMenu/FloatingMenu.js +14 -7
- package/lib/module/floatingMenu/ToolHost.js +266 -0
- package/lib/module/floatingMenu/allToolsRegistry.js +8 -1
- package/lib/module/floatingMenu/autoDiscoverPresets.js +16 -0
- package/lib/module/floatingMenu/autoExternalSync.js +21 -2
- package/lib/module/floatingMenu/dial/DialDevTools.js +15 -7
- package/lib/module/index.js +6 -0
- package/lib/module/toolkit.js +62 -0
- package/lib/module/toolkitComponents.js +230 -0
- package/lib/typescript/commonjs/floatingMenu/AppHost.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts +3 -0
- package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/AppIcon.d.ts +30 -0
- package/lib/typescript/commonjs/floatingMenu/AppIcon.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/ToolHost.d.ts +77 -0
- package/lib/typescript/commonjs/floatingMenu/ToolHost.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/allToolsRegistry.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts +8 -1
- package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +1 -1
- package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
- package/lib/typescript/commonjs/floatingMenu/types.d.ts +62 -2
- package/lib/typescript/commonjs/floatingMenu/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/toolkit.d.ts +31 -0
- package/lib/typescript/commonjs/toolkit.d.ts.map +1 -0
- package/lib/typescript/commonjs/toolkitComponents.d.ts +61 -0
- package/lib/typescript/commonjs/toolkitComponents.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/AppHost.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/AppHost.web.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts +3 -0
- package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/AppIcon.d.ts +30 -0
- package/lib/typescript/module/floatingMenu/AppIcon.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/ToolHost.d.ts +77 -0
- package/lib/typescript/module/floatingMenu/ToolHost.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/allToolsRegistry.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts +8 -1
- package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +1 -1
- package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
- package/lib/typescript/module/floatingMenu/types.d.ts +62 -2
- package/lib/typescript/module/floatingMenu/types.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/toolkit.d.ts +31 -0
- package/lib/typescript/module/toolkit.d.ts.map +1 -0
- package/lib/typescript/module/toolkitComponents.d.ts +61 -0
- package/lib/typescript/module/toolkitComponents.d.ts.map +1 -0
- package/package.json +19 -5
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ToolHost — the declarative chrome layer for custom tools.
|
|
5
|
+
*
|
|
6
|
+
* When an `InstalledApp` declares `modal: {...}`, the AppHost renders its
|
|
7
|
+
* component inside `ToolModalShell` instead of raw: the shared JsModal
|
|
8
|
+
* (drag/resize, floating⇄bottom-sheet, minimize, dimension persistence) plus
|
|
9
|
+
* a managed header (title/subtitle, back navigation, search, actions) and a
|
|
10
|
+
* lightweight toast layer. The tool body talks back to the shell through
|
|
11
|
+
* `useToolHost()` / `useToolHeader()`.
|
|
12
|
+
*/
|
|
13
|
+
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
14
|
+
import { Animated, StyleSheet, Text, View } from "react-native";
|
|
15
|
+
import { JsModal, ModalHeader, HeaderSearchButton, TickProvider, devToolsStorageKeys, buoyColors, gameUIColors } from "@buoy-gg/shared-ui";
|
|
16
|
+
|
|
17
|
+
/** Per-screen header overrides a tool body can apply (see `useToolHeader`). */
|
|
18
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
|
+
const noop = () => {};
|
|
20
|
+
const FALLBACK_CONTEXT = {
|
|
21
|
+
search: "",
|
|
22
|
+
isSearchActive: false,
|
|
23
|
+
clearSearch: noop,
|
|
24
|
+
close: noop,
|
|
25
|
+
showToast: noop,
|
|
26
|
+
setHeaderOverride: noop
|
|
27
|
+
};
|
|
28
|
+
const ToolHostContext = /*#__PURE__*/createContext(null);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Access the hosting shell from a custom tool body: search query, toasts,
|
|
32
|
+
* close. Safe to call outside the shell (returns inert no-ops) so tool
|
|
33
|
+
* components can also be mounted standalone.
|
|
34
|
+
*/
|
|
35
|
+
export function useToolHost() {
|
|
36
|
+
return useContext(ToolHostContext) ?? FALLBACK_CONTEXT;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Declare per-screen header state (title/subtitle/actions/back) from inside a
|
|
41
|
+
* tool body. Applies while the calling component is mounted and reverts to
|
|
42
|
+
* the preset's static config on unmount — so a detail screen simply mounts
|
|
43
|
+
* with its own header and the list header returns when it unmounts.
|
|
44
|
+
*
|
|
45
|
+
* ```tsx
|
|
46
|
+
* useToolHeader(
|
|
47
|
+
* { title: flag.key, onBack: () => setScreen("list"), actions: <CopyButton value={flag} /> },
|
|
48
|
+
* [flag.key]
|
|
49
|
+
* );
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function useToolHeader(override, deps) {
|
|
53
|
+
const {
|
|
54
|
+
setHeaderOverride
|
|
55
|
+
} = useToolHost();
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
setHeaderOverride(override);
|
|
58
|
+
return () => setHeaderOverride(null);
|
|
59
|
+
// Caller-provided deps intentionally control when the override refreshes.
|
|
60
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
61
|
+
}, deps);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Toast layer
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
const TOAST_DURATION_MS = 2200;
|
|
69
|
+
const TOAST_COLORS = {
|
|
70
|
+
success: gameUIColors.success,
|
|
71
|
+
error: gameUIColors.error,
|
|
72
|
+
info: gameUIColors.info
|
|
73
|
+
};
|
|
74
|
+
function ToastView({
|
|
75
|
+
message,
|
|
76
|
+
type,
|
|
77
|
+
nonce
|
|
78
|
+
}) {
|
|
79
|
+
const opacity = useRef(new Animated.Value(0)).current;
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
opacity.setValue(0);
|
|
82
|
+
Animated.sequence([Animated.timing(opacity, {
|
|
83
|
+
toValue: 1,
|
|
84
|
+
duration: 150,
|
|
85
|
+
useNativeDriver: true
|
|
86
|
+
}), Animated.delay(TOAST_DURATION_MS - 450), Animated.timing(opacity, {
|
|
87
|
+
toValue: 0,
|
|
88
|
+
duration: 300,
|
|
89
|
+
useNativeDriver: true
|
|
90
|
+
})]).start();
|
|
91
|
+
}, [nonce, opacity]);
|
|
92
|
+
const color = TOAST_COLORS[type];
|
|
93
|
+
return /*#__PURE__*/_jsxs(Animated.View, {
|
|
94
|
+
pointerEvents: "none",
|
|
95
|
+
style: [styles.toast, {
|
|
96
|
+
opacity,
|
|
97
|
+
borderColor: color + "60"
|
|
98
|
+
}],
|
|
99
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
100
|
+
style: [styles.toastDot, {
|
|
101
|
+
backgroundColor: color
|
|
102
|
+
}]
|
|
103
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
104
|
+
style: styles.toastText,
|
|
105
|
+
numberOfLines: 2,
|
|
106
|
+
children: message
|
|
107
|
+
})]
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// Shell
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
export function ToolModalShell({
|
|
116
|
+
app,
|
|
117
|
+
config,
|
|
118
|
+
visible,
|
|
119
|
+
zIndex,
|
|
120
|
+
onClose,
|
|
121
|
+
onMinimize,
|
|
122
|
+
initialModalState,
|
|
123
|
+
enableSharedModalDimensions,
|
|
124
|
+
bodyProps
|
|
125
|
+
}) {
|
|
126
|
+
const Body = app.component;
|
|
127
|
+
const [isSearchActive, setIsSearchActive] = useState(false);
|
|
128
|
+
const [search, setSearch] = useState("");
|
|
129
|
+
const [headerOverride, setHeaderOverride] = useState(null);
|
|
130
|
+
const [toast, setToast] = useState(null);
|
|
131
|
+
const toastTimeoutRef = useRef(null);
|
|
132
|
+
const clearSearch = useCallback(() => {
|
|
133
|
+
setIsSearchActive(false);
|
|
134
|
+
setSearch("");
|
|
135
|
+
}, []);
|
|
136
|
+
const showToast = useCallback((message, type = "info") => {
|
|
137
|
+
if (toastTimeoutRef.current) clearTimeout(toastTimeoutRef.current);
|
|
138
|
+
setToast(prev => ({
|
|
139
|
+
message,
|
|
140
|
+
type,
|
|
141
|
+
nonce: (prev?.nonce ?? 0) + 1
|
|
142
|
+
}));
|
|
143
|
+
toastTimeoutRef.current = setTimeout(() => setToast(null), TOAST_DURATION_MS);
|
|
144
|
+
}, []);
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
return () => {
|
|
147
|
+
if (toastTimeoutRef.current) clearTimeout(toastTimeoutRef.current);
|
|
148
|
+
};
|
|
149
|
+
}, []);
|
|
150
|
+
const contextValue = useMemo(() => ({
|
|
151
|
+
search: isSearchActive ? search : "",
|
|
152
|
+
isSearchActive,
|
|
153
|
+
clearSearch,
|
|
154
|
+
close: onClose,
|
|
155
|
+
showToast,
|
|
156
|
+
setHeaderOverride,
|
|
157
|
+
instanceId: app.instanceId
|
|
158
|
+
}), [search, isSearchActive, clearSearch, onClose, showToast, app.instanceId]);
|
|
159
|
+
const title = headerOverride?.title ?? config.title ?? app.title ?? app.id;
|
|
160
|
+
const subtitle = headerOverride?.subtitle ?? config.subtitle;
|
|
161
|
+
const onBack = headerOverride?.onBack;
|
|
162
|
+
const actions = headerOverride?.actions ?? config.headerActions;
|
|
163
|
+
const searchable = headerOverride?.searchable ?? config.searchable;
|
|
164
|
+
|
|
165
|
+
// A screen that hides search while it's open would strand the input with
|
|
166
|
+
// no way to dismiss it — close it on entry instead.
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
if (!searchable && isSearchActive) clearSearch();
|
|
169
|
+
}, [searchable, isSearchActive, clearSearch]);
|
|
170
|
+
|
|
171
|
+
// Tool-scoped persistence via the custom namespace unless the user has the
|
|
172
|
+
// shared-dimensions global setting on (all tools share one window size).
|
|
173
|
+
const persistenceKey = enableSharedModalDimensions ? devToolsStorageKeys.modal.root() : devToolsStorageKeys.custom(app.id).modal();
|
|
174
|
+
const header = /*#__PURE__*/_jsxs(ModalHeader, {
|
|
175
|
+
children: [onBack && !isSearchActive && /*#__PURE__*/_jsx(ModalHeader.Navigation, {
|
|
176
|
+
onBack: onBack
|
|
177
|
+
}), isSearchActive ? /*#__PURE__*/_jsx(ModalHeader.Search, {
|
|
178
|
+
value: search,
|
|
179
|
+
onChangeText: setSearch,
|
|
180
|
+
onCancel: clearSearch,
|
|
181
|
+
placeholder: config.searchPlaceholder
|
|
182
|
+
}) : /*#__PURE__*/_jsx(ModalHeader.Content, {
|
|
183
|
+
title: title,
|
|
184
|
+
subtitle: subtitle
|
|
185
|
+
}), /*#__PURE__*/_jsxs(ModalHeader.Actions, {
|
|
186
|
+
children: [!isSearchActive && actions, searchable && !isSearchActive && /*#__PURE__*/_jsx(HeaderSearchButton, {
|
|
187
|
+
testID: `tool-search-${app.id}`,
|
|
188
|
+
onPress: () => setIsSearchActive(true)
|
|
189
|
+
})]
|
|
190
|
+
})]
|
|
191
|
+
});
|
|
192
|
+
return /*#__PURE__*/_jsx(ToolHostContext.Provider, {
|
|
193
|
+
value: contextValue,
|
|
194
|
+
children: /*#__PURE__*/_jsx(JsModal, {
|
|
195
|
+
visible: visible,
|
|
196
|
+
onClose: onClose,
|
|
197
|
+
onBack: onBack,
|
|
198
|
+
onMinimize: onMinimize,
|
|
199
|
+
initialModalState: initialModalState,
|
|
200
|
+
zIndex: zIndex,
|
|
201
|
+
persistenceKey: persistenceKey,
|
|
202
|
+
enablePersistence: true,
|
|
203
|
+
initialMode: config.initialMode ?? "bottomSheet",
|
|
204
|
+
header: {
|
|
205
|
+
customContent: header,
|
|
206
|
+
showToggleButton: true
|
|
207
|
+
}
|
|
208
|
+
// Tool bodies own their scrolling (ScrollView/FlatList) — the shell
|
|
209
|
+
// must not add a competing wrapper.
|
|
210
|
+
,
|
|
211
|
+
disableScrollWrapper: true,
|
|
212
|
+
styles: {},
|
|
213
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
214
|
+
style: styles.bodyRoot,
|
|
215
|
+
children: [/*#__PURE__*/_jsx(TickProvider, {
|
|
216
|
+
children: /*#__PURE__*/_jsx(Body, {
|
|
217
|
+
...bodyProps
|
|
218
|
+
})
|
|
219
|
+
}), toast && /*#__PURE__*/_jsx(ToastView, {
|
|
220
|
+
message: toast.message,
|
|
221
|
+
type: toast.type,
|
|
222
|
+
nonce: toast.nonce
|
|
223
|
+
})]
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
const styles = StyleSheet.create({
|
|
229
|
+
bodyRoot: {
|
|
230
|
+
flex: 1,
|
|
231
|
+
minHeight: 0,
|
|
232
|
+
backgroundColor: buoyColors.base
|
|
233
|
+
},
|
|
234
|
+
toast: {
|
|
235
|
+
position: "absolute",
|
|
236
|
+
bottom: 16,
|
|
237
|
+
alignSelf: "center",
|
|
238
|
+
flexDirection: "row",
|
|
239
|
+
alignItems: "center",
|
|
240
|
+
gap: 8,
|
|
241
|
+
maxWidth: "86%",
|
|
242
|
+
backgroundColor: buoyColors.card,
|
|
243
|
+
borderWidth: 1,
|
|
244
|
+
borderRadius: 8,
|
|
245
|
+
paddingHorizontal: 12,
|
|
246
|
+
paddingVertical: 8,
|
|
247
|
+
shadowColor: "#000",
|
|
248
|
+
shadowOpacity: 0.4,
|
|
249
|
+
shadowRadius: 8,
|
|
250
|
+
shadowOffset: {
|
|
251
|
+
width: 0,
|
|
252
|
+
height: 2
|
|
253
|
+
},
|
|
254
|
+
elevation: 6
|
|
255
|
+
},
|
|
256
|
+
toastDot: {
|
|
257
|
+
width: 6,
|
|
258
|
+
height: 6,
|
|
259
|
+
borderRadius: 3
|
|
260
|
+
},
|
|
261
|
+
toastText: {
|
|
262
|
+
flex: 1,
|
|
263
|
+
fontSize: 12,
|
|
264
|
+
color: buoyColors.text
|
|
265
|
+
}
|
|
266
|
+
});
|
|
@@ -27,7 +27,7 @@ import { ImageOverlayIcon } from "@buoy-gg/shared-ui";
|
|
|
27
27
|
// in shared/icons/*.json and generated into @buoy-gg/floating-tools-core, which
|
|
28
28
|
// IS a required dependency. Unavailable items therefore render the ACTUAL tool
|
|
29
29
|
// icon (just dimmed by DialIcon), and it can no longer drift from the real one.
|
|
30
|
-
import { ZustandIcon, ZUSTAND_ICON_COLOR, JotaiIcon, JOTAI_ICON_COLOR, IMAGE_OVERLAY_ICON_COLOR } from "@buoy-gg/floating-tools-core";
|
|
30
|
+
import { ZustandIcon, ZUSTAND_ICON_COLOR, JotaiIcon, JOTAI_ICON_COLOR, IMAGE_OVERLAY_ICON_COLOR, TimeMachineIcon, TIME_MACHINE_ICON_COLOR } from "@buoy-gg/floating-tools-core";
|
|
31
31
|
|
|
32
32
|
// ─── Registry entry type ──────────────────────────────────────────────────────
|
|
33
33
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -109,6 +109,13 @@ export const ALL_TOOLS_REGISTRY = [{
|
|
|
109
109
|
renderIcon: size => /*#__PURE__*/_jsx(EventsIcon, {
|
|
110
110
|
size: size
|
|
111
111
|
})
|
|
112
|
+
}, {
|
|
113
|
+
id: "time-machine",
|
|
114
|
+
name: "TIME MACHINE",
|
|
115
|
+
color: TIME_MACHINE_ICON_COLOR,
|
|
116
|
+
renderIcon: size => /*#__PURE__*/_jsx(TimeMachineIcon, {
|
|
117
|
+
size: size
|
|
118
|
+
})
|
|
112
119
|
}, {
|
|
113
120
|
id: "jotai",
|
|
114
121
|
name: "JOTAI",
|
|
@@ -185,6 +185,22 @@ export function autoDiscoverPresets() {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
},
|
|
188
|
+
// Time Machine
|
|
189
|
+
{
|
|
190
|
+
name: "@buoy-gg/time-machine",
|
|
191
|
+
loader: () => {
|
|
192
|
+
try {
|
|
193
|
+
// @ts-ignore - Dynamic import that may not exist
|
|
194
|
+
const {
|
|
195
|
+
timeMachineToolPreset
|
|
196
|
+
} = require("@buoy-gg/time-machine");
|
|
197
|
+
return timeMachineToolPreset;
|
|
198
|
+
} catch (e) {
|
|
199
|
+
reportOptionalRequireError("@buoy-gg/time-machine", e);
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
},
|
|
188
204
|
// Redux DevTools
|
|
189
205
|
{
|
|
190
206
|
name: "@buoy-gg/redux",
|
|
@@ -39,6 +39,7 @@ let zustandModule = null;
|
|
|
39
39
|
let jotaiModule = null;
|
|
40
40
|
let eventsModule = null;
|
|
41
41
|
let consoleModule = null;
|
|
42
|
+
let timeMachineModule = null;
|
|
42
43
|
let envModule = null;
|
|
43
44
|
let highlightUpdatesModule = null;
|
|
44
45
|
let debugBordersModule = null;
|
|
@@ -102,6 +103,11 @@ try {
|
|
|
102
103
|
} catch (e) {
|
|
103
104
|
reportOptionalRequireError("@buoy-gg/console", e);
|
|
104
105
|
}
|
|
106
|
+
try {
|
|
107
|
+
timeMachineModule = require("@buoy-gg/time-machine");
|
|
108
|
+
} catch (e) {
|
|
109
|
+
reportOptionalRequireError("@buoy-gg/time-machine", e);
|
|
110
|
+
}
|
|
105
111
|
try {
|
|
106
112
|
envModule = require("@buoy-gg/env");
|
|
107
113
|
} catch (e) {
|
|
@@ -169,7 +175,8 @@ export function AutoExternalSync({
|
|
|
169
175
|
options,
|
|
170
176
|
requiredEnvVars,
|
|
171
177
|
isPro,
|
|
172
|
-
licenseKey
|
|
178
|
+
licenseKey,
|
|
179
|
+
customApps
|
|
173
180
|
}) {
|
|
174
181
|
const {
|
|
175
182
|
useExternalSyncSocket,
|
|
@@ -255,6 +262,9 @@ export function AutoExternalSync({
|
|
|
255
262
|
if (consoleModule?.consoleSyncAdapter) {
|
|
256
263
|
map.console = consoleModule.consoleSyncAdapter;
|
|
257
264
|
}
|
|
265
|
+
if (timeMachineModule?.timeMachineSyncAdapter) {
|
|
266
|
+
map["time-machine"] = timeMachineModule.timeMachineSyncAdapter;
|
|
267
|
+
}
|
|
258
268
|
if (envModule?.createEnvSyncAdapter) {
|
|
259
269
|
map.env = envModule.createEnvSyncAdapter(requiredEnvVars ?? []);
|
|
260
270
|
}
|
|
@@ -279,8 +289,17 @@ export function AutoExternalSync({
|
|
|
279
289
|
if (assetsModule?.assetsSyncAdapter) {
|
|
280
290
|
map.assets = assetsModule.assetsSyncAdapter;
|
|
281
291
|
}
|
|
292
|
+
|
|
293
|
+
// Third-party custom tools that declared InstalledApp.sync. Namespaced so
|
|
294
|
+
// a custom tool named "network" can't shadow the first-party adapter on
|
|
295
|
+
// the broker, in MCP call_action, or in desktop watch state.
|
|
296
|
+
for (const app of customApps ?? []) {
|
|
297
|
+
if (app?.sync) {
|
|
298
|
+
map[`custom:${app.id}`] = app.sync;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
282
301
|
return map;
|
|
283
|
-
}, [queryAdapter, requiredEnvVars]);
|
|
302
|
+
}, [queryAdapter, requiredEnvVars, customApps]);
|
|
284
303
|
useExternalSync({
|
|
285
304
|
tools,
|
|
286
305
|
socket,
|
|
@@ -11,6 +11,7 @@ import { getRankedToolIds, isDialUsageLoaded, loadDialUsage, recordToolUsage } f
|
|
|
11
11
|
import { persistentStorage, useHintsDisabled, devToolsStorageKeys, buoyColors } from "@buoy-gg/shared-ui";
|
|
12
12
|
import { DevToolsSettingsModal, useDevToolsSettings } from "../DevToolsSettingsModal";
|
|
13
13
|
import { useProAccess } from "@buoy-gg/license";
|
|
14
|
+
import { renderAppIcon } from "../AppIcon.js";
|
|
14
15
|
import { useAppHost } from "../AppHost";
|
|
15
16
|
import { OnboardingTooltip } from "./OnboardingTooltip";
|
|
16
17
|
import { getDialLayout, MAX_DIAL_SLOTS, DIAL_BUTTON_SIZE, DIAL_ICON_GLYPH_SIZE, dialAnimationConfig, dialColors } from "@buoy-gg/floating-tools-core";
|
|
@@ -172,9 +173,14 @@ export const DialDevTools = ({
|
|
|
172
173
|
map.set(app.id, {
|
|
173
174
|
id: app.id,
|
|
174
175
|
name: app.name,
|
|
175
|
-
// Pass both the pre-rendered icon (for non-function icons
|
|
176
|
-
// component (for dynamic
|
|
177
|
-
|
|
176
|
+
// Pass both the pre-rendered icon (for non-function icons; strings
|
|
177
|
+
// resolve to auto-fitting text icons) and the component (for dynamic
|
|
178
|
+
// rendering).
|
|
179
|
+
icon: typeof app.icon === "function" ? null : renderAppIcon(app.icon, {
|
|
180
|
+
slot: "dial",
|
|
181
|
+
size: 20,
|
|
182
|
+
color: app.color
|
|
183
|
+
}),
|
|
178
184
|
// Cast to the expected type - the signature is compatible at runtime.
|
|
179
185
|
iconComponent: typeof app.icon === "function" ? app.icon : undefined,
|
|
180
186
|
color: app.color ?? buoyColors.primary,
|
|
@@ -188,10 +194,11 @@ export const DialDevTools = ({
|
|
|
188
194
|
|
|
189
195
|
// Only open modal if not a toggle-only tool.
|
|
190
196
|
if (app.launchMode !== "toggle-only") {
|
|
191
|
-
const resolvedIcon =
|
|
197
|
+
const resolvedIcon = renderAppIcon(app.icon, {
|
|
192
198
|
slot: "dial",
|
|
193
|
-
size: 20
|
|
194
|
-
|
|
199
|
+
size: 20,
|
|
200
|
+
color: app.color
|
|
201
|
+
});
|
|
195
202
|
open({
|
|
196
203
|
id: app.id,
|
|
197
204
|
title: app.name,
|
|
@@ -200,7 +207,8 @@ export const DialDevTools = ({
|
|
|
200
207
|
launchMode: app.launchMode ?? "self-modal",
|
|
201
208
|
singleton: app.singleton ?? true,
|
|
202
209
|
icon: resolvedIcon,
|
|
203
|
-
color: app.color
|
|
210
|
+
color: app.color,
|
|
211
|
+
modal: app.modal
|
|
204
212
|
});
|
|
205
213
|
}
|
|
206
214
|
|
package/lib/module/index.js
CHANGED
|
@@ -20,6 +20,12 @@ export { DevToolsSettingsModal, useDevToolsSettings } from "./floatingMenu/DevTo
|
|
|
20
20
|
// Export AppHost components for advanced use cases
|
|
21
21
|
export { AppHostProvider, AppOverlay, useAppHost } from "./floatingMenu/AppHost";
|
|
22
22
|
|
|
23
|
+
// Declarative chrome for custom tools (pairs with InstalledApp.modal)
|
|
24
|
+
export { useToolHost, useToolHeader } from "./floatingMenu/ToolHost.js";
|
|
25
|
+
|
|
26
|
+
// The custom-tools toolkit: blessed shared-ui components/hooks/tokens
|
|
27
|
+
export * from "./toolkit.js";
|
|
28
|
+
|
|
23
29
|
// Export DevTools visibility tracking
|
|
24
30
|
export { DevToolsVisibilityProvider, useDevToolsVisibility } from "./floatingMenu/DevToolsVisibilityContext.js";
|
|
25
31
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The public custom-tools toolkit — the blessed subset of Buoy's shared UI
|
|
5
|
+
* re-exported from `@buoy-gg/core`, so third-party tool authors need exactly
|
|
6
|
+
* one dependency and never touch `@buoy-gg/shared-ui` (which stays internal
|
|
7
|
+
* and free to churn).
|
|
8
|
+
*
|
|
9
|
+
* Design rules for this surface (keep it Tailwind-small):
|
|
10
|
+
* - Variants over components: a styling difference is a prop, not an export.
|
|
11
|
+
* - Behavior earns a component (CopyButton); a size preset does not.
|
|
12
|
+
* - The tool shell owns chrome — header/back/search buttons are not user API.
|
|
13
|
+
*
|
|
14
|
+
* Everything here is considered API: additions are minor bumps, removals are
|
|
15
|
+
* major. If a component you want is missing, that's deliberate — request it
|
|
16
|
+
* rather than deep-importing.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// ---- Theme tokens ---------------------------------------------------------
|
|
20
|
+
export { toolTheme } from "@buoy-gg/shared-ui";
|
|
21
|
+
|
|
22
|
+
// ---- Badges & status ------------------------------------------------------
|
|
23
|
+
// One Badge for every chip job; color it with the semantic helpers.
|
|
24
|
+
export { Badge, StatusDot, statusColor, methodColor, typeColor } from "./toolkitComponents.js";
|
|
25
|
+
|
|
26
|
+
// ---- Buttons --------------------------------------------------------------
|
|
27
|
+
export { ToolButton as Button, CopyButton, PowerToggleButton as PowerToggle } from "@buoy-gg/shared-ui";
|
|
28
|
+
|
|
29
|
+
// ---- Rows & cards ---------------------------------------------------------
|
|
30
|
+
export { CompactRow as Row, DevToolsCard as Card } from "@buoy-gg/shared-ui";
|
|
31
|
+
export { InfoRow } from "./toolkitComponents.js";
|
|
32
|
+
|
|
33
|
+
// ---- Structure ------------------------------------------------------------
|
|
34
|
+
export { SectionHeader, CollapsibleSection, TabSelector, EmptyState, SearchBar, EventStepperFooter } from "@buoy-gg/shared-ui";
|
|
35
|
+
|
|
36
|
+
// ---- Data -----------------------------------------------------------------
|
|
37
|
+
export { DataViewer } from "@buoy-gg/shared-ui/dataViewer";
|
|
38
|
+
export { DiffViewer } from "./toolkitComponents.js";
|
|
39
|
+
|
|
40
|
+
// ---- Stores (event log / observable state for tool data) ------------------
|
|
41
|
+
export { BaseEventStore } from "@buoy-gg/shared-ui";
|
|
42
|
+
|
|
43
|
+
// ---- Time -----------------------------------------------------------------
|
|
44
|
+
// The tool shell mounts the shared tick clock, so RelativeTime just works.
|
|
45
|
+
export { RelativeTime } from "@buoy-gg/shared-ui";
|
|
46
|
+
|
|
47
|
+
// ---- Formatting -----------------------------------------------------------
|
|
48
|
+
export { formatBytes, formatDuration, formatNumber, truncateMiddle, safeStringify } from "@buoy-gg/shared-ui";
|
|
49
|
+
|
|
50
|
+
// ---- Persistence ----------------------------------------------------------
|
|
51
|
+
export { usePersistedState, persistentStorage, devToolsStorageKeys } from "@buoy-gg/shared-ui";
|
|
52
|
+
|
|
53
|
+
// ---- Hooks / utils --------------------------------------------------------
|
|
54
|
+
export { useSafeAreaInsets, copyToClipboard } from "@buoy-gg/shared-ui";
|
|
55
|
+
|
|
56
|
+
// ---- Manual chrome (advanced escape hatch) --------------------------------
|
|
57
|
+
// Tools should use `InstalledApp.modal` + `useToolHost` instead; JsModal is
|
|
58
|
+
// for the rare tool that needs full control of its shell.
|
|
59
|
+
export { JsModal } from "@buoy-gg/shared-ui";
|
|
60
|
+
|
|
61
|
+
// ---- Icons (curated lucide set) ------------------------------------------
|
|
62
|
+
export { Activity, AlertTriangle, Bug, Check, CheckCircle, ChevronDown, ChevronLeft, ChevronRight, ChevronUp, Clock, Copy, Database, Eye, EyeOff, FileJson, FileText, Filter, FlaskConical, Globe, Hash, Info, Key, Layers, Lock, Pause, Play, Plus, Power, RefreshCw, Search, Settings, Shield, Trash2, User, Wifi, X, Zap, AlertCircle, BarChart3, Bookmark, Cloud, Download, Edit3, GitBranch, HardDrive, HelpCircle, Home, Image, Link, Maximize2, Minus, Palette, Pin, Route, Server, Smartphone, Square, CheckSquare, Timer, Unlock, Upload, Users, XCircle } from "@buoy-gg/shared-ui";
|