@buoy-gg/core 7.0.36 → 7.0.39

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 (103) hide show
  1. package/README.md +57 -69
  2. package/bin/buoy.js +71 -20
  3. package/lib/commonjs/Buoy.js +3 -16
  4. package/lib/commonjs/floatingMenu/AppHost.js +1 -1
  5. package/lib/commonjs/floatingMenu/AppHost.web.js +1 -1
  6. package/lib/commonjs/floatingMenu/AppIcon.web.js +53 -0
  7. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.js +12 -5
  8. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +14 -34
  9. package/lib/commonjs/floatingMenu/FloatingDevTools.js +32 -48
  10. package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +24 -4
  11. package/lib/commonjs/floatingMenu/FloatingMenu.js +1 -1
  12. package/lib/commonjs/floatingMenu/ToolHost.js +1 -0
  13. package/lib/commonjs/floatingMenu/autoExternalSync.js +3 -2
  14. package/lib/commonjs/floatingMenu/dial/DialDevTools.js +43 -10
  15. package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +18 -5
  16. package/lib/commonjs/floatingMenu/dial/dialUsageStore.js +13 -17
  17. package/lib/commonjs/floatingMenu/dial/onboardingConstants.js +37 -65
  18. package/lib/commonjs/floatingMenu/dial/onboardingConstants.web.js +37 -29
  19. package/lib/commonjs/floatingMenu/floatingTools.js +23 -889
  20. package/lib/commonjs/floatingMenu/floatingTools.web.js +24 -514
  21. package/lib/commonjs/floatingMenu/optionalRequire.js +4 -0
  22. package/lib/commonjs/telemetry/installPing.js +7 -0
  23. package/lib/commonjs/version.js +1 -1
  24. package/lib/module/Buoy.js +3 -16
  25. package/lib/module/floatingMenu/AppHost.js +1 -1
  26. package/lib/module/floatingMenu/AppHost.web.js +1 -1
  27. package/lib/module/floatingMenu/AppIcon.web.js +47 -0
  28. package/lib/module/floatingMenu/DevToolsSettingsModal.js +13 -6
  29. package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +15 -35
  30. package/lib/module/floatingMenu/FloatingDevTools.js +35 -49
  31. package/lib/module/floatingMenu/FloatingDevTools.web.js +24 -3
  32. package/lib/module/floatingMenu/FloatingMenu.js +1 -1
  33. package/lib/module/floatingMenu/ToolHost.js +1 -0
  34. package/lib/module/floatingMenu/autoExternalSync.js +3 -2
  35. package/lib/module/floatingMenu/dial/DialDevTools.js +43 -10
  36. package/lib/module/floatingMenu/dial/DialDevTools.web.js +18 -5
  37. package/lib/module/floatingMenu/dial/dialUsageStore.js +14 -18
  38. package/lib/module/floatingMenu/dial/onboardingConstants.js +1 -62
  39. package/lib/module/floatingMenu/dial/onboardingConstants.web.js +1 -25
  40. package/lib/module/floatingMenu/floatingTools.js +15 -890
  41. package/lib/module/floatingMenu/floatingTools.web.js +1 -517
  42. package/lib/module/floatingMenu/optionalRequire.js +4 -0
  43. package/lib/module/telemetry/installPing.js +7 -0
  44. package/lib/module/version.js +1 -1
  45. package/lib/typescript/commonjs/Buoy.d.ts +14 -3
  46. package/lib/typescript/commonjs/Buoy.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/floatingMenu/AppIcon.web.d.ts +14 -0
  48. package/lib/typescript/commonjs/floatingMenu/AppIcon.web.d.ts.map +1 -0
  49. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  50. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts +4 -14
  52. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts +4 -19
  54. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  55. package/lib/typescript/commonjs/floatingMenu/ToolHost.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts +3 -4
  57. package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  59. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/floatingMenu/dial/dialUsageStore.d.ts +3 -15
  61. package/lib/typescript/commonjs/floatingMenu/dial/dialUsageStore.d.ts.map +1 -1
  62. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.d.ts +1 -29
  63. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts +1 -12
  65. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts +6 -55
  67. package/lib/typescript/commonjs/floatingMenu/floatingTools.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts +3 -53
  69. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/floatingMenu/optionalRequire.d.ts.map +1 -1
  71. package/lib/typescript/commonjs/telemetry/installPing.d.ts +8 -1
  72. package/lib/typescript/commonjs/telemetry/installPing.d.ts.map +1 -1
  73. package/lib/typescript/commonjs/version.d.ts +1 -1
  74. package/lib/typescript/module/Buoy.d.ts +14 -3
  75. package/lib/typescript/module/Buoy.d.ts.map +1 -1
  76. package/lib/typescript/module/floatingMenu/AppIcon.web.d.ts +14 -0
  77. package/lib/typescript/module/floatingMenu/AppIcon.web.d.ts.map +1 -0
  78. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.d.ts.map +1 -1
  79. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  80. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts +4 -14
  81. package/lib/typescript/module/floatingMenu/FloatingDevTools.d.ts.map +1 -1
  82. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts +4 -19
  83. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  84. package/lib/typescript/module/floatingMenu/ToolHost.d.ts.map +1 -1
  85. package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts +3 -4
  86. package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +1 -1
  87. package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  88. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  89. package/lib/typescript/module/floatingMenu/dial/dialUsageStore.d.ts +3 -15
  90. package/lib/typescript/module/floatingMenu/dial/dialUsageStore.d.ts.map +1 -1
  91. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.d.ts +1 -29
  92. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.d.ts.map +1 -1
  93. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts +1 -12
  94. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts.map +1 -1
  95. package/lib/typescript/module/floatingMenu/floatingTools.d.ts +6 -55
  96. package/lib/typescript/module/floatingMenu/floatingTools.d.ts.map +1 -1
  97. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts +3 -53
  98. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts.map +1 -1
  99. package/lib/typescript/module/floatingMenu/optionalRequire.d.ts.map +1 -1
  100. package/lib/typescript/module/telemetry/installPing.d.ts +8 -1
  101. package/lib/typescript/module/telemetry/installPing.d.ts.map +1 -1
  102. package/lib/typescript/module/version.d.ts +1 -1
  103. package/package.json +6 -6
@@ -3,518 +3,28 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.Divider = Divider;
7
- exports.FloatingTools = FloatingTools;
8
- exports.UserStatus = UserStatus;
9
- exports.getBubbleAnchorPosition = getBubbleAnchorPosition;
10
- var _react = require("react");
11
- var _onboardingConstantsWeb = require("./dial/onboardingConstants.web.js");
12
- var _floatingToolsReact = require("@buoy-gg/floating-tools-react");
13
- var _jsxRuntime = require("react/jsx-runtime");
14
- /**
15
- * FloatingTools - Web renderer using shared React bindings.
16
- *
17
- * This file contains ONLY web-specific code (React DOM):
18
- * - Pointer event handling (mouse + touch — WKWebView/Capacitor included)
19
- * - requestAnimationFrame animation
20
- * - Web JSX (div, span)
21
- * - localStorage adapter
22
- *
23
- * All logic is shared via @buoy-gg/floating-tools-react
24
- *
25
- * @platform React DOM Web (Vite, CRA, Next.js, Electron)
26
- */
27
-
28
- // Re-export for consumers
29
-
30
- // =============================
31
- // Web Storage Adapter
32
- // =============================
33
- const webStorageAdapter = {
34
- getItem: key => localStorage.getItem(key),
35
- setItem: (key, value) => localStorage.setItem(key, value)
36
- };
37
-
38
- // =============================
39
- // Native color values not present in floatingToolsColors
40
- // (core's `secondary` is #E0E0E0 = buoyColors.text; the native bubble uses
41
- // buoyColors.textSecondary #A0A0A0 for grip dots and "User" label text.
42
- // Inlined here rather than changed in core because dial.ts also consumes
43
- // floatingToolsColors.secondary for other surfaces.)
44
- // =============================
45
- // native shared-ui gameUIColors.ts: buoyColors.textSecondary = "#A0A0A0"
46
- const NATIVE_TEXT_SECONDARY = '#A0A0A0';
47
-
48
- // =============================
49
- // GripVerticalIcon (web JSX)
50
- // =============================
51
- function GripVerticalIcon({
52
- size = 24,
53
- // native shared-ui GripVerticalIcon.tsx: buoyColors.textSecondary + "CC"
54
- color = (0, _floatingToolsReact.withAlpha)(NATIVE_TEXT_SECONDARY, 'CC')
55
- }) {
56
- const layout = (0, _floatingToolsReact.getGripIconLayout)(size);
57
- return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
58
- style: {
59
- width: size,
60
- height: size,
61
- display: 'flex',
62
- flexDirection: 'row',
63
- alignItems: 'center',
64
- justifyContent: 'center'
65
- },
66
- children: [0, 1].map(col => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
67
- style: {
68
- display: 'flex',
69
- flexDirection: 'column',
70
- alignItems: 'center',
71
- justifyContent: 'center',
72
- // native GripVerticalIcon.tsx: marginHorizontal columnGap / 2
73
- marginLeft: layout.columnGap / 2,
74
- marginRight: layout.columnGap / 2
75
- },
76
- children: [0, 1, 2].map(row => /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
77
- style: {
78
- width: layout.dotSize,
79
- height: layout.dotSize,
80
- borderRadius: layout.dotSize / 2,
81
- backgroundColor: color,
82
- // native GripVerticalIcon.tsx: marginVertical rowGap / 2
83
- marginTop: layout.rowGap / 2,
84
- marginBottom: layout.rowGap / 2
85
- }
86
- }, row))
87
- }, col))
88
- });
89
- }
90
-
91
- // =============================
92
- // Divider (web JSX)
93
- // =============================
94
- function Divider() {
95
- return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
96
- style: {
97
- width: 1,
98
- height: 12,
99
- backgroundColor: (0, _floatingToolsReact.withAlpha)(_floatingToolsReact.floatingToolsColors.muted, '66'),
100
- flexShrink: 0
101
- }
102
- });
103
- }
104
-
105
- // =============================
106
- // UserStatus (web JSX)
107
- // =============================
108
- // Mirrors the native gameUIColorsCompat mapping in floatingTools.tsx:
109
- // success/optional/muted come from the shared palette, but `secondary`
110
- // (the "User" label text) is buoyColors.textSecondary, not core's secondary.
111
- const userStatusColors = {
112
- success: _floatingToolsReact.floatingToolsColors.success,
113
- optional: _floatingToolsReact.floatingToolsColors.optional,
114
- muted: _floatingToolsReact.floatingToolsColors.muted,
115
- // native floatingTools.tsx: gameUIColorsCompat.secondary = buoyColors.textSecondary
116
- secondary: NATIVE_TEXT_SECONDARY
117
- };
118
- function UserStatus({
119
- userRole,
120
- onPress
121
- }) {
122
- const {
123
- isDragging
124
- } = (0, _floatingToolsReact.useFloatingToolsContext)();
125
- const config = (0, _floatingToolsReact.getUserStatusConfig)(userRole, userStatusColors);
126
- const handleClick = e => {
127
- if (!isDragging && onPress) {
128
- e.stopPropagation();
129
- onPress();
130
- }
131
- };
132
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)("button", {
133
- role: "button",
134
- "aria-label": `User status: ${config.label}`,
135
- onClick: handleClick,
136
- style: {
137
- display: 'flex',
138
- flexDirection: 'row',
139
- alignItems: 'center',
140
- paddingTop: 6,
141
- paddingBottom: 6,
142
- paddingLeft: 8,
143
- paddingRight: 8,
144
- flexShrink: 0,
145
- cursor: onPress && !isDragging ? 'pointer' : 'default',
146
- background: 'none',
147
- border: 'none',
148
- margin: 0 // neutralize UA button margin (native View/Touchable has none)
149
- },
150
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
151
- style: {
152
- width: 6,
153
- height: 6,
154
- borderRadius: 3,
155
- backgroundColor: config.dotColor,
156
- marginRight: 4
157
- }
158
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
159
- style: {
160
- fontSize: 10,
161
- fontWeight: 500,
162
- color: config.textColor,
163
- letterSpacing: 0.3,
164
- // native RN <Text> renders in the platform system font; buttons
165
- // otherwise use the UA font on web
166
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
167
- lineHeight: 'normal'
168
- },
169
- children: config.label
170
- })]
171
- });
172
- }
173
-
174
- // =============================
175
- // Web Animation Hook
176
- // =============================
177
- function useWebAnimation() {
178
- const animationRef = (0, _react.useRef)(null);
179
- const [position, setPosition] = (0, _react.useState)({
180
- x: 0,
181
- y: 0
182
- });
183
- const animateTo = (0, _react.useCallback)((from, to, onComplete) => {
184
- if (animationRef.current) {
185
- cancelAnimationFrame(animationRef.current);
186
- }
187
- const startTime = performance.now();
188
- const animate = currentTime => {
189
- const elapsed = currentTime - startTime;
190
- const progress = Math.min(elapsed / _floatingToolsReact.ANIMATION_DURATION, 1);
191
- const newPosition = (0, _floatingToolsReact.interpolatePosition)(from, to, progress, _floatingToolsReact.easing.easeOutCubic);
192
- setPosition(newPosition);
193
- if (progress < 1) {
194
- animationRef.current = requestAnimationFrame(animate);
195
- } else {
196
- setPosition(to);
197
- onComplete?.();
198
- }
199
- };
200
- animationRef.current = requestAnimationFrame(animate);
201
- }, []);
202
- (0, _react.useEffect)(() => {
203
- return () => {
204
- if (animationRef.current) {
205
- cancelAnimationFrame(animationRef.current);
206
- }
207
- };
208
- }, []);
209
- return {
210
- position,
211
- setPosition,
212
- animateTo
213
- };
214
- }
215
-
216
- // =============================
217
- // Main FloatingTools Component
218
- // =============================
219
-
220
- // Last known bubble position — the AppHost minimize animation targets this so
221
- // tools shrink toward the stack instead of the old bottom-right dock.
222
- let lastBubbleAnchor = null;
223
- function getBubbleAnchorPosition() {
224
- return lastBubbleAnchor;
225
- }
226
- function FloatingTools({
227
- enablePositionPersistence = true,
228
- children,
229
- pushToSide = false,
230
- suspendPointerEvents = false,
231
- centerOnboarding = false,
232
- minimizedStack,
233
- hasMinimizedStack = false
234
- }) {
235
- const bubbleRef = (0, _react.useRef)(null);
236
-
237
- // Use shared hook
238
- const {
239
- state,
240
- actions,
241
- isInitialized
242
- } = (0, _floatingToolsReact.useFloatingTools)({
243
- screenSize: {
244
- width: window.innerWidth,
245
- height: window.innerHeight
246
- },
247
- enablePositionPersistence,
248
- storage: webStorageAdapter
249
- });
250
-
251
- // Web-specific animation
252
- const {
253
- position: animatedPosition,
254
- setPosition: setAnimatedPosition,
255
- animateTo
256
- } = useWebAnimation();
257
-
258
- // Sync position when initialized
259
- (0, _react.useEffect)(() => {
260
- if (isInitialized) {
261
- setAnimatedPosition(state.position);
262
- }
263
- }, [isInitialized, state.position, setAnimatedPosition]);
264
-
265
- // Publish the bubble anchor for the AppHost minimize-target (stack lives
266
- // fused to the bubble now, not in a fixed dock).
267
- (0, _react.useEffect)(() => {
268
- lastBubbleAnchor = {
269
- x: animatedPosition.x,
270
- y: animatedPosition.y
271
- };
272
- }, [animatedPosition]);
273
-
274
- // Handle window resize
275
- (0, _react.useEffect)(() => {
276
- const handleResize = () => {
277
- actions.setScreenSize(window.innerWidth, window.innerHeight);
278
- };
279
- window.addEventListener('resize', handleResize);
280
- return () => window.removeEventListener('resize', handleResize);
281
- }, [actions]);
282
-
283
- // Update bubble size on layout
284
- const [bubbleMeasured, setBubbleMeasured] = (0, _react.useState)(false);
285
- (0, _react.useEffect)(() => {
286
- if (!bubbleMeasured && bubbleRef.current) {
287
- const rect = bubbleRef.current.getBoundingClientRect();
288
- if (rect.width > 0 && rect.height > 0) {
289
- actions.setBubbleSize({
290
- width: rect.width,
291
- height: rect.height
292
- });
293
- setBubbleMeasured(true);
294
- }
295
- }
296
- }, [bubbleMeasured, actions]);
297
-
298
- // Keep the bubble below notches/status bars (WKWebView with viewport-fit=cover).
299
- (0, _react.useEffect)(() => {
300
- const probe = document.createElement('div');
301
- probe.style.cssText = 'position:fixed;top:env(safe-area-inset-top);left:env(safe-area-inset-left);' + 'visibility:hidden;pointer-events:none';
302
- document.body.appendChild(probe);
303
- const rect = probe.getBoundingClientRect();
304
- document.body.removeChild(probe);
305
- if (rect.top > 0 || rect.left > 0) {
306
- actions.setMinPosition({
307
- x: Math.max(rect.left, 10),
308
- y: Math.max(rect.top, 10)
309
- });
310
- }
311
- }, [actions]);
312
-
313
- // Web-specific: pointer event handling (mouse + touch).
314
- // preventDefault on pointerdown suppresses the compatibility mouse events,
315
- // and touchAction: 'none' on the bubble stops touch-drags from scrolling.
316
- const [isPointerDown, setIsPointerDown] = (0, _react.useState)(false);
317
- const handlePointerDown = (0, _react.useCallback)(e => {
318
- e.preventDefault();
319
- setIsPointerDown(true);
320
- actions.handleDragStart({
321
- clientX: e.clientX,
322
- clientY: e.clientY
323
- });
324
- }, [actions]);
325
- const handlePointerMove = (0, _react.useCallback)(e => {
326
- const result = actions.handleDragMove({
327
- clientX: e.clientX,
328
- clientY: e.clientY
329
- });
330
- if (result.isDragging) {
331
- setAnimatedPosition(result.position);
332
- }
333
- }, [actions, setAnimatedPosition]);
334
- const handlePointerUp = (0, _react.useCallback)(e => {
335
- setIsPointerDown(false);
336
- const result = actions.handleDragEnd({
337
- clientX: e.clientX,
338
- clientY: e.clientY
339
- });
340
- if (result.wasTap) {
341
- const toggleResult = actions.toggleHideShow();
342
- animateTo(state.position, toggleResult.targetPosition, () => {
343
- actions.commitPosition(toggleResult.targetPosition);
344
- });
345
- } else if (result.shouldHide) {
346
- animateTo(state.position, result.position, () => {
347
- actions.commitPosition(result.position);
348
- });
349
- }
350
- }, [actions, animateTo, state.position]);
351
- (0, _react.useEffect)(() => {
352
- if (isPointerDown) {
353
- window.addEventListener('pointermove', handlePointerMove);
354
- window.addEventListener('pointerup', handlePointerUp);
355
- window.addEventListener('pointercancel', handlePointerUp);
356
- return () => {
357
- window.removeEventListener('pointermove', handlePointerMove);
358
- window.removeEventListener('pointerup', handlePointerUp);
359
- window.removeEventListener('pointercancel', handlePointerUp);
360
- };
361
- }
362
- }, [isPointerDown, handlePointerMove, handlePointerUp]);
363
-
364
- // Live refs so the pushToSide effect never animates from a stale closure
365
- // (the from-position jump read as a "pop" when restoring).
366
- const statePositionRef = (0, _react.useRef)(state.position);
367
- statePositionRef.current = state.position;
368
- const isHiddenRef = (0, _react.useRef)(state.isHidden);
369
- isHiddenRef.current = state.isHidden;
370
-
371
- // pushToSide: forceHide to the edge while a dial/tool is open; forceShow
372
- // restores the saved position when it closes (200ms, native parity).
373
- // Native semantics ported exactly (floatingTools.tsx:537-603):
374
- // - push only when the bubble isn't already hidden (a user-hidden bubble
375
- // is left alone, and we don't claim it as OUR push)
376
- // - restore only when the bubble is STILL hidden from OUR push — if the
377
- // user tapped/dragged it back out while a tool was open
378
- // (userWantsVisibleRef), it stays exactly where they put it
379
- const pushedRef = (0, _react.useRef)(false);
380
- (0, _react.useEffect)(() => {
381
- if (!isInitialized) return;
382
- if (pushToSide && !pushedRef.current) {
383
- if (isHiddenRef.current) return; // user hid it themselves — not our push
384
- pushedRef.current = true;
385
- const {
386
- targetPosition
387
- } = actions.forceHide();
388
- animateTo(statePositionRef.current, targetPosition, () => {});
389
- } else if (!pushToSide && pushedRef.current) {
390
- pushedRef.current = false;
391
- // User already showed it manually while the tool was open — leave it.
392
- if (!isHiddenRef.current) return;
393
- const {
394
- targetPosition
395
- } = actions.forceShow();
396
- // The bubble may have grown while hidden (row tools/env badge toggled
397
- // on) — clamp the restored position so it stays fully on-screen
398
- // (native handles this via its width-change auto-reposition).
399
- const width = bubbleRef.current?.getBoundingClientRect().width ?? 100;
400
- const clamped = {
401
- x: Math.max(10, Math.min(targetPosition.x, window.innerWidth - width - 10)),
402
- y: targetPosition.y
403
- };
404
- animateTo(statePositionRef.current, clamped, () => {
405
- actions.commitPosition(clamped);
406
- });
407
- }
408
- // eslint-disable-next-line react-hooks/exhaustive-deps
409
- }, [pushToSide, isInitialized]);
410
-
411
- // centerOnboarding: park the bubble under the tooltip arrow while the
412
- // welcome tooltip is up (native calculateTargetPosition math).
413
- (0, _react.useEffect)(() => {
414
- if (!centerOnboarding || !isInitialized) return;
415
- const bubbleWidth = bubbleRef.current?.getBoundingClientRect().width ?? 100;
416
- const bubbleHeight = bubbleRef.current?.getBoundingClientRect().height ?? 32;
417
- const fromBottom = (0, _onboardingConstantsWeb.calculateTargetPosition)();
418
- const target = {
419
- x: (window.innerWidth - bubbleWidth) / 2,
420
- y: window.innerHeight - fromBottom - bubbleHeight
421
- };
422
- animateTo(statePositionRef.current, target, () => {});
423
- // eslint-disable-next-line react-hooks/exhaustive-deps
424
- }, [centerOnboarding, isInitialized]);
425
-
426
- // Interleave children with dividers
427
- const actionsContent = (0, _react.useMemo)(() => (0, _floatingToolsReact.interleaveWithDividers)(_react.Children.toArray(children), key => /*#__PURE__*/(0, _jsxRuntime.jsx)(Divider, {}, key)), [children]);
428
-
429
- // Suppress the first paint until the persisted position has loaded so the
430
- // bubble doesn't flash at 0,0 (native floatingTools.tsx:935-937).
431
- if (!isInitialized) {
432
- return null;
6
+ Object.defineProperty(exports, "Divider", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _floating.FloatingToolDivider;
433
10
  }
434
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
435
- ref: bubbleRef,
436
- role: "toolbar",
437
- "aria-label": "Floating Tools",
438
- style: {
439
- position: 'fixed',
440
- left: animatedPosition.x,
441
- top: animatedPosition.y,
442
- zIndex: 9999,
443
- display: 'flex',
444
- flexDirection: 'row',
445
- alignItems: 'center',
446
- backgroundColor: _floatingToolsReact.floatingToolsColors.panel,
447
- // native: top-left corner + top border flatten when the minimized
448
- // stack is fused above (floatingTools.tsx containerStyle)
449
- borderTopLeftRadius: hasMinimizedStack ? 0 : 6,
450
- borderTopRightRadius: 6,
451
- borderBottomLeftRadius: 6,
452
- borderBottomRightRadius: 6,
453
- borderWidth: state.isDragging ? 2 : 1,
454
- borderTopWidth: state.isDragging ? 2 : hasMinimizedStack ? 0 : 1,
455
- borderStyle: 'solid',
456
- borderColor: state.isDragging ? _floatingToolsReact.floatingToolsColors.dragActive : (0, _floatingToolsReact.withAlpha)(_floatingToolsReact.floatingToolsColors.muted, '66'),
457
- // native floatingTools.tsx: shadowOffset {0, 6|4}, shadowRadius 12|8,
458
- // shadowOpacity 0.6|0.3, shadowColor dragActive+"99"|"#000".
459
- // Dragging color = 0x99 (0.6) alpha x 0.6 shadowOpacity = ~0.36 effective.
460
- boxShadow: state.isDragging ? `0 6px 12px ${(0, _floatingToolsReact.withAlpha)(_floatingToolsReact.floatingToolsColors.dragActive, 0.36)}` : '0 4px 8px rgba(0, 0, 0, 0.3)',
461
- userSelect: 'none',
462
- touchAction: 'none',
463
- pointerEvents: suspendPointerEvents ? 'none' : 'auto'
464
- },
465
- children: [minimizedStack && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
466
- style: {
467
- position: 'absolute',
468
- bottom: '100%',
469
- left: -1,
470
- // align with the bubble border edge
471
- width: _floatingToolsReact.VISIBLE_HANDLE_WIDTH,
472
- overflow: 'visible',
473
- zIndex: 1001
474
- },
475
- children: minimizedStack
476
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
477
- role: "slider",
478
- "aria-label": "Drag handle",
479
- "aria-valuetext": `Position: ${Math.round(animatedPosition.x)}, ${Math.round(animatedPosition.y)}`,
480
- tabIndex: 0,
481
- onPointerDown: handlePointerDown,
482
- style: {
483
- touchAction: 'none',
484
- paddingLeft: 6,
485
- paddingRight: 6,
486
- paddingTop: 6,
487
- paddingBottom: 6,
488
- backgroundColor: (0, _floatingToolsReact.withAlpha)(_floatingToolsReact.floatingToolsColors.muted, '1A'),
489
- display: 'flex',
490
- alignItems: 'center',
491
- justifyContent: 'center',
492
- width: _floatingToolsReact.VISIBLE_HANDLE_WIDTH,
493
- boxSizing: 'border-box',
494
- // RN width includes padding/border
495
- borderRight: `1px solid ${(0, _floatingToolsReact.withAlpha)(_floatingToolsReact.floatingToolsColors.muted, '66')}`,
496
- // native dragHandleStyle sets NO corner radius (container overflow is
497
- // visible); the 10%-alpha bg square corner matches native rendering
498
- cursor: state.isDragging ? 'grabbing' : 'grab'
499
- },
500
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(GripVerticalIcon, {
501
- size: 12
502
- })
503
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingToolsReact.FloatingToolsProvider, {
504
- value: {
505
- isDragging: state.isDragging,
506
- isHidden: state.isHidden
507
- },
508
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
509
- style: {
510
- display: 'flex',
511
- flexDirection: 'row',
512
- alignItems: 'center',
513
- gap: 6,
514
- paddingRight: 8
515
- },
516
- children: actionsContent
517
- })
518
- })]
519
- });
520
- }
11
+ });
12
+ Object.defineProperty(exports, "FloatingTools", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _floating.FloatingTool;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "UserStatus", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _floating.FloatingToolUserStatus;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "getBubbleAnchorPosition", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _floating.getBubbleAnchorPosition;
28
+ }
29
+ });
30
+ var _floating = require("@buoy-gg/shared-ui/floating");
@@ -20,6 +20,10 @@ const MODULE_NOT_FOUND_RE = /could not be found within the project|Cannot find m
20
20
  */
21
21
  function reportOptionalRequireError(moduleName, err) {
22
22
  if (!isDev) return;
23
+ // Under an ESM bundler (the desktop's Vite renderer) `require` itself does
24
+ // not exist, so every guarded require fails the same way. That says nothing
25
+ // about the package, so it is not worth a warning.
26
+ if (typeof require !== "function") return;
23
27
  const message = err instanceof Error ? err.message : String(err);
24
28
  const code = err?.code;
25
29
  const isNotFound = code === "MODULE_NOT_FOUND" || MODULE_NOT_FOUND_RE.test(message);
@@ -74,6 +74,13 @@ function announceOnce() {
74
74
  }
75
75
  let sentThisSession = false;
76
76
 
77
+ /**
78
+ * What the ping reports about the account: the tier of an admitted account,
79
+ * or "locked" for an install that has not been admitted (no key, or a key the
80
+ * license server rejected). "locked" is what gives "how many installs never
81
+ * get an account" its numerator.
82
+ */
83
+
77
84
  /**
78
85
  * Send the ping if it is due. Safe to call on every mount: it is idempotent
79
86
  * within a session, throttled to once a day across sessions, and resolves
@@ -15,4 +15,4 @@ exports.SDK_VERSION = void 0;
15
15
  * Drift is prevented by a test that fails when this disagrees with
16
16
  * package.json, so a version bump that forgets this file cannot ship.
17
17
  */
18
- const SDK_VERSION = exports.SDK_VERSION = "7.0.36";
18
+ const SDK_VERSION = exports.SDK_VERSION = "7.0.39";
@@ -56,16 +56,7 @@ export const Buoy = {
56
56
  */
57
57
  init(config) {
58
58
  if (config.telemetry === false) telemetryEnabled = false;
59
-
60
- // If no license key or empty string, clear any cached license
61
- if (!config.licenseKey || config.licenseKey.trim() === "") {
62
- LicenseManager.initialize().then(() => LicenseManager.clearLicense()).catch(() => {});
63
- return;
64
- }
65
-
66
- // Initialize the license manager and set the key
67
- const key = config.licenseKey; // We've already checked it's not empty above
68
- LicenseManager.initialize().then(() => LicenseManager.setLicenseKey(key)).catch(error => {
59
+ void LicenseManager.configure(config.licenseKey).catch(error => {
69
60
  console.warn("[Buoy] License initialization failed:", error);
70
61
  });
71
62
  },
@@ -83,12 +74,8 @@ export const Buoy = {
83
74
  * ```
84
75
  */
85
76
  async initAsync(config) {
86
- if (!config.licenseKey) {
87
- console.warn("[Buoy] No license key provided to Buoy.initAsync()");
88
- return false;
89
- }
90
- await LicenseManager.initialize();
91
- return LicenseManager.setLicenseKey(config.licenseKey);
77
+ if (config.telemetry === false) telemetryEnabled = false;
78
+ return LicenseManager.configure(config.licenseKey);
92
79
  },
93
80
  /**
94
81
  * Check if Buoy Pro is active
@@ -4,7 +4,7 @@ import { persistentStorage, setExpandableWindowControls } from "@buoy-gg/shared-
4
4
  import React, { createContext, useCallback, useContext, useMemo, useState, useEffect, useRef } from "react";
5
5
  import { BackHandler, Modal, StyleSheet, View } from "react-native";
6
6
  import { resolveOpenAppsState } from "./AppHostLogic.js";
7
- import { renderAppIcon } from "./AppIcon.js";
7
+ import { renderAppIcon } from "./AppIcon";
8
8
  import { useMinimizedTools } from "./MinimizedToolsContext.js";
9
9
  import { ToolModalShell } from "./ToolHost.js";
10
10
  import { useDevToolsSettings } from "./DevToolsSettingsModal";
@@ -25,7 +25,7 @@
25
25
  import { persistentStorage } from "@buoy-gg/shared-ui";
26
26
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
27
27
  import { resolveOpenAppsState } from "./AppHostLogic.js";
28
- import { renderAppIcon } from "./AppIcon.js";
28
+ import { renderAppIcon } from "./AppIcon";
29
29
  import { getBubbleAnchorPosition } from "./floatingTools.web.js";
30
30
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
31
31
  const AppHostContext = /*#__PURE__*/createContext(null);
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+
3
+ import React from "react";
4
+ import { toolTheme } from "@buoy-gg/shared-ui";
5
+ import { jsx as _jsx } from "react/jsx-runtime";
6
+ /** DOM twin of the native icon resolver; importing RN breaks pure web hosts. */
7
+ export function AppTextIcon({
8
+ label,
9
+ size,
10
+ color = toolTheme.colors.text
11
+ }) {
12
+ const chars = Math.max(Array.from(label.replace(/[\uFE00-\uFE0F\u200D]/g, "")).length, 1);
13
+ const maxWidth = chars <= 2 ? size : size * 1.6;
14
+ const fontSize = Math.max(7, Math.min(size * (chars === 1 ? 0.7 : 0.62), maxWidth / (0.62 * chars)));
15
+ return /*#__PURE__*/_jsx("span", {
16
+ style: {
17
+ display: "inline-flex",
18
+ minWidth: size,
19
+ maxWidth,
20
+ height: size,
21
+ alignItems: "center",
22
+ justifyContent: "center",
23
+ color,
24
+ fontSize,
25
+ fontWeight: 800,
26
+ letterSpacing: 0.5,
27
+ whiteSpace: "nowrap",
28
+ overflow: "hidden"
29
+ },
30
+ children: label
31
+ });
32
+ }
33
+ export function renderAppIcon(icon, ctx) {
34
+ if (icon == null) return icon;
35
+ if (typeof icon === "function") return /*#__PURE__*/React.createElement(icon, {
36
+ slot: ctx.slot,
37
+ size: ctx.size,
38
+ state: ctx.state,
39
+ actions: ctx.actions
40
+ });
41
+ if (typeof icon === "string" || typeof icon === "number") return /*#__PURE__*/_jsx(AppTextIcon, {
42
+ label: String(icon),
43
+ size: ctx.size,
44
+ color: ctx.color
45
+ });
46
+ return icon;
47
+ }