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