@buoy-gg/core 1.7.2
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/README.md +43 -0
- package/lib/commonjs/floatingMenu/AppHost.js +410 -0
- package/lib/commonjs/floatingMenu/AppHostLogic.js +44 -0
- package/lib/commonjs/floatingMenu/DefaultConfigContext.js +45 -0
- package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +2274 -0
- package/lib/commonjs/floatingMenu/DevToolsVisibilityContext.js +49 -0
- package/lib/commonjs/floatingMenu/DraggableHeader.js +114 -0
- package/lib/commonjs/floatingMenu/FloatingDevTools.js +254 -0
- package/lib/commonjs/floatingMenu/FloatingMenu.js +364 -0
- package/lib/commonjs/floatingMenu/MinimizedToolsContext.js +247 -0
- package/lib/commonjs/floatingMenu/MinimizedToolsStack.js +206 -0
- package/lib/commonjs/floatingMenu/ToggleStateManager.js +36 -0
- package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +241 -0
- package/lib/commonjs/floatingMenu/defaultConfig.js +160 -0
- package/lib/commonjs/floatingMenu/dial/DialDevTools.js +835 -0
- package/lib/commonjs/floatingMenu/dial/DialIcon.js +246 -0
- package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.js +249 -0
- package/lib/commonjs/floatingMenu/dial/onboardingConstants.js +70 -0
- package/lib/commonjs/floatingMenu/floatingTools.js +771 -0
- package/lib/commonjs/floatingMenu/settingsBus.js +23 -0
- package/lib/commonjs/floatingMenu/types.js +5 -0
- package/lib/commonjs/index.js +240 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/module/floatingMenu/AppHost.js +402 -0
- package/lib/module/floatingMenu/AppHostLogic.js +39 -0
- package/lib/module/floatingMenu/DefaultConfigContext.js +39 -0
- package/lib/module/floatingMenu/DevToolsSettingsModal.js +2273 -0
- package/lib/module/floatingMenu/DevToolsVisibilityContext.js +44 -0
- package/lib/module/floatingMenu/DraggableHeader.js +110 -0
- package/lib/module/floatingMenu/FloatingDevTools.js +249 -0
- package/lib/module/floatingMenu/FloatingMenu.js +358 -0
- package/lib/module/floatingMenu/MinimizedToolsContext.js +239 -0
- package/lib/module/floatingMenu/MinimizedToolsStack.js +202 -0
- package/lib/module/floatingMenu/ToggleStateManager.js +32 -0
- package/lib/module/floatingMenu/autoDiscoverPresets.js +236 -0
- package/lib/module/floatingMenu/defaultConfig.js +151 -0
- package/lib/module/floatingMenu/dial/DialDevTools.js +829 -0
- package/lib/module/floatingMenu/dial/DialIcon.js +241 -0
- package/lib/module/floatingMenu/dial/OnboardingTooltip.js +244 -0
- package/lib/module/floatingMenu/dial/onboardingConstants.js +64 -0
- package/lib/module/floatingMenu/floatingTools.js +767 -0
- package/lib/module/floatingMenu/settingsBus.js +19 -0
- package/lib/module/floatingMenu/types.js +3 -0
- package/lib/module/index.js +29 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/commonjs/floatingMenu/AppHost.d.ts +39 -0
- package/lib/typescript/commonjs/floatingMenu/AppHost.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts +37 -0
- package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/DefaultConfigContext.d.ts +27 -0
- package/lib/typescript/commonjs/floatingMenu/DefaultConfigContext.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts +57 -0
- package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/DevToolsVisibilityContext.d.ts +25 -0
- package/lib/typescript/commonjs/floatingMenu/DevToolsVisibilityContext.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/DraggableHeader.d.ts +30 -0
- package/lib/typescript/commonjs/floatingMenu/DraggableHeader.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts +226 -0
- package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts +39 -0
- package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts +95 -0
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.d.ts +10 -0
- package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/ToggleStateManager.d.ts +21 -0
- package/lib/typescript/commonjs/floatingMenu/ToggleStateManager.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts +75 -0
- package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +120 -0
- package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts +35 -0
- package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts +14 -0
- package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.d.ts +12 -0
- package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.d.ts +30 -0
- package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts +56 -0
- package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/settingsBus.d.ts +10 -0
- package/lib/typescript/commonjs/floatingMenu/settingsBus.d.ts.map +1 -0
- package/lib/typescript/commonjs/floatingMenu/types.d.ts +56 -0
- package/lib/typescript/commonjs/floatingMenu/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +18 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/module/floatingMenu/AppHost.d.ts +39 -0
- package/lib/typescript/module/floatingMenu/AppHost.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts +37 -0
- package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/DefaultConfigContext.d.ts +27 -0
- package/lib/typescript/module/floatingMenu/DefaultConfigContext.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts +57 -0
- package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/DevToolsVisibilityContext.d.ts +25 -0
- package/lib/typescript/module/floatingMenu/DevToolsVisibilityContext.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/DraggableHeader.d.ts +30 -0
- package/lib/typescript/module/floatingMenu/DraggableHeader.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts +226 -0
- package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts +39 -0
- package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts +95 -0
- package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/MinimizedToolsStack.d.ts +10 -0
- package/lib/typescript/module/floatingMenu/MinimizedToolsStack.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/ToggleStateManager.d.ts +21 -0
- package/lib/typescript/module/floatingMenu/ToggleStateManager.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts +75 -0
- package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +120 -0
- package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts +35 -0
- package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts +14 -0
- package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.d.ts +12 -0
- package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/dial/onboardingConstants.d.ts +30 -0
- package/lib/typescript/module/floatingMenu/dial/onboardingConstants.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/floatingTools.d.ts +56 -0
- package/lib/typescript/module/floatingMenu/floatingTools.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/settingsBus.d.ts +10 -0
- package/lib/typescript/module/floatingMenu/settingsBus.d.ts.map +1 -0
- package/lib/typescript/module/floatingMenu/types.d.ts +56 -0
- package/lib/typescript/module/floatingMenu/types.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +18 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/package.json +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @buoy/core
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@buoy/core)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Floating dev tools launcher and host provider for React Native apps.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @buoy/core @buoy/shared-ui
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
```tsx
|
|
15
|
+
import { AppHostProvider, FloatingMenu } from '@buoy/core';
|
|
16
|
+
import type { InstalledApp } from '@buoy/core';
|
|
17
|
+
import { EnvVarsModal } from '@buoy/env';
|
|
18
|
+
|
|
19
|
+
const APPS: InstalledApp[] = [
|
|
20
|
+
{
|
|
21
|
+
id: 'env',
|
|
22
|
+
name: 'Environment',
|
|
23
|
+
icon: '🛰️',
|
|
24
|
+
component: EnvVarsModal,
|
|
25
|
+
singleton: true,
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export function DevToolsHost() {
|
|
30
|
+
return (
|
|
31
|
+
<AppHostProvider>
|
|
32
|
+
<FloatingMenu apps={APPS} />
|
|
33
|
+
</AppHostProvider>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Key Exports
|
|
39
|
+
- `AppHostProvider` – Context provider that manages installed dev tools.
|
|
40
|
+
- `FloatingMenu` – Cyberpunk-inspired floating entrypoint for tools.
|
|
41
|
+
- `AppOverlay` & `useAppHost()` – Programmatic APIs for opening tools.
|
|
42
|
+
|
|
43
|
+
The menu hosts any `InstalledApp` descriptor. Combine it with other `@buoy/*` packages for a full suite of debug panels.
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useAppHost = exports.AppOverlay = exports.AppHostProvider = void 0;
|
|
7
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
var _reactNative = require("react-native");
|
|
10
|
+
var _AppHostLogic = require("./AppHostLogic.js");
|
|
11
|
+
var _MinimizedToolsContext = require("./MinimizedToolsContext.js");
|
|
12
|
+
var _DevToolsSettingsModal = require("./DevToolsSettingsModal.js");
|
|
13
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
15
|
+
const AppHostContext = /*#__PURE__*/(0, _react.createContext)(null);
|
|
16
|
+
const STORAGE_KEY_OPEN_APPS = "@react_buoy_open_apps";
|
|
17
|
+
const PERSISTENCE_DELAY = 500;
|
|
18
|
+
|
|
19
|
+
// Type for persisted app state
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Provides the floating dev tools application host. Tracks open tool instances, restores
|
|
23
|
+
* persisted state, and exposes imperative helpers used by `FloatingMenu` and friends.
|
|
24
|
+
*/
|
|
25
|
+
const AppHostProvider = ({
|
|
26
|
+
children
|
|
27
|
+
}) => {
|
|
28
|
+
const [openApps, setOpenApps] = (0, _react.useState)([]);
|
|
29
|
+
const [isRestored, setIsRestored] = (0, _react.useState)(false);
|
|
30
|
+
const persistenceTimeoutRef = (0, _react.useRef)(null);
|
|
31
|
+
const installedAppsRef = (0, _react.useRef)([]);
|
|
32
|
+
const pendingRestoreRef = (0, _react.useRef)(null);
|
|
33
|
+
const {
|
|
34
|
+
restore: removeFromMinimizedStack
|
|
35
|
+
} = (0, _MinimizedToolsContext.useMinimizedTools)();
|
|
36
|
+
const open = (0, _react.useCallback)(def => {
|
|
37
|
+
let resolvedId = "";
|
|
38
|
+
setOpenApps(current => {
|
|
39
|
+
const {
|
|
40
|
+
apps,
|
|
41
|
+
instanceId,
|
|
42
|
+
wasMinimized
|
|
43
|
+
} = (0, _AppHostLogic.resolveOpenAppsState)(current, def, () => `${def.id}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
44
|
+
resolvedId = instanceId;
|
|
45
|
+
|
|
46
|
+
// If the app was minimized, remove it from the minimized stack
|
|
47
|
+
// This needs to be done outside of setOpenApps to avoid nested state updates
|
|
48
|
+
if (wasMinimized) {
|
|
49
|
+
// Schedule the removal for after this state update completes
|
|
50
|
+
setTimeout(() => removeFromMinimizedStack(instanceId), 0);
|
|
51
|
+
}
|
|
52
|
+
return apps;
|
|
53
|
+
});
|
|
54
|
+
return resolvedId;
|
|
55
|
+
}, [removeFromMinimizedStack]);
|
|
56
|
+
const tryRestorePending = (0, _react.useCallback)(() => {
|
|
57
|
+
if (isRestored) return;
|
|
58
|
+
if (!installedAppsRef.current.length) return;
|
|
59
|
+
const pendingApps = pendingRestoreRef.current;
|
|
60
|
+
if (!pendingApps || pendingApps.length === 0) {
|
|
61
|
+
setIsRestored(true);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
pendingRestoreRef.current = null;
|
|
65
|
+
pendingApps.forEach(({
|
|
66
|
+
id: appId,
|
|
67
|
+
minimized
|
|
68
|
+
}) => {
|
|
69
|
+
const appDef = installedAppsRef.current.find(app => app.id === appId);
|
|
70
|
+
if (appDef) {
|
|
71
|
+
const resolvedIcon = typeof appDef.icon === "function" ? appDef.icon({
|
|
72
|
+
slot: "dial",
|
|
73
|
+
size: 20
|
|
74
|
+
}) : appDef.icon;
|
|
75
|
+
open({
|
|
76
|
+
id: appDef.id,
|
|
77
|
+
title: appDef.name,
|
|
78
|
+
component: appDef.component,
|
|
79
|
+
props: appDef.props,
|
|
80
|
+
launchMode: appDef.launchMode || "self-modal",
|
|
81
|
+
singleton: appDef.singleton,
|
|
82
|
+
icon: resolvedIcon,
|
|
83
|
+
color: appDef.color,
|
|
84
|
+
minimized: minimized // Preserve minimized state
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
setIsRestored(true);
|
|
89
|
+
}, [isRestored, open]);
|
|
90
|
+
|
|
91
|
+
// Restore open apps on mount
|
|
92
|
+
(0, _react.useEffect)(() => {
|
|
93
|
+
const restoreOpenApps = async () => {
|
|
94
|
+
try {
|
|
95
|
+
const saved = await (0, _sharedUi.safeGetItem)(STORAGE_KEY_OPEN_APPS);
|
|
96
|
+
if (saved) {
|
|
97
|
+
const parsed = JSON.parse(saved);
|
|
98
|
+
// Handle both old format (string[]) and new format (PersistedAppState[])
|
|
99
|
+
let savedApps;
|
|
100
|
+
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
101
|
+
if (typeof parsed[0] === "string") {
|
|
102
|
+
// Old format: convert string[] to PersistedAppState[]
|
|
103
|
+
savedApps = parsed.map(id => ({
|
|
104
|
+
id,
|
|
105
|
+
minimized: false
|
|
106
|
+
}));
|
|
107
|
+
} else {
|
|
108
|
+
// New format: already PersistedAppState[]
|
|
109
|
+
savedApps = parsed;
|
|
110
|
+
}
|
|
111
|
+
if (savedApps.length) {
|
|
112
|
+
pendingRestoreRef.current = savedApps;
|
|
113
|
+
tryRestorePending();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
// Failed to restore open apps - continue with fresh state
|
|
120
|
+
}
|
|
121
|
+
setIsRestored(true);
|
|
122
|
+
};
|
|
123
|
+
restoreOpenApps();
|
|
124
|
+
}, [tryRestorePending]);
|
|
125
|
+
|
|
126
|
+
// Save open apps with debounce
|
|
127
|
+
(0, _react.useEffect)(() => {
|
|
128
|
+
if (!isRestored) return;
|
|
129
|
+
|
|
130
|
+
// Clear existing timeout
|
|
131
|
+
if (persistenceTimeoutRef.current) {
|
|
132
|
+
clearTimeout(persistenceTimeoutRef.current);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Set new timeout to save
|
|
136
|
+
persistenceTimeoutRef.current = setTimeout(() => {
|
|
137
|
+
const appStates = openApps.map(app => ({
|
|
138
|
+
id: app.id,
|
|
139
|
+
minimized: app.minimized ?? false
|
|
140
|
+
}));
|
|
141
|
+
(0, _sharedUi.safeSetItem)(STORAGE_KEY_OPEN_APPS, JSON.stringify(appStates));
|
|
142
|
+
}, PERSISTENCE_DELAY);
|
|
143
|
+
return () => {
|
|
144
|
+
if (persistenceTimeoutRef.current) {
|
|
145
|
+
clearTimeout(persistenceTimeoutRef.current);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}, [openApps, isRestored]);
|
|
149
|
+
|
|
150
|
+
// Store reference to installed apps for restoration
|
|
151
|
+
const registerApps = (0, _react.useCallback)(apps => {
|
|
152
|
+
installedAppsRef.current = apps;
|
|
153
|
+
tryRestorePending();
|
|
154
|
+
}, [tryRestorePending]);
|
|
155
|
+
const close = (0, _react.useCallback)(instanceId => {
|
|
156
|
+
setOpenApps(s => {
|
|
157
|
+
if (!s.length) return s;
|
|
158
|
+
if (!instanceId) return s.slice(0, -1);
|
|
159
|
+
return s.filter(a => a.instanceId !== instanceId);
|
|
160
|
+
});
|
|
161
|
+
}, []);
|
|
162
|
+
const closeAll = (0, _react.useCallback)(() => setOpenApps([]), []);
|
|
163
|
+
const minimize = (0, _react.useCallback)(instanceId => {
|
|
164
|
+
setOpenApps(s => s.map(app => app.instanceId === instanceId ? {
|
|
165
|
+
...app,
|
|
166
|
+
minimized: true
|
|
167
|
+
} : app));
|
|
168
|
+
}, []);
|
|
169
|
+
const restore = (0, _react.useCallback)((instanceId, restoreState) => {
|
|
170
|
+
setOpenApps(s => s.map(app => app.instanceId === instanceId ? {
|
|
171
|
+
...app,
|
|
172
|
+
minimized: false,
|
|
173
|
+
restoreState
|
|
174
|
+
} : app));
|
|
175
|
+
}, []);
|
|
176
|
+
const isMinimized = (0, _react.useCallback)(instanceId => {
|
|
177
|
+
const app = openApps.find(a => a.instanceId === instanceId);
|
|
178
|
+
return app?.minimized ?? false;
|
|
179
|
+
}, [openApps]);
|
|
180
|
+
_react.default.useEffect(() => {
|
|
181
|
+
if (openApps.length === 0) return;
|
|
182
|
+
const handler = () => {
|
|
183
|
+
close();
|
|
184
|
+
return true;
|
|
185
|
+
};
|
|
186
|
+
const sub = _reactNative.BackHandler.addEventListener("hardwareBackPress", handler);
|
|
187
|
+
return () => sub.remove();
|
|
188
|
+
}, [openApps.length, close]);
|
|
189
|
+
const value = (0, _react.useMemo)(() => ({
|
|
190
|
+
openApps,
|
|
191
|
+
// Only count non-toggle-only and non-minimized tools as "open"
|
|
192
|
+
isAnyOpen: openApps.filter(app => app.launchMode !== "toggle-only" && !app.minimized).length > 0,
|
|
193
|
+
open,
|
|
194
|
+
close,
|
|
195
|
+
closeAll,
|
|
196
|
+
registerApps,
|
|
197
|
+
minimize,
|
|
198
|
+
restore,
|
|
199
|
+
isMinimized
|
|
200
|
+
}), [openApps, open, close, closeAll, registerApps, minimize, restore, isMinimized]);
|
|
201
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(AppHostContext.Provider, {
|
|
202
|
+
value: value,
|
|
203
|
+
children: children
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Accessor hook for the dev tools app host. Components can open/close tools or inspect
|
|
209
|
+
* the active stack. Falls back to a no-op implementation when rendered outside the provider.
|
|
210
|
+
*/
|
|
211
|
+
exports.AppHostProvider = AppHostProvider;
|
|
212
|
+
const useAppHost = () => {
|
|
213
|
+
const ctx = (0, _react.useContext)(AppHostContext);
|
|
214
|
+
// Return a default value if not in provider (for backwards compatibility)
|
|
215
|
+
if (!ctx) {
|
|
216
|
+
return {
|
|
217
|
+
openApps: [],
|
|
218
|
+
isAnyOpen: false,
|
|
219
|
+
open: () => "",
|
|
220
|
+
close: () => {},
|
|
221
|
+
closeAll: () => {},
|
|
222
|
+
minimize: () => {},
|
|
223
|
+
restore: (_instanceId, _restoreState) => {},
|
|
224
|
+
isMinimized: () => false
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return ctx;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Renders a single app instance. Keeps component mounted even when minimized
|
|
232
|
+
* by passing visible={false} instead of unmounting.
|
|
233
|
+
*
|
|
234
|
+
* Supports multiple simultaneous modals - each gets its own z-index based on
|
|
235
|
+
* position in the open apps stack (later opened = higher z-index).
|
|
236
|
+
*/
|
|
237
|
+
exports.useAppHost = useAppHost;
|
|
238
|
+
const AppRenderer = ({
|
|
239
|
+
app,
|
|
240
|
+
zIndex,
|
|
241
|
+
onClose,
|
|
242
|
+
onMinimize,
|
|
243
|
+
minimizeTargetPosition,
|
|
244
|
+
globalEnableSharedModalDimensions
|
|
245
|
+
}) => {
|
|
246
|
+
const Comp = app.component;
|
|
247
|
+
// All non-minimized apps are visible - supports multiple simultaneous modals
|
|
248
|
+
const isVisible = !app.minimized;
|
|
249
|
+
|
|
250
|
+
// Merge props with global settings override
|
|
251
|
+
// Priority: Global settings (if defined) > Tool prop > Default (false)
|
|
252
|
+
const mergedProps = {
|
|
253
|
+
...(app.props ?? {}),
|
|
254
|
+
// Only override if globalEnableSharedModalDimensions is explicitly true
|
|
255
|
+
// (when the user turns it on in settings)
|
|
256
|
+
...(globalEnableSharedModalDimensions === true ? {
|
|
257
|
+
enableSharedModalDimensions: true
|
|
258
|
+
} : {})
|
|
259
|
+
};
|
|
260
|
+
if (app.launchMode === "self-modal") {
|
|
261
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(Comp, {
|
|
262
|
+
...mergedProps,
|
|
263
|
+
visible: isVisible,
|
|
264
|
+
onClose: onClose,
|
|
265
|
+
onRequestClose: onClose,
|
|
266
|
+
onMinimize: onMinimize,
|
|
267
|
+
minimizeTargetPosition: minimizeTargetPosition,
|
|
268
|
+
initialModalState: app.restoreState,
|
|
269
|
+
instanceId: app.instanceId,
|
|
270
|
+
zIndex: zIndex
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (app.launchMode === "inline") {
|
|
274
|
+
if (!isVisible) return null;
|
|
275
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
276
|
+
pointerEvents: "box-none",
|
|
277
|
+
style: [_reactNative.StyleSheet.absoluteFill, {
|
|
278
|
+
zIndex
|
|
279
|
+
}],
|
|
280
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Comp, {
|
|
281
|
+
...mergedProps,
|
|
282
|
+
onClose: onClose,
|
|
283
|
+
onMinimize: onMinimize,
|
|
284
|
+
minimizeTargetPosition: minimizeTargetPosition,
|
|
285
|
+
initialModalState: app.restoreState,
|
|
286
|
+
instanceId: app.instanceId
|
|
287
|
+
})
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// host-modal mode
|
|
292
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Modal, {
|
|
293
|
+
visible: isVisible,
|
|
294
|
+
transparent: true,
|
|
295
|
+
animationType: "slide",
|
|
296
|
+
onRequestClose: onClose,
|
|
297
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
298
|
+
style: styles.backdrop,
|
|
299
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
300
|
+
style: styles.card,
|
|
301
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Comp, {
|
|
302
|
+
...mergedProps,
|
|
303
|
+
onClose: onClose,
|
|
304
|
+
onMinimize: onMinimize,
|
|
305
|
+
minimizeTargetPosition: minimizeTargetPosition,
|
|
306
|
+
initialModalState: app.restoreState,
|
|
307
|
+
instanceId: app.instanceId
|
|
308
|
+
})
|
|
309
|
+
})
|
|
310
|
+
})
|
|
311
|
+
});
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Renders all dev tool surfaces. Keeps minimized apps mounted but hidden
|
|
316
|
+
* so their state and listeners are preserved (similar to React Navigation screens).
|
|
317
|
+
*
|
|
318
|
+
* Supports multiple simultaneous modals - each modal gets a z-index based on
|
|
319
|
+
* its position in the stack (later opened modals appear on top).
|
|
320
|
+
*/
|
|
321
|
+
const AppOverlay = () => {
|
|
322
|
+
const {
|
|
323
|
+
openApps,
|
|
324
|
+
close,
|
|
325
|
+
minimize
|
|
326
|
+
} = useAppHost();
|
|
327
|
+
const {
|
|
328
|
+
minimize: addToMinimizedStack,
|
|
329
|
+
getNextIconPosition,
|
|
330
|
+
minimizedTools
|
|
331
|
+
} = (0, _MinimizedToolsContext.useMinimizedTools)();
|
|
332
|
+
const {
|
|
333
|
+
settings
|
|
334
|
+
} = (0, _DevToolsSettingsModal.useDevToolsSettings)();
|
|
335
|
+
|
|
336
|
+
// Sync restored minimized apps to MinimizedToolsContext
|
|
337
|
+
// This handles apps that were restored from persistence with minimized=true
|
|
338
|
+
_react.default.useEffect(() => {
|
|
339
|
+
openApps.forEach(app => {
|
|
340
|
+
if (app.minimized && app.launchMode !== "toggle-only") {
|
|
341
|
+
// Check if this app is already in the minimized stack
|
|
342
|
+
const isInStack = minimizedTools.some(t => t.instanceId === app.instanceId);
|
|
343
|
+
if (!isInStack) {
|
|
344
|
+
// Add to minimized stack (restored from persistence)
|
|
345
|
+
addToMinimizedStack({
|
|
346
|
+
instanceId: app.instanceId,
|
|
347
|
+
id: app.id,
|
|
348
|
+
title: app.title || app.id,
|
|
349
|
+
icon: app.icon,
|
|
350
|
+
color: app.color
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}, [openApps, minimizedTools, addToMinimizedStack]);
|
|
356
|
+
|
|
357
|
+
// Filter to renderable apps (exclude toggle-only)
|
|
358
|
+
const renderableApps = openApps.filter(app => app.launchMode !== "toggle-only");
|
|
359
|
+
if (renderableApps.length === 0) return null;
|
|
360
|
+
|
|
361
|
+
// Base z-index for modals - each subsequent modal gets +1
|
|
362
|
+
const BASE_ZINDEX = 9000;
|
|
363
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
364
|
+
children: renderableApps.map((app, index) => {
|
|
365
|
+
// z-index based on position - later in array = higher z-index (on top)
|
|
366
|
+
const zIndex = BASE_ZINDEX + index;
|
|
367
|
+
const minimizeTargetPosition = getNextIconPosition();
|
|
368
|
+
const handleMinimize = modalState => {
|
|
369
|
+
// IMPORTANT: Order matters here!
|
|
370
|
+
// 1. First mark the app as minimized in AppHost - this updates isAnyOpen
|
|
371
|
+
// so that pushToSide becomes false before the icon component mounts
|
|
372
|
+
minimize(app.instanceId);
|
|
373
|
+
// 2. Then add to the minimized stack - this triggers the icon to mount
|
|
374
|
+
// By now isAnyOpen is false, so the icon mounts with pushToSide=false
|
|
375
|
+
addToMinimizedStack({
|
|
376
|
+
instanceId: app.instanceId,
|
|
377
|
+
id: app.id,
|
|
378
|
+
title: app.title || app.id,
|
|
379
|
+
icon: app.icon,
|
|
380
|
+
color: app.color,
|
|
381
|
+
modalState: modalState
|
|
382
|
+
});
|
|
383
|
+
};
|
|
384
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(AppRenderer, {
|
|
385
|
+
app: app,
|
|
386
|
+
zIndex: zIndex,
|
|
387
|
+
onClose: () => close(app.instanceId),
|
|
388
|
+
onMinimize: handleMinimize,
|
|
389
|
+
minimizeTargetPosition: minimizeTargetPosition,
|
|
390
|
+
globalEnableSharedModalDimensions: settings.globalSettings?.enableSharedModalDimensions
|
|
391
|
+
}, app.instanceId);
|
|
392
|
+
})
|
|
393
|
+
});
|
|
394
|
+
};
|
|
395
|
+
exports.AppOverlay = AppOverlay;
|
|
396
|
+
const styles = _reactNative.StyleSheet.create({
|
|
397
|
+
backdrop: {
|
|
398
|
+
flex: 1,
|
|
399
|
+
backgroundColor: "rgba(0,0,0,0.28)",
|
|
400
|
+
alignItems: "center",
|
|
401
|
+
justifyContent: "center"
|
|
402
|
+
},
|
|
403
|
+
card: {
|
|
404
|
+
maxHeight: "90%",
|
|
405
|
+
width: "94%",
|
|
406
|
+
borderRadius: 12,
|
|
407
|
+
backgroundColor: "white",
|
|
408
|
+
overflow: "hidden"
|
|
409
|
+
}
|
|
410
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.resolveOpenAppsState = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Computes the new list of open tool instances when a user launches a dev app. Singleton
|
|
9
|
+
* tools reuse their existing instance while non-singletons create a new entry using the
|
|
10
|
+
* provided `generateId` helper.
|
|
11
|
+
*
|
|
12
|
+
* @param current - Current stack of open app instances.
|
|
13
|
+
* @param def - Descriptor of the tool to launch (without runtime instance id).
|
|
14
|
+
* @param generateId - Callback used to generate a unique instance identifier.
|
|
15
|
+
* @returns Updated instance list alongside the resolved instance id.
|
|
16
|
+
*/
|
|
17
|
+
const resolveOpenAppsState = (current, def, generateId) => {
|
|
18
|
+
if (def.singleton) {
|
|
19
|
+
const existing = current.find(app => app.id === def.id);
|
|
20
|
+
if (existing) {
|
|
21
|
+
const wasMinimized = existing.minimized ?? false;
|
|
22
|
+
return {
|
|
23
|
+
instanceId: existing.instanceId,
|
|
24
|
+
wasMinimized,
|
|
25
|
+
apps: [...current.filter(app => app.instanceId !== existing.instanceId),
|
|
26
|
+
// Un-minimize the existing app when re-opening it
|
|
27
|
+
{
|
|
28
|
+
...existing,
|
|
29
|
+
minimized: false
|
|
30
|
+
}]
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const instanceId = generateId();
|
|
35
|
+
return {
|
|
36
|
+
instanceId,
|
|
37
|
+
wasMinimized: false,
|
|
38
|
+
apps: [...current, {
|
|
39
|
+
...def,
|
|
40
|
+
instanceId
|
|
41
|
+
}]
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
exports.resolveOpenAppsState = resolveOpenAppsState;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.DefaultConfigProvider = DefaultConfigProvider;
|
|
7
|
+
exports.useDefaultConfig = useDefaultConfig;
|
|
8
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
9
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
10
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
11
|
+
/**
|
|
12
|
+
* Context value for default configuration settings.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const DefaultConfigContext = /*#__PURE__*/(0, _react.createContext)({});
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Provider for default configuration that can be consumed by the settings system.
|
|
19
|
+
* This allows teams to set default tool configurations without prop drilling.
|
|
20
|
+
*
|
|
21
|
+
* @internal Used by FloatingDevTools to provide defaults to the settings hook.
|
|
22
|
+
*/
|
|
23
|
+
function DefaultConfigProvider({
|
|
24
|
+
children,
|
|
25
|
+
defaultFloatingTools,
|
|
26
|
+
defaultDialTools
|
|
27
|
+
}) {
|
|
28
|
+
const value = _react.default.useMemo(() => ({
|
|
29
|
+
defaultFloatingTools,
|
|
30
|
+
defaultDialTools
|
|
31
|
+
}), [defaultFloatingTools, defaultDialTools]);
|
|
32
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(DefaultConfigContext.Provider, {
|
|
33
|
+
value: value,
|
|
34
|
+
children: children
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Hook to access the default configuration from context.
|
|
40
|
+
*
|
|
41
|
+
* @internal Used by useDevToolsSettings to apply defaults.
|
|
42
|
+
*/
|
|
43
|
+
function useDefaultConfig() {
|
|
44
|
+
return (0, _react.useContext)(DefaultConfigContext);
|
|
45
|
+
}
|