@buoy-gg/floating-tools-core 2.1.4-beta.1 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/FloatingToolsStore.js +1 -501
- package/lib/commonjs/colors.js +1 -54
- package/lib/commonjs/constants.js +1 -31
- package/lib/commonjs/devToolsState.js +1 -325
- package/lib/commonjs/dial.js +1 -617
- package/lib/commonjs/easing.js +1 -69
- package/lib/commonjs/icons/benchmark-icon.js +1 -24
- package/lib/commonjs/icons/env-icon.js +1 -24
- package/lib/commonjs/icons/events-icon.js +1 -24
- package/lib/commonjs/icons/highlight-icon.js +1 -24
- package/lib/commonjs/icons/icon-data.js +1 -2268
- package/lib/commonjs/icons/icon-factories.js +1 -173
- package/lib/commonjs/icons/icon-primitives.js +1 -559
- package/lib/commonjs/icons/icon-primitives.native.js +1 -779
- package/lib/commonjs/icons/icon-renderer.js +1 -260
- package/lib/commonjs/icons/network-icon.js +1 -24
- package/lib/commonjs/icons/query-icon.js +1 -24
- package/lib/commonjs/icons/redux-icon.js +1 -85
- package/lib/commonjs/icons/renders-icon.js +1 -33
- package/lib/commonjs/icons/routes-icon.js +1 -49
- package/lib/commonjs/icons/sentry-icon.js +1 -24
- package/lib/commonjs/icons/storage-icon.js +1 -24
- package/lib/commonjs/icons/wifi-icon.js +1 -24
- package/lib/commonjs/index.js +1 -723
- package/lib/commonjs/settings.js +1 -588
- package/lib/commonjs/utils.js +1 -72
- package/lib/module/FloatingToolsStore.js +1 -496
- package/lib/module/colors.js +1 -49
- package/lib/module/constants.js +1 -27
- package/lib/module/devToolsState.js +1 -318
- package/lib/module/dial.js +1 -603
- package/lib/module/easing.js +1 -62
- package/lib/module/icons/benchmark-icon.js +1 -15
- package/lib/module/icons/env-icon.js +1 -15
- package/lib/module/icons/events-icon.js +1 -15
- package/lib/module/icons/highlight-icon.js +1 -15
- package/lib/module/icons/icon-data.js +1 -2264
- package/lib/module/icons/icon-factories.js +1 -163
- package/lib/module/icons/icon-primitives.js +1 -547
- package/lib/module/icons/icon-primitives.native.js +1 -767
- package/lib/module/icons/icon-renderer.js +1 -255
- package/lib/module/icons/network-icon.js +1 -15
- package/lib/module/icons/query-icon.js +1 -15
- package/lib/module/icons/redux-icon.js +1 -81
- package/lib/module/icons/renders-icon.js +1 -17
- package/lib/module/icons/routes-icon.js +1 -41
- package/lib/module/icons/sentry-icon.js +1 -15
- package/lib/module/icons/storage-icon.js +1 -15
- package/lib/module/icons/wifi-icon.js +1 -15
- package/lib/module/index.js +1 -103
- package/lib/module/settings.js +1 -576
- package/lib/module/utils.js +1 -66
- package/package.json +1 -1
- package/lib/typescript/commonjs/FloatingToolsStore.d.ts.map +0 -1
- package/lib/typescript/commonjs/colors.d.ts.map +0 -1
- package/lib/typescript/commonjs/constants.d.ts.map +0 -1
- package/lib/typescript/commonjs/devToolsState.d.ts.map +0 -1
- package/lib/typescript/commonjs/dial.d.ts.map +0 -1
- package/lib/typescript/commonjs/easing.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/benchmark-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/env-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/events-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/highlight-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/icon-data.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/icon-factories.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/icon-primitives.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/icon-primitives.native.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/icon-renderer.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/network-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/query-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/redux-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/renders-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/routes-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/sentry-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/storage-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/icons/wifi-icon.d.ts.map +0 -1
- package/lib/typescript/commonjs/index.d.ts.map +0 -1
- package/lib/typescript/commonjs/settings.d.ts.map +0 -1
- package/lib/typescript/commonjs/types.d.ts.map +0 -1
- package/lib/typescript/commonjs/utils.d.ts.map +0 -1
- package/lib/typescript/module/FloatingToolsStore.d.ts.map +0 -1
- package/lib/typescript/module/colors.d.ts.map +0 -1
- package/lib/typescript/module/constants.d.ts.map +0 -1
- package/lib/typescript/module/devToolsState.d.ts.map +0 -1
- package/lib/typescript/module/dial.d.ts.map +0 -1
- package/lib/typescript/module/easing.d.ts.map +0 -1
- package/lib/typescript/module/icons/benchmark-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/env-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/events-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/highlight-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/icon-data.d.ts.map +0 -1
- package/lib/typescript/module/icons/icon-factories.d.ts.map +0 -1
- package/lib/typescript/module/icons/icon-primitives.d.ts.map +0 -1
- package/lib/typescript/module/icons/icon-primitives.native.d.ts.map +0 -1
- package/lib/typescript/module/icons/icon-renderer.d.ts.map +0 -1
- package/lib/typescript/module/icons/network-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/query-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/redux-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/renders-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/routes-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/sentry-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/storage-icon.d.ts.map +0 -1
- package/lib/typescript/module/icons/wifi-icon.d.ts.map +0 -1
- package/lib/typescript/module/index.d.ts.map +0 -1
- package/lib/typescript/module/settings.d.ts.map +0 -1
- package/lib/typescript/module/types.d.ts.map +0 -1
- package/lib/typescript/module/utils.d.ts.map +0 -1
|
@@ -1,501 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.FloatingToolsStore = void 0;
|
|
7
|
-
var _constants = require("./constants.js");
|
|
8
|
-
/**
|
|
9
|
-
* FloatingToolsStore - Headless state management for floating tools.
|
|
10
|
-
*
|
|
11
|
-
* This class manages all the business logic for the floating tools bubble:
|
|
12
|
-
* - Position state and validation
|
|
13
|
-
* - Drag detection (tap vs drag)
|
|
14
|
-
* - Hide/show toggle
|
|
15
|
-
* - Auto-hide when dragged past edge
|
|
16
|
-
* - Position persistence
|
|
17
|
-
*
|
|
18
|
-
* Platform-specific code (animation, event handling) is NOT included here.
|
|
19
|
-
* Use this with platform-specific hooks/bindings.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
class FloatingToolsStore {
|
|
23
|
-
// State
|
|
24
|
-
|
|
25
|
-
isDragging = false;
|
|
26
|
-
isHidden = false;
|
|
27
|
-
|
|
28
|
-
// Configuration
|
|
29
|
-
|
|
30
|
-
// Callbacks
|
|
31
|
-
|
|
32
|
-
// Drag tracking
|
|
33
|
-
dragStartPos = {
|
|
34
|
-
x: 0,
|
|
35
|
-
y: 0
|
|
36
|
-
};
|
|
37
|
-
dragStartMouse = {
|
|
38
|
-
x: 0,
|
|
39
|
-
y: 0
|
|
40
|
-
};
|
|
41
|
-
hasMoved = false;
|
|
42
|
-
savedPosition = null;
|
|
43
|
-
|
|
44
|
-
// Persistence
|
|
45
|
-
saveTimeout = null;
|
|
46
|
-
isInitialized = false;
|
|
47
|
-
|
|
48
|
-
// Subscribers (for useSyncExternalStore)
|
|
49
|
-
listeners = new Set();
|
|
50
|
-
constructor(options) {
|
|
51
|
-
this.screenWidth = options.screenWidth;
|
|
52
|
-
this.screenHeight = options.screenHeight;
|
|
53
|
-
this.bubbleSize = options.initialBubbleSize ?? {
|
|
54
|
-
width: 100,
|
|
55
|
-
height: 32
|
|
56
|
-
};
|
|
57
|
-
this.minPosition = options.minPosition ?? {
|
|
58
|
-
x: _constants.EDGE_PADDING,
|
|
59
|
-
y: _constants.EDGE_PADDING
|
|
60
|
-
};
|
|
61
|
-
this.visibleHandleWidth = options.visibleHandleWidth ?? _constants.VISIBLE_HANDLE_WIDTH;
|
|
62
|
-
this.dragThreshold = options.dragThreshold ?? _constants.DRAG_THRESHOLD;
|
|
63
|
-
this.edgePadding = options.edgePadding ?? _constants.EDGE_PADDING;
|
|
64
|
-
this.enablePositionPersistence = options.enablePositionPersistence ?? true;
|
|
65
|
-
this.storage = options.storage;
|
|
66
|
-
this.onPositionChange = options.onPositionChange;
|
|
67
|
-
this.onHiddenChange = options.onHiddenChange;
|
|
68
|
-
this.onDraggingChange = options.onDraggingChange;
|
|
69
|
-
|
|
70
|
-
// Default position
|
|
71
|
-
this.position = options.initialPosition ?? {
|
|
72
|
-
x: this.screenWidth - this.bubbleSize.width - 20,
|
|
73
|
-
y: Math.max(this.minPosition.y, Math.min(100, this.screenHeight - this.bubbleSize.height - this.edgePadding))
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// Initialize snapshot
|
|
77
|
-
this.stateSnapshot = this.createSnapshot();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// =============================
|
|
81
|
-
// Subscription (for React hooks)
|
|
82
|
-
// =============================
|
|
83
|
-
|
|
84
|
-
subscribe = listener => {
|
|
85
|
-
this.listeners.add(listener);
|
|
86
|
-
return () => this.listeners.delete(listener);
|
|
87
|
-
};
|
|
88
|
-
getSnapshot = () => {
|
|
89
|
-
return this.stateSnapshot;
|
|
90
|
-
};
|
|
91
|
-
createSnapshot() {
|
|
92
|
-
return {
|
|
93
|
-
position: {
|
|
94
|
-
...this.position
|
|
95
|
-
},
|
|
96
|
-
isDragging: this.isDragging,
|
|
97
|
-
isHidden: this.isHidden,
|
|
98
|
-
bubbleSize: {
|
|
99
|
-
...this.bubbleSize
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
notify() {
|
|
104
|
-
this.stateSnapshot = this.createSnapshot();
|
|
105
|
-
this.listeners.forEach(listener => listener());
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// =============================
|
|
109
|
-
// Initialization
|
|
110
|
-
// =============================
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Initialize the store by loading persisted position.
|
|
114
|
-
* Call this after setting up storage adapter.
|
|
115
|
-
*/
|
|
116
|
-
async initialize() {
|
|
117
|
-
if (this.isInitialized || !this.enablePositionPersistence || !this.storage) {
|
|
118
|
-
this.isInitialized = true;
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
try {
|
|
122
|
-
const [xStr, yStr] = await Promise.all([this.storage.getItem(_constants.STORAGE_KEYS.POSITION_X), this.storage.getItem(_constants.STORAGE_KEYS.POSITION_Y)]);
|
|
123
|
-
if (xStr !== null && yStr !== null) {
|
|
124
|
-
const x = parseFloat(xStr);
|
|
125
|
-
const y = parseFloat(yStr);
|
|
126
|
-
if (!Number.isNaN(x) && !Number.isNaN(y)) {
|
|
127
|
-
const saved = {
|
|
128
|
-
x,
|
|
129
|
-
y
|
|
130
|
-
};
|
|
131
|
-
const validated = this.validatePosition(saved);
|
|
132
|
-
|
|
133
|
-
// Save corrected position if out of bounds
|
|
134
|
-
if (Math.abs(saved.x - validated.x) > 5 || Math.abs(saved.y - validated.y) > 5) {
|
|
135
|
-
this.savePosition(validated.x, validated.y);
|
|
136
|
-
}
|
|
137
|
-
this.position = validated;
|
|
138
|
-
|
|
139
|
-
// Check if loaded in hidden state
|
|
140
|
-
if (validated.x >= this.screenWidth - this.visibleHandleWidth - 5) {
|
|
141
|
-
this.isHidden = true;
|
|
142
|
-
}
|
|
143
|
-
this.notify();
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
} catch {
|
|
147
|
-
// Failed to load - use default position
|
|
148
|
-
}
|
|
149
|
-
this.isInitialized = true;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// =============================
|
|
153
|
-
// Position Management
|
|
154
|
-
// =============================
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Get current bounds for position validation.
|
|
158
|
-
*/
|
|
159
|
-
getBounds() {
|
|
160
|
-
return {
|
|
161
|
-
minX: this.minPosition.x,
|
|
162
|
-
maxX: this.screenWidth - this.visibleHandleWidth,
|
|
163
|
-
minY: this.minPosition.y,
|
|
164
|
-
maxY: this.screenHeight - this.bubbleSize.height - this.edgePadding
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Validate and clamp a position to screen boundaries.
|
|
170
|
-
*/
|
|
171
|
-
validatePosition(pos) {
|
|
172
|
-
const bounds = this.getBounds();
|
|
173
|
-
return {
|
|
174
|
-
x: Math.max(bounds.minX, Math.min(pos.x, bounds.maxX)),
|
|
175
|
-
y: Math.max(bounds.minY, Math.min(pos.y, bounds.maxY))
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Set position directly (for animation callbacks).
|
|
181
|
-
*/
|
|
182
|
-
setPosition(pos) {
|
|
183
|
-
this.position = pos;
|
|
184
|
-
this.onPositionChange?.(pos);
|
|
185
|
-
this.notify();
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Update bubble size (call on layout).
|
|
190
|
-
* Only notifies if size actually changed.
|
|
191
|
-
*/
|
|
192
|
-
setBubbleSize(size) {
|
|
193
|
-
if (this.bubbleSize.width === size.width && this.bubbleSize.height === size.height) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
this.bubbleSize = size;
|
|
197
|
-
this.notify();
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Update screen dimensions (call on resize).
|
|
202
|
-
*/
|
|
203
|
-
setScreenSize(width, height) {
|
|
204
|
-
this.screenWidth = width;
|
|
205
|
-
this.screenHeight = height;
|
|
206
|
-
// Re-validate position
|
|
207
|
-
const validated = this.validatePosition(this.position);
|
|
208
|
-
if (validated.x !== this.position.x || validated.y !== this.position.y) {
|
|
209
|
-
this.position = validated;
|
|
210
|
-
this.notify();
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Update min position (e.g., for safe area insets).
|
|
216
|
-
*/
|
|
217
|
-
setMinPosition(minPos) {
|
|
218
|
-
this.minPosition = minPos;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// =============================
|
|
222
|
-
// Persistence
|
|
223
|
-
// =============================
|
|
224
|
-
|
|
225
|
-
async savePosition(x, y) {
|
|
226
|
-
if (!this.enablePositionPersistence || !this.storage) return;
|
|
227
|
-
try {
|
|
228
|
-
await Promise.all([this.storage.setItem(_constants.STORAGE_KEYS.POSITION_X, x.toString()), this.storage.setItem(_constants.STORAGE_KEYS.POSITION_Y, y.toString())]);
|
|
229
|
-
} catch {
|
|
230
|
-
// Failed to save - continue without persistence
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
debouncedSavePosition(x, y) {
|
|
234
|
-
if (this.saveTimeout) clearTimeout(this.saveTimeout);
|
|
235
|
-
this.saveTimeout = setTimeout(() => this.savePosition(x, y), _constants.SAVE_DEBOUNCE_MS);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// =============================
|
|
239
|
-
// Hide/Show Toggle
|
|
240
|
-
// =============================
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Toggle between hidden and visible states.
|
|
244
|
-
* Returns the target position for animation.
|
|
245
|
-
*/
|
|
246
|
-
toggleHideShow() {
|
|
247
|
-
const isVisuallyOffScreen = this.position.x > this.screenWidth - this.bubbleSize.width / 2;
|
|
248
|
-
if (this.isHidden || isVisuallyOffScreen) {
|
|
249
|
-
// Show the bubble
|
|
250
|
-
let targetX;
|
|
251
|
-
let targetY;
|
|
252
|
-
if (this.savedPosition && this.savedPosition.x < this.screenWidth - this.bubbleSize.width / 2) {
|
|
253
|
-
targetX = this.savedPosition.x;
|
|
254
|
-
targetY = this.savedPosition.y;
|
|
255
|
-
} else {
|
|
256
|
-
targetX = this.screenWidth - this.bubbleSize.width - 20;
|
|
257
|
-
targetY = this.position.y;
|
|
258
|
-
}
|
|
259
|
-
this.isHidden = false;
|
|
260
|
-
this.onHiddenChange?.(false);
|
|
261
|
-
this.notify();
|
|
262
|
-
return {
|
|
263
|
-
targetPosition: {
|
|
264
|
-
x: targetX,
|
|
265
|
-
y: targetY
|
|
266
|
-
},
|
|
267
|
-
isHiding: false
|
|
268
|
-
};
|
|
269
|
-
} else {
|
|
270
|
-
// Hide the bubble
|
|
271
|
-
this.savedPosition = {
|
|
272
|
-
...this.position
|
|
273
|
-
};
|
|
274
|
-
const hiddenX = this.screenWidth - this.visibleHandleWidth;
|
|
275
|
-
this.isHidden = true;
|
|
276
|
-
this.onHiddenChange?.(true);
|
|
277
|
-
this.notify();
|
|
278
|
-
return {
|
|
279
|
-
targetPosition: {
|
|
280
|
-
x: hiddenX,
|
|
281
|
-
y: this.position.y
|
|
282
|
-
},
|
|
283
|
-
isHiding: true
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Force hide (for pushToSide behavior).
|
|
290
|
-
*/
|
|
291
|
-
forceHide() {
|
|
292
|
-
if (this.isHidden) {
|
|
293
|
-
return {
|
|
294
|
-
targetPosition: this.position
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
this.savedPosition = {
|
|
298
|
-
...this.position
|
|
299
|
-
};
|
|
300
|
-
const hiddenX = this.screenWidth - this.visibleHandleWidth;
|
|
301
|
-
this.isHidden = true;
|
|
302
|
-
this.onHiddenChange?.(true);
|
|
303
|
-
this.notify();
|
|
304
|
-
return {
|
|
305
|
-
targetPosition: {
|
|
306
|
-
x: hiddenX,
|
|
307
|
-
y: this.position.y
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Force show (restore from pushToSide).
|
|
314
|
-
*/
|
|
315
|
-
forceShow() {
|
|
316
|
-
if (!this.isHidden) {
|
|
317
|
-
return {
|
|
318
|
-
targetPosition: this.position
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
let targetX;
|
|
322
|
-
let targetY;
|
|
323
|
-
if (this.savedPosition) {
|
|
324
|
-
targetX = this.savedPosition.x;
|
|
325
|
-
targetY = this.savedPosition.y;
|
|
326
|
-
} else {
|
|
327
|
-
targetX = this.screenWidth - this.bubbleSize.width - 20;
|
|
328
|
-
targetY = this.position.y;
|
|
329
|
-
}
|
|
330
|
-
this.isHidden = false;
|
|
331
|
-
this.onHiddenChange?.(false);
|
|
332
|
-
this.notify();
|
|
333
|
-
return {
|
|
334
|
-
targetPosition: {
|
|
335
|
-
x: targetX,
|
|
336
|
-
y: targetY
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// =============================
|
|
342
|
-
// Drag Handling
|
|
343
|
-
// =============================
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Start a drag operation.
|
|
347
|
-
*/
|
|
348
|
-
handleDragStart(event) {
|
|
349
|
-
this.hasMoved = false;
|
|
350
|
-
this.dragStartPos = {
|
|
351
|
-
...this.position
|
|
352
|
-
};
|
|
353
|
-
this.dragStartMouse = {
|
|
354
|
-
x: event.clientX,
|
|
355
|
-
y: event.clientY
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Process drag movement.
|
|
361
|
-
* Returns the new position (for animation) and whether drag threshold was exceeded.
|
|
362
|
-
*/
|
|
363
|
-
handleDragMove(event) {
|
|
364
|
-
const dx = event.clientX - this.dragStartMouse.x;
|
|
365
|
-
const dy = event.clientY - this.dragStartMouse.y;
|
|
366
|
-
const totalDistance = Math.abs(dx) + Math.abs(dy);
|
|
367
|
-
|
|
368
|
-
// Check if moved enough to be considered a drag
|
|
369
|
-
if (!this.hasMoved && totalDistance > this.dragThreshold) {
|
|
370
|
-
this.hasMoved = true;
|
|
371
|
-
this.isDragging = true;
|
|
372
|
-
this.onDraggingChange?.(true);
|
|
373
|
-
this.notify();
|
|
374
|
-
}
|
|
375
|
-
if (this.hasMoved) {
|
|
376
|
-
const newX = this.dragStartPos.x + dx;
|
|
377
|
-
const newY = this.dragStartPos.y + dy;
|
|
378
|
-
|
|
379
|
-
// Allow overflow to right for hide detection, but clamp Y
|
|
380
|
-
const bounds = this.getBounds();
|
|
381
|
-
const clampedX = Math.max(bounds.minX, Math.min(newX, this.screenWidth - this.visibleHandleWidth + this.bubbleSize.width));
|
|
382
|
-
const clampedY = Math.max(bounds.minY, Math.min(newY, bounds.maxY));
|
|
383
|
-
this.position = {
|
|
384
|
-
x: clampedX,
|
|
385
|
-
y: clampedY
|
|
386
|
-
};
|
|
387
|
-
this.onPositionChange?.(this.position);
|
|
388
|
-
this.notify();
|
|
389
|
-
return {
|
|
390
|
-
position: this.position,
|
|
391
|
-
isDragging: true
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
return {
|
|
395
|
-
position: this.position,
|
|
396
|
-
isDragging: false
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* End a drag operation.
|
|
402
|
-
* Returns the result including whether to animate to hidden state.
|
|
403
|
-
*/
|
|
404
|
-
handleDragEnd(event) {
|
|
405
|
-
const wasTap = !this.hasMoved;
|
|
406
|
-
if (wasTap) {
|
|
407
|
-
this.isDragging = false;
|
|
408
|
-
this.onDraggingChange?.(false);
|
|
409
|
-
this.notify();
|
|
410
|
-
return {
|
|
411
|
-
position: this.position,
|
|
412
|
-
shouldHide: false,
|
|
413
|
-
wasTap: true
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// Calculate final position
|
|
418
|
-
const dx = event.clientX - this.dragStartMouse.x;
|
|
419
|
-
const dy = event.clientY - this.dragStartMouse.y;
|
|
420
|
-
const currentX = this.dragStartPos.x + dx;
|
|
421
|
-
const currentY = this.dragStartPos.y + dy;
|
|
422
|
-
|
|
423
|
-
// Check if should auto-hide (bubble midpoint past right edge)
|
|
424
|
-
const bubbleMidpoint = currentX + this.bubbleSize.width / 2;
|
|
425
|
-
const shouldHide = bubbleMidpoint > this.screenWidth;
|
|
426
|
-
const bounds = this.getBounds();
|
|
427
|
-
if (shouldHide) {
|
|
428
|
-
const hiddenX = this.screenWidth - this.visibleHandleWidth;
|
|
429
|
-
const clampedY = Math.max(bounds.minY, Math.min(currentY, bounds.maxY));
|
|
430
|
-
this.isHidden = true;
|
|
431
|
-
this.onHiddenChange?.(true);
|
|
432
|
-
this.isDragging = false;
|
|
433
|
-
this.onDraggingChange?.(false);
|
|
434
|
-
this.notify();
|
|
435
|
-
return {
|
|
436
|
-
position: {
|
|
437
|
-
x: hiddenX,
|
|
438
|
-
y: clampedY
|
|
439
|
-
},
|
|
440
|
-
shouldHide: true,
|
|
441
|
-
wasTap: false
|
|
442
|
-
};
|
|
443
|
-
} else {
|
|
444
|
-
// Check if pulling back from hidden
|
|
445
|
-
if (this.isHidden && currentX < this.screenWidth - this.visibleHandleWidth - 10) {
|
|
446
|
-
this.isHidden = false;
|
|
447
|
-
this.onHiddenChange?.(false);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// Clamp to visible area
|
|
451
|
-
const clampedX = Math.max(bounds.minX, Math.min(currentX, this.screenWidth - this.bubbleSize.width - this.edgePadding));
|
|
452
|
-
const clampedY = Math.max(bounds.minY, Math.min(currentY, bounds.maxY));
|
|
453
|
-
|
|
454
|
-
// Save position if visible
|
|
455
|
-
if (clampedX < this.screenWidth - this.bubbleSize.width / 2) {
|
|
456
|
-
this.savedPosition = {
|
|
457
|
-
x: clampedX,
|
|
458
|
-
y: clampedY
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
this.position = {
|
|
462
|
-
x: clampedX,
|
|
463
|
-
y: clampedY
|
|
464
|
-
};
|
|
465
|
-
this.isDragging = false;
|
|
466
|
-
this.onDraggingChange?.(false);
|
|
467
|
-
this.debouncedSavePosition(clampedX, clampedY);
|
|
468
|
-
this.notify();
|
|
469
|
-
return {
|
|
470
|
-
position: {
|
|
471
|
-
x: clampedX,
|
|
472
|
-
y: clampedY
|
|
473
|
-
},
|
|
474
|
-
shouldHide: false,
|
|
475
|
-
wasTap: false
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* Commit position after animation completes.
|
|
482
|
-
*/
|
|
483
|
-
commitPosition(pos) {
|
|
484
|
-
this.position = pos;
|
|
485
|
-
this.savePosition(pos.x, pos.y);
|
|
486
|
-
this.notify();
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// =============================
|
|
490
|
-
// Cleanup
|
|
491
|
-
// =============================
|
|
492
|
-
|
|
493
|
-
destroy() {
|
|
494
|
-
if (this.saveTimeout) {
|
|
495
|
-
clearTimeout(this.saveTimeout);
|
|
496
|
-
this.saveTimeout = null;
|
|
497
|
-
}
|
|
498
|
-
this.listeners.clear();
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
exports.FloatingToolsStore = FloatingToolsStore;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.FloatingToolsStore=void 0;var _constants=require("./constants.js");class FloatingToolsStore{isDragging=!1;isHidden=!1;dragStartPos={x:0,y:0};dragStartMouse={x:0,y:0};hasMoved=!1;savedPosition=null;saveTimeout=null;isInitialized=!1;listeners=new Set;constructor(i){this.screenWidth=i.screenWidth,this.screenHeight=i.screenHeight,this.bubbleSize=i.initialBubbleSize??{width:100,height:32},this.minPosition=i.minPosition??{x:_constants.EDGE_PADDING,y:_constants.EDGE_PADDING},this.visibleHandleWidth=i.visibleHandleWidth??_constants.VISIBLE_HANDLE_WIDTH,this.dragThreshold=i.dragThreshold??_constants.DRAG_THRESHOLD,this.edgePadding=i.edgePadding??_constants.EDGE_PADDING,this.enablePositionPersistence=i.enablePositionPersistence??!0,this.storage=i.storage,this.onPositionChange=i.onPositionChange,this.onHiddenChange=i.onHiddenChange,this.onDraggingChange=i.onDraggingChange,this.position=i.initialPosition??{x:this.screenWidth-this.bubbleSize.width-20,y:Math.max(this.minPosition.y,Math.min(100,this.screenHeight-this.bubbleSize.height-this.edgePadding))},this.stateSnapshot=this.createSnapshot()}subscribe=i=>(this.listeners.add(i),()=>this.listeners.delete(i));getSnapshot=()=>this.stateSnapshot;createSnapshot(){return{position:{...this.position},isDragging:this.isDragging,isHidden:this.isHidden,bubbleSize:{...this.bubbleSize}}}notify(){this.stateSnapshot=this.createSnapshot(),this.listeners.forEach(i=>i())}async initialize(){if(!this.isInitialized&&this.enablePositionPersistence&&this.storage){try{const[i,t]=await Promise.all([this.storage.getItem(_constants.STORAGE_KEYS.POSITION_X),this.storage.getItem(_constants.STORAGE_KEYS.POSITION_Y)]);if(null!==i&&null!==t){const s=parseFloat(i),e=parseFloat(t);if(!Number.isNaN(s)&&!Number.isNaN(e)){const i={x:s,y:e},t=this.validatePosition(i);(Math.abs(i.x-t.x)>5||Math.abs(i.y-t.y)>5)&&this.savePosition(t.x,t.y),this.position=t,t.x>=this.screenWidth-this.visibleHandleWidth-5&&(this.isHidden=!0),this.notify()}}}catch{}this.isInitialized=!0}else this.isInitialized=!0}getBounds(){return{minX:this.minPosition.x,maxX:this.screenWidth-this.visibleHandleWidth,minY:this.minPosition.y,maxY:this.screenHeight-this.bubbleSize.height-this.edgePadding}}validatePosition(i){const t=this.getBounds();return{x:Math.max(t.minX,Math.min(i.x,t.maxX)),y:Math.max(t.minY,Math.min(i.y,t.maxY))}}setPosition(i){this.position=i,this.onPositionChange?.(i),this.notify()}setBubbleSize(i){this.bubbleSize.width===i.width&&this.bubbleSize.height===i.height||(this.bubbleSize=i,this.notify())}setScreenSize(i,t){this.screenWidth=i,this.screenHeight=t;const s=this.validatePosition(this.position);s.x===this.position.x&&s.y===this.position.y||(this.position=s,this.notify())}setMinPosition(i){this.minPosition=i}async savePosition(i,t){if(this.enablePositionPersistence&&this.storage)try{await Promise.all([this.storage.setItem(_constants.STORAGE_KEYS.POSITION_X,i.toString()),this.storage.setItem(_constants.STORAGE_KEYS.POSITION_Y,t.toString())])}catch{}}debouncedSavePosition(i,t){this.saveTimeout&&clearTimeout(this.saveTimeout),this.saveTimeout=setTimeout(()=>this.savePosition(i,t),_constants.SAVE_DEBOUNCE_MS)}toggleHideShow(){const i=this.position.x>this.screenWidth-this.bubbleSize.width/2;if(this.isHidden||i){let i,t;return this.savedPosition&&this.savedPosition.x<this.screenWidth-this.bubbleSize.width/2?(i=this.savedPosition.x,t=this.savedPosition.y):(i=this.screenWidth-this.bubbleSize.width-20,t=this.position.y),this.isHidden=!1,this.onHiddenChange?.(!1),this.notify(),{targetPosition:{x:i,y:t},isHiding:!1}}{this.savedPosition={...this.position};const i=this.screenWidth-this.visibleHandleWidth;return this.isHidden=!0,this.onHiddenChange?.(!0),this.notify(),{targetPosition:{x:i,y:this.position.y},isHiding:!0}}}forceHide(){if(this.isHidden)return{targetPosition:this.position};this.savedPosition={...this.position};const i=this.screenWidth-this.visibleHandleWidth;return this.isHidden=!0,this.onHiddenChange?.(!0),this.notify(),{targetPosition:{x:i,y:this.position.y}}}forceShow(){if(!this.isHidden)return{targetPosition:this.position};let i,t;return this.savedPosition?(i=this.savedPosition.x,t=this.savedPosition.y):(i=this.screenWidth-this.bubbleSize.width-20,t=this.position.y),this.isHidden=!1,this.onHiddenChange?.(!1),this.notify(),{targetPosition:{x:i,y:t}}}handleDragStart(i){this.hasMoved=!1,this.dragStartPos={...this.position},this.dragStartMouse={x:i.clientX,y:i.clientY}}handleDragMove(i){const t=i.clientX-this.dragStartMouse.x,s=i.clientY-this.dragStartMouse.y,e=Math.abs(t)+Math.abs(s);if(!this.hasMoved&&e>this.dragThreshold&&(this.hasMoved=!0,this.isDragging=!0,this.onDraggingChange?.(!0),this.notify()),this.hasMoved){const i=this.dragStartPos.x+t,e=this.dragStartPos.y+s,n=this.getBounds(),h=Math.max(n.minX,Math.min(i,this.screenWidth-this.visibleHandleWidth+this.bubbleSize.width)),o=Math.max(n.minY,Math.min(e,n.maxY));return this.position={x:h,y:o},this.onPositionChange?.(this.position),this.notify(),{position:this.position,isDragging:!0}}return{position:this.position,isDragging:!1}}handleDragEnd(i){if(!this.hasMoved)return this.isDragging=!1,this.onDraggingChange?.(!1),this.notify(),{position:this.position,shouldHide:!1,wasTap:!0};const t=i.clientX-this.dragStartMouse.x,s=i.clientY-this.dragStartMouse.y,e=this.dragStartPos.x+t,n=this.dragStartPos.y+s,h=e+this.bubbleSize.width/2>this.screenWidth,o=this.getBounds();if(h){const i=this.screenWidth-this.visibleHandleWidth,t=Math.max(o.minY,Math.min(n,o.maxY));return this.isHidden=!0,this.onHiddenChange?.(!0),this.isDragging=!1,this.onDraggingChange?.(!1),this.notify(),{position:{x:i,y:t},shouldHide:!0,wasTap:!1}}{this.isHidden&&e<this.screenWidth-this.visibleHandleWidth-10&&(this.isHidden=!1,this.onHiddenChange?.(!1));const i=Math.max(o.minX,Math.min(e,this.screenWidth-this.bubbleSize.width-this.edgePadding)),t=Math.max(o.minY,Math.min(n,o.maxY));return i<this.screenWidth-this.bubbleSize.width/2&&(this.savedPosition={x:i,y:t}),this.position={x:i,y:t},this.isDragging=!1,this.onDraggingChange?.(!1),this.debouncedSavePosition(i,t),this.notify(),{position:{x:i,y:t},shouldHide:!1,wasTap:!1}}}commitPosition(i){this.position=i,this.savePosition(i.x,i.y),this.notify()}destroy(){this.saveTimeout&&(clearTimeout(this.saveTimeout),this.saveTimeout=null),this.listeners.clear()}}exports.FloatingToolsStore=FloatingToolsStore;
|
package/lib/commonjs/colors.js
CHANGED
|
@@ -1,54 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.floatingToolsColors = void 0;
|
|
7
|
-
exports.withAlpha = withAlpha;
|
|
8
|
-
/**
|
|
9
|
-
* Shared color palette for floating tools.
|
|
10
|
-
* Matches the gameUIColors from @buoy-gg/shared-ui.
|
|
11
|
-
*
|
|
12
|
-
* These are duplicated here to avoid requiring @buoy-gg/shared-ui
|
|
13
|
-
* as a dependency (which has React Native dependencies).
|
|
14
|
-
*
|
|
15
|
-
* TODO: Consider extracting colors to a truly platform-agnostic package
|
|
16
|
-
* that both shared-ui and floating-tools-core can depend on.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Buoy brand colors - EXACT values from web docs site dark theme
|
|
21
|
-
*/
|
|
22
|
-
const floatingToolsColors = exports.floatingToolsColors = {
|
|
23
|
-
/** Dark panel background */
|
|
24
|
-
panel: '#1A1A1A',
|
|
25
|
-
/** Muted gray for secondary elements */
|
|
26
|
-
muted: '#888888',
|
|
27
|
-
/** Primary text color */
|
|
28
|
-
secondary: '#E0E0E0',
|
|
29
|
-
/** Info/active state color (Buoy teal) */
|
|
30
|
-
info: '#20C997',
|
|
31
|
-
/** Success/admin color (Buoy teal) */
|
|
32
|
-
success: '#20C997',
|
|
33
|
-
/** Warning/optional color (Buoy orange) */
|
|
34
|
-
optional: '#FFA94D',
|
|
35
|
-
/** Error color (Buoy red) */
|
|
36
|
-
error: '#EF4444',
|
|
37
|
-
/** Primary accent color (Buoy teal) */
|
|
38
|
-
primary: '#20C997',
|
|
39
|
-
/** Color used when dragging the floating tools (Buoy teal) */
|
|
40
|
-
dragActive: '#20C997'
|
|
41
|
-
};
|
|
42
|
-
/**
|
|
43
|
-
* Get a color with optional alpha.
|
|
44
|
-
* @param color - The base color (hex)
|
|
45
|
-
* @param alpha - Alpha value as hex string (00-FF) or number (0-1)
|
|
46
|
-
*/
|
|
47
|
-
function withAlpha(color, alpha) {
|
|
48
|
-
if (typeof alpha === 'number') {
|
|
49
|
-
// Convert 0-1 to hex
|
|
50
|
-
const hex = Math.round(alpha * 255).toString(16).padStart(2, '0');
|
|
51
|
-
return `${color}${hex}`;
|
|
52
|
-
}
|
|
53
|
-
return `${color}${alpha}`;
|
|
54
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.floatingToolsColors=void 0,exports.withAlpha=withAlpha;const floatingToolsColors=exports.floatingToolsColors={panel:"#1A1A1A",muted:"#888888",secondary:"#E0E0E0",info:"#20C997",success:"#20C997",optional:"#FFA94D",error:"#EF4444",primary:"#20C997",dragActive:"#20C997"};function withAlpha(o,t){return"number"==typeof t?`${o}${Math.round(255*t).toString(16).padStart(2,"0")}`:`${o}${t}`}
|
|
@@ -1,31 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.VISIBLE_HANDLE_WIDTH = exports.STORAGE_KEYS = exports.SAVE_DEBOUNCE_MS = exports.EDGE_PADDING = exports.DRAG_THRESHOLD = exports.ANIMATION_DURATION = void 0;
|
|
7
|
-
/**
|
|
8
|
-
* Shared constants for floating tools behavior.
|
|
9
|
-
* These values ensure consistent behavior across platforms.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/** Width of the visible grip handle when bubble is hidden (pixels) */
|
|
13
|
-
const VISIBLE_HANDLE_WIDTH = exports.VISIBLE_HANDLE_WIDTH = 32;
|
|
14
|
-
|
|
15
|
-
/** Minimum movement to distinguish drag from tap (pixels) */
|
|
16
|
-
const DRAG_THRESHOLD = exports.DRAG_THRESHOLD = 5;
|
|
17
|
-
|
|
18
|
-
/** Animation duration for hide/show transitions (milliseconds) */
|
|
19
|
-
const ANIMATION_DURATION = exports.ANIMATION_DURATION = 200;
|
|
20
|
-
|
|
21
|
-
/** Padding from screen edges (pixels) */
|
|
22
|
-
const EDGE_PADDING = exports.EDGE_PADDING = 10;
|
|
23
|
-
|
|
24
|
-
/** Debounce delay for position persistence (milliseconds) */
|
|
25
|
-
const SAVE_DEBOUNCE_MS = exports.SAVE_DEBOUNCE_MS = 500;
|
|
26
|
-
|
|
27
|
-
/** Storage keys for position persistence */
|
|
28
|
-
const STORAGE_KEYS = exports.STORAGE_KEYS = {
|
|
29
|
-
POSITION_X: '@react_buoy_bubble_position_x',
|
|
30
|
-
POSITION_Y: '@react_buoy_bubble_position_y'
|
|
31
|
-
};
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.VISIBLE_HANDLE_WIDTH=exports.STORAGE_KEYS=exports.SAVE_DEBOUNCE_MS=exports.EDGE_PADDING=exports.DRAG_THRESHOLD=exports.ANIMATION_DURATION=void 0;const VISIBLE_HANDLE_WIDTH=exports.VISIBLE_HANDLE_WIDTH=32,DRAG_THRESHOLD=exports.DRAG_THRESHOLD=5,ANIMATION_DURATION=exports.ANIMATION_DURATION=200,EDGE_PADDING=exports.EDGE_PADDING=10,SAVE_DEBOUNCE_MS=exports.SAVE_DEBOUNCE_MS=500,STORAGE_KEYS=exports.STORAGE_KEYS={POSITION_X:"@react_buoy_bubble_position_x",POSITION_Y:"@react_buoy_bubble_position_y"};
|