@buoy-gg/core 7.0.15 → 7.0.17

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 (133) hide show
  1. package/lib/commonjs/floatingMenu/AppHost.js +18 -0
  2. package/lib/commonjs/floatingMenu/AppHost.web.js +359 -0
  3. package/lib/commonjs/floatingMenu/AppHostLogic.js +6 -0
  4. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +787 -418
  5. package/lib/commonjs/floatingMenu/FloatingDevTools.js +1 -1
  6. package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +244 -36
  7. package/lib/commonjs/floatingMenu/FloatingMenu.js +4 -3
  8. package/lib/commonjs/floatingMenu/MinimizedToolsContext.js +2 -3
  9. package/lib/commonjs/floatingMenu/MinimizedToolsStack.web.js +287 -0
  10. package/lib/commonjs/floatingMenu/ToolHost.js +264 -0
  11. package/lib/commonjs/floatingMenu/allToolsRegistry.js +7 -0
  12. package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +32 -0
  13. package/lib/commonjs/floatingMenu/autoExternalSync.js +18 -0
  14. package/lib/commonjs/floatingMenu/dial/DialDevTools.js +9 -5
  15. package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +373 -231
  16. package/lib/commonjs/floatingMenu/dial/DialIcon.js +25 -3
  17. package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.js +1 -1
  18. package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.web.js +154 -0
  19. package/lib/commonjs/floatingMenu/dial/onboardingConstants.web.js +34 -0
  20. package/lib/commonjs/floatingMenu/floatingTools.js +3 -3
  21. package/lib/commonjs/floatingMenu/floatingTools.web.js +191 -28
  22. package/lib/commonjs/index.js +29 -2
  23. package/lib/commonjs/index.web.js +19 -0
  24. package/lib/commonjs/toolkit.js +427 -0
  25. package/lib/commonjs/utils/autoDiscoverPresets.web.js +50 -5
  26. package/lib/module/floatingMenu/AppHost.js +18 -0
  27. package/lib/module/floatingMenu/AppHost.web.js +351 -0
  28. package/lib/module/floatingMenu/AppHostLogic.js +6 -0
  29. package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +792 -422
  30. package/lib/module/floatingMenu/FloatingDevTools.js +2 -2
  31. package/lib/module/floatingMenu/FloatingDevTools.web.js +247 -38
  32. package/lib/module/floatingMenu/FloatingMenu.js +4 -3
  33. package/lib/module/floatingMenu/MinimizedToolsContext.js +2 -3
  34. package/lib/module/floatingMenu/MinimizedToolsStack.web.js +284 -0
  35. package/lib/module/floatingMenu/ToolHost.js +256 -0
  36. package/lib/module/floatingMenu/allToolsRegistry.js +8 -1
  37. package/lib/module/floatingMenu/autoDiscoverPresets.js +32 -0
  38. package/lib/module/floatingMenu/autoExternalSync.js +18 -0
  39. package/lib/module/floatingMenu/dial/DialDevTools.js +10 -6
  40. package/lib/module/floatingMenu/dial/DialDevTools.web.js +375 -233
  41. package/lib/module/floatingMenu/dial/DialIcon.js +26 -4
  42. package/lib/module/floatingMenu/dial/OnboardingTooltip.js +1 -1
  43. package/lib/module/floatingMenu/dial/OnboardingTooltip.web.js +149 -0
  44. package/lib/module/floatingMenu/dial/onboardingConstants.web.js +27 -0
  45. package/lib/module/floatingMenu/floatingTools.js +3 -3
  46. package/lib/module/floatingMenu/floatingTools.web.js +190 -28
  47. package/lib/module/index.js +8 -2
  48. package/lib/module/index.web.js +5 -0
  49. package/lib/module/toolkit.js +45 -0
  50. package/lib/module/utils/autoDiscoverPresets.web.js +53 -7
  51. package/lib/typescript/commonjs/floatingMenu/AppHost.d.ts.map +1 -1
  52. package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts +38 -0
  53. package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts.map +1 -0
  54. package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts +24 -1
  55. package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts +5 -2
  57. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts +2 -14
  59. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/floatingMenu/FloatingMenu.d.ts.map +1 -1
  61. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts +2 -20
  62. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts.map +1 -1
  63. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.web.d.ts +21 -0
  64. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.web.d.ts.map +1 -0
  65. package/lib/typescript/commonjs/floatingMenu/ToolHost.d.ts +72 -0
  66. package/lib/typescript/commonjs/floatingMenu/ToolHost.d.ts.map +1 -0
  67. package/lib/typescript/commonjs/floatingMenu/allToolsRegistry.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  69. package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts +1 -1
  71. package/lib/typescript/commonjs/floatingMenu/defaultConfig.d.ts.map +1 -1
  72. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  73. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts +16 -2
  74. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  75. package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +1 -1
  76. package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.web.d.ts +9 -0
  77. package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +1 -0
  78. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts +13 -0
  79. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts.map +1 -0
  80. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts +29 -2
  81. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts.map +1 -1
  82. package/lib/typescript/commonjs/floatingMenu/types.d.ts +30 -1
  83. package/lib/typescript/commonjs/floatingMenu/types.d.ts.map +1 -1
  84. package/lib/typescript/commonjs/index.d.ts +2 -0
  85. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  86. package/lib/typescript/commonjs/index.web.d.ts +1 -0
  87. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  88. package/lib/typescript/commonjs/toolkit.d.ts +22 -0
  89. package/lib/typescript/commonjs/toolkit.d.ts.map +1 -0
  90. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts +2 -0
  91. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts.map +1 -1
  92. package/lib/typescript/module/floatingMenu/AppHost.d.ts.map +1 -1
  93. package/lib/typescript/module/floatingMenu/AppHost.web.d.ts +38 -0
  94. package/lib/typescript/module/floatingMenu/AppHost.web.d.ts.map +1 -0
  95. package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts +24 -1
  96. package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts.map +1 -1
  97. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts +5 -2
  98. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  99. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts +2 -14
  100. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  101. package/lib/typescript/module/floatingMenu/FloatingMenu.d.ts.map +1 -1
  102. package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts +2 -20
  103. package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts.map +1 -1
  104. package/lib/typescript/module/floatingMenu/MinimizedToolsStack.web.d.ts +21 -0
  105. package/lib/typescript/module/floatingMenu/MinimizedToolsStack.web.d.ts.map +1 -0
  106. package/lib/typescript/module/floatingMenu/ToolHost.d.ts +72 -0
  107. package/lib/typescript/module/floatingMenu/ToolHost.d.ts.map +1 -0
  108. package/lib/typescript/module/floatingMenu/allToolsRegistry.d.ts.map +1 -1
  109. package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  110. package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +1 -1
  111. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts +1 -1
  112. package/lib/typescript/module/floatingMenu/defaultConfig.d.ts.map +1 -1
  113. package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  114. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts +16 -2
  115. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  116. package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +1 -1
  117. package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.web.d.ts +9 -0
  118. package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +1 -0
  119. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts +13 -0
  120. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts.map +1 -0
  121. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts +29 -2
  122. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts.map +1 -1
  123. package/lib/typescript/module/floatingMenu/types.d.ts +30 -1
  124. package/lib/typescript/module/floatingMenu/types.d.ts.map +1 -1
  125. package/lib/typescript/module/index.d.ts +2 -0
  126. package/lib/typescript/module/index.d.ts.map +1 -1
  127. package/lib/typescript/module/index.web.d.ts +1 -0
  128. package/lib/typescript/module/index.web.d.ts.map +1 -1
  129. package/lib/typescript/module/toolkit.d.ts +22 -0
  130. package/lib/typescript/module/toolkit.d.ts.map +1 -0
  131. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts +2 -0
  132. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts.map +1 -1
  133. package/package.json +5 -5
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MinimizedToolsStack = MinimizedToolsStack;
7
+ var _react = require("react");
8
+ var _sharedUi = require("@buoy-gg/shared-ui");
9
+ var _AppHostWeb = require("./AppHost.web.js");
10
+ var _jsxRuntime = require("react/jsx-runtime");
11
+ /**
12
+ * MinimizedToolsStack — Web twin of MinimizedToolsStack.tsx +
13
+ * shared-ui's ExpandablePopover (inlined: the popover is only used here on
14
+ * web). A vertical stack of minimized-tool icons fused to the top of the
15
+ * floating bubble's drag handle:
16
+ * - collapsed: a 28px "peek" tab (chevron-up + count) with top corners only
17
+ * - expanded: animated-height panel, icons newest-first, collapse chevron
18
+ * - expanded state persists under "@react_buoy_minimized_stack_expanded"
19
+ * - each icon runs the native randomized glitch loop (translateX shake +
20
+ * opacity flicker + scale pulse, 80ms), scheduled every 2-6s + index*300ms
21
+ *
22
+ * Data comes from the web AppHost (openApps with minimized === true) instead
23
+ * of the native MinimizedToolsContext — same derivation the MinimizedDock
24
+ * used before this replaced it.
25
+ */
26
+
27
+ // native MinimizedToolsStack.tsx constants
28
+ const PEEK_HEIGHT = 28;
29
+ const TOOL_ITEM_SIZE = 32;
30
+ const ICON_GAP = 6;
31
+ const TOOLBAR_PADDING = 8;
32
+ const COLLAPSE_BUTTON_SIZE = 24;
33
+ const STORAGE_KEY_EXPANDED = '@react_buoy_minimized_stack_expanded';
34
+ const GLITCH_DURATION_MS = 80;
35
+ const MIN_GLITCH_DELAY = 2000;
36
+ const MAX_GLITCH_DELAY = 6000;
37
+
38
+ // native shared-ui buoyColors (gameUIColors.ts) — card + textMuted
39
+ const CARD = '#1A1A1A';
40
+ const TEXT_MUTED = '#888888';
41
+ function ChevronGlyph({
42
+ down = false
43
+ }) {
44
+ // native: ChevronUp size 12, strokeWidth 2, buoyColors.textMuted
45
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("svg", {
46
+ width: 12,
47
+ height: 12,
48
+ viewBox: "0 0 24 24",
49
+ "aria-hidden": "true",
50
+ style: {
51
+ transform: down ? 'rotate(180deg)' : undefined
52
+ },
53
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("path", {
54
+ d: "M18 15l-6-6-6 6",
55
+ fill: "none",
56
+ stroke: TEXT_MUTED,
57
+ strokeWidth: "2",
58
+ strokeLinecap: "round",
59
+ strokeLinejoin: "round"
60
+ })
61
+ });
62
+ }
63
+ function GlitchToolButton({
64
+ title,
65
+ icon,
66
+ index,
67
+ onPress
68
+ }) {
69
+ const innerRef = (0, _react.useRef)(null);
70
+ (0, _react.useEffect)(() => {
71
+ let mounted = true;
72
+ let timer;
73
+ const runGlitch = () => {
74
+ // native: parallel translateX shake / opacity flicker / scale pulse,
75
+ // all inside GLITCH_DURATION_MS — one WAAPI animation with offsets.
76
+ innerRef.current?.animate([{
77
+ transform: 'translateX(0) scale(1)',
78
+ opacity: 1,
79
+ offset: 0
80
+ }, {
81
+ transform: 'translateX(3px) scale(1.05)',
82
+ opacity: 0.4,
83
+ offset: 0.2
84
+ }, {
85
+ transform: 'translateX(-3px) scale(1.1)',
86
+ opacity: 1,
87
+ offset: 0.4
88
+ }, {
89
+ transform: 'translateX(2px) scale(1.0)',
90
+ opacity: 0.6,
91
+ offset: 0.6
92
+ }, {
93
+ transform: 'translateX(-1px) scale(0.95)',
94
+ opacity: 1,
95
+ offset: 0.8
96
+ }, {
97
+ transform: 'translateX(0) scale(1)',
98
+ opacity: 1,
99
+ offset: 1
100
+ }], {
101
+ duration: GLITCH_DURATION_MS,
102
+ easing: 'linear'
103
+ });
104
+ };
105
+ const schedule = initial => {
106
+ const delay = initial ? 500 + Math.random() * 1500 + index * 200 : MIN_GLITCH_DELAY + Math.random() * (MAX_GLITCH_DELAY - MIN_GLITCH_DELAY) + index * 300;
107
+ timer = setTimeout(() => {
108
+ if (!mounted) return;
109
+ runGlitch();
110
+ schedule(false);
111
+ }, delay);
112
+ };
113
+ schedule(true);
114
+ return () => {
115
+ mounted = false;
116
+ clearTimeout(timer);
117
+ };
118
+ }, [index]);
119
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
120
+ type: "button",
121
+ "aria-label": `Restore ${title}`,
122
+ onClick: onPress,
123
+ style: {
124
+ width: TOOL_ITEM_SIZE,
125
+ height: TOOL_ITEM_SIZE,
126
+ display: 'flex',
127
+ alignItems: 'center',
128
+ justifyContent: 'center',
129
+ background: 'none',
130
+ border: 'none',
131
+ padding: 0,
132
+ cursor: 'pointer'
133
+ },
134
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
135
+ ref: innerRef,
136
+ style: {
137
+ display: 'flex',
138
+ alignItems: 'center',
139
+ justifyContent: 'center'
140
+ },
141
+ children: icon
142
+ })
143
+ });
144
+ }
145
+ function MinimizedToolsStack({
146
+ containerWidth = 32
147
+ }) {
148
+ const {
149
+ openApps,
150
+ restore
151
+ } = (0, _AppHostWeb.useAppHost)();
152
+ const minimized = openApps.filter(app => app.minimized && app.launchMode !== 'toggle-only');
153
+ const [isExpanded, setIsExpanded] = (0, _react.useState)(false);
154
+ const [isStateRestored, setIsStateRestored] = (0, _react.useState)(false);
155
+
156
+ // Restore + persist the expanded flag (native ExpandablePopover persistState).
157
+ (0, _react.useEffect)(() => {
158
+ let cancelled = false;
159
+ const load = async () => {
160
+ const saved = await _sharedUi.persistentStorage.getItem(STORAGE_KEY_EXPANDED);
161
+ if (!cancelled && saved === 'true') setIsExpanded(true);
162
+ if (!cancelled) setIsStateRestored(true);
163
+ };
164
+ void load();
165
+ return () => {
166
+ cancelled = true;
167
+ };
168
+ }, []);
169
+ (0, _react.useEffect)(() => {
170
+ if (!isStateRestored) return;
171
+ void _sharedUi.persistentStorage.setItem(STORAGE_KEY_EXPANDED, isExpanded ? 'true' : 'false');
172
+ }, [isExpanded, isStateRestored]);
173
+ const handleRestore = (0, _react.useCallback)(instanceId => {
174
+ restore(instanceId);
175
+ }, [restore]);
176
+ if (minimized.length === 0) return null;
177
+
178
+ // native: expandedHeight = padding + n*item + (n-1)*gap + gap + collapse + 4
179
+ const expandedHeight = TOOLBAR_PADDING + minimized.length * TOOL_ITEM_SIZE + (minimized.length - 1) * ICON_GAP + ICON_GAP + COLLAPSE_BUTTON_SIZE + 4;
180
+ const frame = {
181
+ // native peekButton/expandedContainer: card bg, top corners 6, 1px border
182
+ // on top/left/right only (fuses with the bubble below)
183
+ backgroundColor: CARD,
184
+ borderTopLeftRadius: 6,
185
+ borderTopRightRadius: 6,
186
+ borderTop: `1px solid ${TEXT_MUTED}66`,
187
+ borderLeft: `1px solid ${TEXT_MUTED}66`,
188
+ borderRight: `1px solid ${TEXT_MUTED}66`,
189
+ borderBottom: 'none',
190
+ boxSizing: 'border-box'
191
+ };
192
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
193
+ style: {
194
+ height: PEEK_HEIGHT,
195
+ overflow: 'visible',
196
+ position: 'relative'
197
+ },
198
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
199
+ style: {
200
+ position: 'absolute',
201
+ bottom: 0,
202
+ left: 0,
203
+ width: containerWidth,
204
+ height: isExpanded ? expandedHeight : 0,
205
+ opacity: isExpanded ? 1 : 0,
206
+ overflow: 'hidden',
207
+ transition: 'height 200ms ease, opacity 200ms ease',
208
+ pointerEvents: isExpanded ? 'auto' : 'none',
209
+ ...frame
210
+ },
211
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
212
+ style: {
213
+ height: expandedHeight,
214
+ display: 'flex',
215
+ flexDirection: 'column',
216
+ alignItems: 'center',
217
+ paddingTop: TOOLBAR_PADDING,
218
+ gap: ICON_GAP,
219
+ boxSizing: 'border-box'
220
+ },
221
+ children: [[...minimized].reverse().map((app, index) => /*#__PURE__*/(0, _jsxRuntime.jsx)(GlitchToolButton, {
222
+ title: app.title || app.id,
223
+ icon: app.icon ?? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
224
+ style: {
225
+ color: '#fff',
226
+ fontSize: 13
227
+ },
228
+ children: (app.title || app.id).slice(0, 1).toUpperCase()
229
+ }),
230
+ index: index,
231
+ onPress: () => handleRestore(app.instanceId)
232
+ }, app.instanceId)), /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
233
+ type: "button",
234
+ "aria-label": "Collapse",
235
+ onClick: () => setIsExpanded(false),
236
+ style: {
237
+ width: '100%',
238
+ height: COLLAPSE_BUTTON_SIZE,
239
+ marginTop: 3,
240
+ display: 'flex',
241
+ alignItems: 'center',
242
+ justifyContent: 'center',
243
+ background: 'none',
244
+ border: 'none',
245
+ cursor: 'pointer',
246
+ padding: 0
247
+ },
248
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ChevronGlyph, {
249
+ down: true
250
+ })
251
+ })]
252
+ })
253
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
254
+ type: "button",
255
+ "aria-label": `Show ${minimized.length} minimized tools`,
256
+ onClick: () => setIsExpanded(true),
257
+ style: {
258
+ position: 'absolute',
259
+ bottom: 0,
260
+ left: 0,
261
+ width: containerWidth,
262
+ height: PEEK_HEIGHT,
263
+ display: 'flex',
264
+ flexDirection: 'row',
265
+ alignItems: 'center',
266
+ justifyContent: 'center',
267
+ gap: 2,
268
+ cursor: 'pointer',
269
+ padding: 0,
270
+ opacity: isExpanded ? 0 : 1,
271
+ transform: isExpanded ? 'scale(0.9)' : 'scale(1)',
272
+ transition: 'opacity 200ms ease, transform 200ms ease',
273
+ pointerEvents: isExpanded ? 'none' : 'auto',
274
+ ...frame
275
+ },
276
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(ChevronGlyph, {}), minimized.length > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
277
+ style: {
278
+ fontSize: 9,
279
+ fontWeight: 600,
280
+ color: TEXT_MUTED,
281
+ marginLeft: 1
282
+ },
283
+ children: minimized.length
284
+ })]
285
+ })]
286
+ });
287
+ }
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ToolModalShell = ToolModalShell;
7
+ exports.useToolHeader = useToolHeader;
8
+ exports.useToolHost = useToolHost;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _reactNative = require("react-native");
11
+ var _sharedUi = require("@buoy-gg/shared-ui");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ 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); }
14
+ /**
15
+ * ToolHost — the declarative chrome layer for custom tools.
16
+ *
17
+ * When an `InstalledApp` declares `modal: {...}`, the AppHost renders its
18
+ * component inside `ToolModalShell` instead of raw: the shared JsModal
19
+ * (drag/resize, floating⇄bottom-sheet, minimize, dimension persistence) plus
20
+ * a managed header (title/subtitle, back navigation, search, actions) and a
21
+ * lightweight toast layer. The tool body talks back to the shell through
22
+ * `useToolHost()` / `useToolHeader()`.
23
+ */
24
+
25
+ /** Per-screen header overrides a tool body can apply (see `useToolHeader`). */
26
+
27
+ const noop = () => {};
28
+ const FALLBACK_CONTEXT = {
29
+ search: "",
30
+ isSearchActive: false,
31
+ clearSearch: noop,
32
+ close: noop,
33
+ showToast: noop,
34
+ setHeaderOverride: noop
35
+ };
36
+ const ToolHostContext = /*#__PURE__*/(0, _react.createContext)(null);
37
+
38
+ /**
39
+ * Access the hosting shell from a custom tool body: search query, toasts,
40
+ * close. Safe to call outside the shell (returns inert no-ops) so tool
41
+ * components can also be mounted standalone.
42
+ */
43
+ function useToolHost() {
44
+ return (0, _react.useContext)(ToolHostContext) ?? FALLBACK_CONTEXT;
45
+ }
46
+
47
+ /**
48
+ * Declare per-screen header state (title/subtitle/actions/back) from inside a
49
+ * tool body. Applies while the calling component is mounted and reverts to
50
+ * the preset's static config on unmount — so a detail screen simply mounts
51
+ * with its own header and the list header returns when it unmounts.
52
+ *
53
+ * ```tsx
54
+ * useToolHeader(
55
+ * { title: flag.key, onBack: () => setScreen("list"), actions: <CopyButton value={flag} /> },
56
+ * [flag.key]
57
+ * );
58
+ * ```
59
+ */
60
+ function useToolHeader(override, deps) {
61
+ const {
62
+ setHeaderOverride
63
+ } = useToolHost();
64
+ (0, _react.useEffect)(() => {
65
+ setHeaderOverride(override);
66
+ return () => setHeaderOverride(null);
67
+ // Caller-provided deps intentionally control when the override refreshes.
68
+ // eslint-disable-next-line react-hooks/exhaustive-deps
69
+ }, deps);
70
+ }
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // Toast layer
74
+ // ---------------------------------------------------------------------------
75
+
76
+ const TOAST_DURATION_MS = 2200;
77
+ const TOAST_COLORS = {
78
+ success: _sharedUi.gameUIColors.success,
79
+ error: _sharedUi.gameUIColors.error,
80
+ info: _sharedUi.gameUIColors.info
81
+ };
82
+ function ToastView({
83
+ message,
84
+ type,
85
+ nonce
86
+ }) {
87
+ const opacity = (0, _react.useRef)(new _reactNative.Animated.Value(0)).current;
88
+ (0, _react.useEffect)(() => {
89
+ opacity.setValue(0);
90
+ _reactNative.Animated.sequence([_reactNative.Animated.timing(opacity, {
91
+ toValue: 1,
92
+ duration: 150,
93
+ useNativeDriver: true
94
+ }), _reactNative.Animated.delay(TOAST_DURATION_MS - 450), _reactNative.Animated.timing(opacity, {
95
+ toValue: 0,
96
+ duration: 300,
97
+ useNativeDriver: true
98
+ })]).start();
99
+ }, [nonce, opacity]);
100
+ const color = TOAST_COLORS[type];
101
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Animated.View, {
102
+ pointerEvents: "none",
103
+ style: [styles.toast, {
104
+ opacity,
105
+ borderColor: color + "60"
106
+ }],
107
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
108
+ style: [styles.toastDot, {
109
+ backgroundColor: color
110
+ }]
111
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
112
+ style: styles.toastText,
113
+ numberOfLines: 2,
114
+ children: message
115
+ })]
116
+ });
117
+ }
118
+
119
+ // ---------------------------------------------------------------------------
120
+ // Shell
121
+ // ---------------------------------------------------------------------------
122
+
123
+ function ToolModalShell({
124
+ app,
125
+ config,
126
+ visible,
127
+ zIndex,
128
+ onClose,
129
+ onMinimize,
130
+ initialModalState,
131
+ enableSharedModalDimensions,
132
+ bodyProps
133
+ }) {
134
+ const Body = app.component;
135
+ const [isSearchActive, setIsSearchActive] = (0, _react.useState)(false);
136
+ const [search, setSearch] = (0, _react.useState)("");
137
+ const [headerOverride, setHeaderOverride] = (0, _react.useState)(null);
138
+ const [toast, setToast] = (0, _react.useState)(null);
139
+ const toastTimeoutRef = (0, _react.useRef)(null);
140
+ const clearSearch = (0, _react.useCallback)(() => {
141
+ setIsSearchActive(false);
142
+ setSearch("");
143
+ }, []);
144
+ const showToast = (0, _react.useCallback)((message, type = "info") => {
145
+ if (toastTimeoutRef.current) clearTimeout(toastTimeoutRef.current);
146
+ setToast(prev => ({
147
+ message,
148
+ type,
149
+ nonce: (prev?.nonce ?? 0) + 1
150
+ }));
151
+ toastTimeoutRef.current = setTimeout(() => setToast(null), TOAST_DURATION_MS);
152
+ }, []);
153
+ (0, _react.useEffect)(() => {
154
+ return () => {
155
+ if (toastTimeoutRef.current) clearTimeout(toastTimeoutRef.current);
156
+ };
157
+ }, []);
158
+ const contextValue = (0, _react.useMemo)(() => ({
159
+ search: isSearchActive ? search : "",
160
+ isSearchActive,
161
+ clearSearch,
162
+ close: onClose,
163
+ showToast,
164
+ setHeaderOverride,
165
+ instanceId: app.instanceId
166
+ }), [search, isSearchActive, clearSearch, onClose, showToast, app.instanceId]);
167
+ const title = headerOverride?.title ?? config.title ?? app.title ?? app.id;
168
+ const subtitle = headerOverride?.subtitle ?? config.subtitle;
169
+ const onBack = headerOverride?.onBack;
170
+ const actions = headerOverride?.actions ?? config.headerActions;
171
+
172
+ // Tool-scoped persistence via the custom namespace unless the user has the
173
+ // shared-dimensions global setting on (all tools share one window size).
174
+ const persistenceKey = enableSharedModalDimensions ? _sharedUi.devToolsStorageKeys.modal.root() : _sharedUi.devToolsStorageKeys.custom(app.id).modal();
175
+ const header = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader, {
176
+ children: [onBack && !isSearchActive && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Navigation, {
177
+ onBack: onBack
178
+ }), isSearchActive ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Search, {
179
+ value: search,
180
+ onChangeText: setSearch,
181
+ onCancel: clearSearch,
182
+ placeholder: config.searchPlaceholder
183
+ }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ModalHeader.Content, {
184
+ title: title,
185
+ subtitle: subtitle
186
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_sharedUi.ModalHeader.Actions, {
187
+ children: [!isSearchActive && actions, config.searchable && !isSearchActive && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.HeaderSearchButton, {
188
+ onPress: () => setIsSearchActive(true)
189
+ })]
190
+ })]
191
+ });
192
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(ToolHostContext.Provider, {
193
+ value: contextValue,
194
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.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__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
214
+ style: styles.bodyRoot,
215
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Body, {
216
+ ...bodyProps
217
+ }), toast && /*#__PURE__*/(0, _jsxRuntime.jsx)(ToastView, {
218
+ message: toast.message,
219
+ type: toast.type,
220
+ nonce: toast.nonce
221
+ })]
222
+ })
223
+ })
224
+ });
225
+ }
226
+ const styles = _reactNative.StyleSheet.create({
227
+ bodyRoot: {
228
+ flex: 1,
229
+ minHeight: 0,
230
+ backgroundColor: _sharedUi.buoyColors.base
231
+ },
232
+ toast: {
233
+ position: "absolute",
234
+ bottom: 16,
235
+ alignSelf: "center",
236
+ flexDirection: "row",
237
+ alignItems: "center",
238
+ gap: 8,
239
+ maxWidth: "86%",
240
+ backgroundColor: _sharedUi.buoyColors.card,
241
+ borderWidth: 1,
242
+ borderRadius: 8,
243
+ paddingHorizontal: 12,
244
+ paddingVertical: 8,
245
+ shadowColor: "#000",
246
+ shadowOpacity: 0.4,
247
+ shadowRadius: 8,
248
+ shadowOffset: {
249
+ width: 0,
250
+ height: 2
251
+ },
252
+ elevation: 6
253
+ },
254
+ toastDot: {
255
+ width: 6,
256
+ height: 6,
257
+ borderRadius: 3
258
+ },
259
+ toastText: {
260
+ flex: 1,
261
+ fontSize: 12,
262
+ color: _sharedUi.buoyColors.text
263
+ }
264
+ });
@@ -113,6 +113,13 @@ const ALL_TOOLS_REGISTRY = exports.ALL_TOOLS_REGISTRY = [{
113
113
  renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.EventsIcon, {
114
114
  size: size
115
115
  })
116
+ }, {
117
+ id: "time-machine",
118
+ name: "TIME MACHINE",
119
+ color: _floatingToolsCore.TIME_MACHINE_ICON_COLOR,
120
+ renderIcon: size => /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsCore.TimeMachineIcon, {
121
+ size: size
122
+ })
116
123
  }, {
117
124
  id: "jotai",
118
125
  name: "JOTAI",
@@ -189,6 +189,22 @@ function autoDiscoverPresets() {
189
189
  }
190
190
  }
191
191
  },
192
+ // Time Machine
193
+ {
194
+ name: "@buoy-gg/time-machine",
195
+ loader: () => {
196
+ try {
197
+ // @ts-ignore - Dynamic import that may not exist
198
+ const {
199
+ timeMachineToolPreset
200
+ } = require("@buoy-gg/time-machine");
201
+ return timeMachineToolPreset;
202
+ } catch (e) {
203
+ (0, _optionalRequire.reportOptionalRequireError)("@buoy-gg/time-machine", e);
204
+ return null;
205
+ }
206
+ }
207
+ },
192
208
  // Redux DevTools
193
209
  {
194
210
  name: "@buoy-gg/redux",
@@ -318,6 +334,22 @@ function autoDiscoverPresets() {
318
334
  return null;
319
335
  }
320
336
  }
337
+ },
338
+ // ASSETS — bundled-asset inventory (sizes / scale coverage / unused)
339
+ {
340
+ name: "@buoy-gg/assets",
341
+ loader: () => {
342
+ try {
343
+ // @ts-ignore - Dynamic import that may not exist
344
+ const {
345
+ assetsToolPreset
346
+ } = require("@buoy-gg/assets");
347
+ return assetsToolPreset;
348
+ } catch (e) {
349
+ (0, _optionalRequire.reportOptionalRequireError)("@buoy-gg/assets", e);
350
+ return null;
351
+ }
352
+ }
321
353
  }];
322
354
 
323
355
  // Attempt to load each preset
@@ -44,6 +44,7 @@ let zustandModule = null;
44
44
  let jotaiModule = null;
45
45
  let eventsModule = null;
46
46
  let consoleModule = null;
47
+ let timeMachineModule = null;
47
48
  let envModule = null;
48
49
  let highlightUpdatesModule = null;
49
50
  let debugBordersModule = null;
@@ -51,6 +52,7 @@ let impersonateModule = null;
51
52
  let perfMonitorModule = null;
52
53
  let jsTopModule = null;
53
54
  let imagesModule = null;
55
+ let assetsModule = null;
54
56
  let expoConstantsModule = null;
55
57
 
56
58
  // Catch bodies report through reportOptionalRequireError: silent for a
@@ -106,6 +108,11 @@ try {
106
108
  } catch (e) {
107
109
  (0, _optionalRequire.reportOptionalRequireError)("@buoy-gg/console", e);
108
110
  }
111
+ try {
112
+ timeMachineModule = require("@buoy-gg/time-machine");
113
+ } catch (e) {
114
+ (0, _optionalRequire.reportOptionalRequireError)("@buoy-gg/time-machine", e);
115
+ }
109
116
  try {
110
117
  envModule = require("@buoy-gg/env");
111
118
  } catch (e) {
@@ -141,6 +148,11 @@ try {
141
148
  } catch (e) {
142
149
  (0, _optionalRequire.reportOptionalRequireError)("@buoy-gg/images", e);
143
150
  }
151
+ try {
152
+ assetsModule = require("@buoy-gg/assets");
153
+ } catch (e) {
154
+ (0, _optionalRequire.reportOptionalRequireError)("@buoy-gg/assets", e);
155
+ }
144
156
  try {
145
157
  expoConstantsModule = require("expo-constants");
146
158
  } catch (e) {
@@ -254,6 +266,9 @@ function AutoExternalSync({
254
266
  if (consoleModule?.consoleSyncAdapter) {
255
267
  map.console = consoleModule.consoleSyncAdapter;
256
268
  }
269
+ if (timeMachineModule?.timeMachineSyncAdapter) {
270
+ map["time-machine"] = timeMachineModule.timeMachineSyncAdapter;
271
+ }
257
272
  if (envModule?.createEnvSyncAdapter) {
258
273
  map.env = envModule.createEnvSyncAdapter(requiredEnvVars ?? []);
259
274
  }
@@ -275,6 +290,9 @@ function AutoExternalSync({
275
290
  if (imagesModule?.imagesSyncAdapter) {
276
291
  map.images = imagesModule.imagesSyncAdapter;
277
292
  }
293
+ if (assetsModule?.assetsSyncAdapter) {
294
+ map.assets = assetsModule.assetsSyncAdapter;
295
+ }
278
296
  return map;
279
297
  }, [queryAdapter, requiredEnvVars]);
280
298
  useExternalSync({