@vite-plugin-opencode-assistant/components 1.0.25 → 1.0.27
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/es/index.d.ts +1 -1
- package/es/index.js +1 -1
- package/es/open-code-widget/composables/use-inspector.js +118 -79
- package/es/open-code-widget/composables/use-persist-state.d.ts +24 -0
- package/es/open-code-widget/composables/use-persist-state.js +59 -0
- package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble-sfc.css +1 -1
- package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.d.ts +2 -3
- package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +50 -60
- package/es/open-code-widget/src/components/Trigger.vue.d.ts +2 -5
- package/es/open-code-widget/src/components/Trigger.vue.js +10 -38
- package/es/open-code-widget/src/context.d.ts +3 -0
- package/es/open-code-widget/src/index-sfc.css +1 -1
- package/es/open-code-widget/src/index.vue.d.ts +10 -10
- package/es/open-code-widget/src/index.vue.js +143 -28
- package/lib/@vite-plugin-opencode-assistant/components.cjs.js +359 -200
- package/lib/@vite-plugin-opencode-assistant/components.es.js +360 -201
- package/lib/components.css +2 -2
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/open-code-widget/composables/use-inspector.js +118 -79
- package/lib/open-code-widget/composables/use-persist-state.d.ts +24 -0
- package/lib/open-code-widget/composables/use-persist-state.js +78 -0
- package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble-sfc.css +1 -1
- package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.d.ts +2 -3
- package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +49 -59
- package/lib/open-code-widget/src/components/Trigger.vue.d.ts +2 -5
- package/lib/open-code-widget/src/components/Trigger.vue.js +9 -37
- package/lib/open-code-widget/src/context.d.ts +3 -0
- package/lib/open-code-widget/src/index-sfc.css +1 -1
- package/lib/open-code-widget/src/index.vue.d.ts +10 -10
- package/lib/open-code-widget/src/index.vue.js +141 -26
- package/lib/web-types.json +1 -1
- package/package.json +2 -2
package/es/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import OpenCodeWidget from './open-code-widget';
|
|
2
2
|
import type { App } from 'vue';
|
|
3
|
-
declare const version = "1.0.
|
|
3
|
+
declare const version = "1.0.27";
|
|
4
4
|
declare function install(app: App<any>, options?: any): void;
|
|
5
5
|
export { install, version, OpenCodeWidget };
|
|
6
6
|
export default install;
|
package/es/index.js
CHANGED
|
@@ -202,35 +202,20 @@ function findFileInfo(element, inspector) {
|
|
|
202
202
|
return fallbackFileInfo || { file: null, line: null, column: null };
|
|
203
203
|
}
|
|
204
204
|
function getPreciseElementAtPoint(x, y, boundary) {
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
try {
|
|
214
|
-
const elements = document.elementsFromPoint(x, y);
|
|
215
|
-
for (const el of elements) {
|
|
216
|
-
if (el.closest("#vue-inspector-container")) continue;
|
|
217
|
-
if (el.closest(".opencode-widget")) continue;
|
|
218
|
-
if (el.hasAttribute("data-v-inspector-ignore")) continue;
|
|
219
|
-
if (boundary) {
|
|
220
|
-
if (boundary.contains(el) || el === boundary) {
|
|
221
|
-
element = el;
|
|
222
|
-
break;
|
|
223
|
-
}
|
|
224
|
-
} else {
|
|
225
|
-
element = el;
|
|
226
|
-
break;
|
|
205
|
+
const elements = document.elementsFromPoint(x, y);
|
|
206
|
+
for (const el of elements) {
|
|
207
|
+
if (el.closest("#vue-inspector-container")) continue;
|
|
208
|
+
if (el.closest(".opencode-widget")) continue;
|
|
209
|
+
if (el.hasAttribute("data-v-inspector-ignore")) continue;
|
|
210
|
+
if (boundary) {
|
|
211
|
+
if (boundary.contains(el) || el === boundary) {
|
|
212
|
+
return el;
|
|
227
213
|
}
|
|
214
|
+
} else {
|
|
215
|
+
return el;
|
|
228
216
|
}
|
|
229
|
-
} finally {
|
|
230
|
-
if (highlight) highlight.style.display = highlightDisplay;
|
|
231
|
-
if (tooltip) tooltip.style.display = tooltipDisplay;
|
|
232
217
|
}
|
|
233
|
-
return
|
|
218
|
+
return null;
|
|
234
219
|
}
|
|
235
220
|
function useInspector(options) {
|
|
236
221
|
const highlightVisible = ref(false);
|
|
@@ -245,67 +230,99 @@ function useInspector(options) {
|
|
|
245
230
|
const tooltipContent = ref({ description: "", fileInfo: "" });
|
|
246
231
|
const INSPECTOR_CHECK_INTERVAL = 500;
|
|
247
232
|
let inspectorCheckTimer = null;
|
|
233
|
+
let currentHighlightElement = null;
|
|
234
|
+
let currentFileInfo = { file: null, line: null, column: null };
|
|
235
|
+
let currentPrimary = "#3b82f6";
|
|
236
|
+
let currentPrimaryBg = "rgba(59, 130, 246, 0.1)";
|
|
237
|
+
let currentDescription = "";
|
|
238
|
+
let currentFileInfoText = "";
|
|
248
239
|
function handleMouseMoveCore(e) {
|
|
249
240
|
var _a, _b;
|
|
250
241
|
if (!options.selectMode.value) return;
|
|
251
242
|
const inspector = window.__VUE_INSPECTOR__;
|
|
243
|
+
const highlight = document.querySelector(".opencode-element-highlight");
|
|
244
|
+
const tooltip = document.querySelector(".opencode-element-tooltip");
|
|
245
|
+
if (highlight) highlight.style.pointerEvents = "none";
|
|
246
|
+
if (tooltip) tooltip.style.pointerEvents = "none";
|
|
252
247
|
let elementToHighlight = null;
|
|
248
|
+
let targetNode = null;
|
|
253
249
|
let fileInfo = { file: null, line: null, column: null };
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
250
|
+
try {
|
|
251
|
+
if (inspector) {
|
|
252
|
+
const result = inspector.getTargetNode(e);
|
|
253
|
+
targetNode = result.targetNode;
|
|
254
|
+
const params = result.params;
|
|
255
|
+
if (targetNode) {
|
|
256
|
+
const preciseElement = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode);
|
|
257
|
+
elementToHighlight = preciseElement || targetNode;
|
|
258
|
+
if (params && params.file) {
|
|
259
|
+
fileInfo = {
|
|
260
|
+
file: params.file,
|
|
261
|
+
line: (_a = params.line) != null ? _a : null,
|
|
262
|
+
column: (_b = params.column) != null ? _b : null
|
|
263
|
+
};
|
|
264
|
+
} else {
|
|
265
|
+
fileInfo = findFileInfo(targetNode, inspector);
|
|
266
|
+
}
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
269
|
+
if (!elementToHighlight) {
|
|
270
|
+
elementToHighlight = getPreciseElementAtPoint(e.clientX, e.clientY, null);
|
|
271
|
+
}
|
|
272
|
+
if (elementToHighlight && !fileInfo.file) {
|
|
273
|
+
fileInfo = getFileInfoFromVueInstance(elementToHighlight) || fileInfo;
|
|
274
|
+
}
|
|
275
|
+
} finally {
|
|
276
|
+
if (highlight) highlight.style.pointerEvents = "";
|
|
277
|
+
if (tooltip) tooltip.style.pointerEvents = "";
|
|
275
278
|
}
|
|
276
279
|
if (elementToHighlight) {
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
280
|
+
const elementChanged = currentHighlightElement !== elementToHighlight;
|
|
281
|
+
if (elementChanged) {
|
|
282
|
+
currentHighlightElement = elementToHighlight;
|
|
283
|
+
currentFileInfo = fileInfo;
|
|
284
|
+
const widget = document.querySelector(".opencode-widget");
|
|
285
|
+
if (widget) {
|
|
286
|
+
const style = getComputedStyle(widget);
|
|
287
|
+
currentPrimary = style.getPropertyValue("--oc-primary").trim() || currentPrimary;
|
|
288
|
+
currentPrimaryBg = style.getPropertyValue("--oc-primary-bg").trim() || currentPrimaryBg;
|
|
289
|
+
}
|
|
290
|
+
currentDescription = getElementDescription(elementToHighlight);
|
|
291
|
+
} else if (!currentFileInfo.file && fileInfo.file) {
|
|
292
|
+
currentFileInfo = fileInfo;
|
|
285
293
|
}
|
|
286
|
-
|
|
287
|
-
highlightStyle.value = {
|
|
288
|
-
top: `${rect.top}px`,
|
|
289
|
-
left: `${rect.left}px`,
|
|
290
|
-
width: `${rect.width}px`,
|
|
291
|
-
height: `${rect.height}px`,
|
|
292
|
-
border: `2px solid ${primary}`,
|
|
293
|
-
background: primaryBg
|
|
294
|
-
};
|
|
295
|
-
const description = getElementDescription(elementToHighlight);
|
|
296
|
-
const fileName = fileInfo.file ? fileInfo.file.split("/").pop() : "";
|
|
294
|
+
const fileName = currentFileInfo.file ? currentFileInfo.file.split("/").pop() : "";
|
|
297
295
|
let lineInfo = "";
|
|
298
|
-
if (
|
|
299
|
-
lineInfo = `:${
|
|
300
|
-
if (
|
|
301
|
-
lineInfo += `:${
|
|
296
|
+
if (currentFileInfo.line) {
|
|
297
|
+
lineInfo = `:${currentFileInfo.line}`;
|
|
298
|
+
if (currentFileInfo.column) {
|
|
299
|
+
lineInfo += `:${currentFileInfo.column}`;
|
|
302
300
|
}
|
|
303
301
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
302
|
+
const newFileInfoText = fileName ? `${fileName}${lineInfo}` : "";
|
|
303
|
+
const fileInfoChanged = currentFileInfoText !== newFileInfoText;
|
|
304
|
+
if (elementChanged || fileInfoChanged) {
|
|
305
|
+
currentFileInfoText = newFileInfoText;
|
|
306
|
+
tooltipContent.value = {
|
|
307
|
+
description: currentDescription,
|
|
308
|
+
fileInfo: currentFileInfoText
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const rect = elementToHighlight.getBoundingClientRect();
|
|
312
|
+
const newTop = `${rect.top}px`;
|
|
313
|
+
const newLeft = `${rect.left}px`;
|
|
314
|
+
const newWidth = `${rect.width}px`;
|
|
315
|
+
const newHeight = `${rect.height}px`;
|
|
316
|
+
if (highlightStyle.value.top !== newTop || highlightStyle.value.left !== newLeft || highlightStyle.value.width !== newWidth || highlightStyle.value.height !== newHeight) {
|
|
317
|
+
highlightStyle.value = {
|
|
318
|
+
top: newTop,
|
|
319
|
+
left: newLeft,
|
|
320
|
+
width: newWidth,
|
|
321
|
+
height: newHeight,
|
|
322
|
+
border: `2px solid ${currentPrimary}`,
|
|
323
|
+
background: currentPrimaryBg
|
|
324
|
+
};
|
|
325
|
+
}
|
|
309
326
|
const tooltipHeight = 50;
|
|
310
327
|
const tooltipWidth = 200;
|
|
311
328
|
let tooltipTop = rect.top - tooltipHeight - 8;
|
|
@@ -316,13 +333,31 @@ function useInspector(options) {
|
|
|
316
333
|
if (tooltipLeft + tooltipWidth > window.innerWidth - 10) {
|
|
317
334
|
tooltipLeft = window.innerWidth - tooltipWidth - 10;
|
|
318
335
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
336
|
+
const newTooltipTop = `${tooltipTop}px`;
|
|
337
|
+
const newTooltipLeft = `${tooltipLeft}px`;
|
|
338
|
+
if (tooltipStyle.value.top !== newTooltipTop || tooltipStyle.value.left !== newTooltipLeft) {
|
|
339
|
+
tooltipStyle.value = {
|
|
340
|
+
top: newTooltipTop,
|
|
341
|
+
left: newTooltipLeft
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
if (!highlightVisible.value) {
|
|
345
|
+
highlightVisible.value = true;
|
|
346
|
+
}
|
|
347
|
+
if (!tooltipVisible.value) {
|
|
348
|
+
tooltipVisible.value = true;
|
|
349
|
+
}
|
|
323
350
|
} else {
|
|
324
|
-
|
|
325
|
-
|
|
351
|
+
currentHighlightElement = null;
|
|
352
|
+
currentDescription = "";
|
|
353
|
+
currentFileInfoText = "";
|
|
354
|
+
currentFileInfo = { file: null, line: null, column: null };
|
|
355
|
+
if (highlightVisible.value) {
|
|
356
|
+
highlightVisible.value = false;
|
|
357
|
+
}
|
|
358
|
+
if (tooltipVisible.value) {
|
|
359
|
+
tooltipVisible.value = false;
|
|
360
|
+
}
|
|
326
361
|
}
|
|
327
362
|
}
|
|
328
363
|
const handleMouseMove = throttle(handleMouseMoveCore, 16);
|
|
@@ -394,6 +429,10 @@ function useInspector(options) {
|
|
|
394
429
|
}
|
|
395
430
|
document.removeEventListener("mousemove", handleMouseMove);
|
|
396
431
|
document.removeEventListener("keydown", handleKeydown, true);
|
|
432
|
+
currentHighlightElement = null;
|
|
433
|
+
currentDescription = "";
|
|
434
|
+
currentFileInfoText = "";
|
|
435
|
+
currentFileInfo = { file: null, line: null, column: null };
|
|
397
436
|
highlightVisible.value = false;
|
|
398
437
|
tooltipVisible.value = false;
|
|
399
438
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
import type { FloatingBubbleOffset } from "../src/components/FloatingBubble/types";
|
|
3
|
+
import type { OpenCodeWidgetTheme } from "../src/types";
|
|
4
|
+
export interface WidgetPersistState {
|
|
5
|
+
open: boolean;
|
|
6
|
+
minimized: boolean;
|
|
7
|
+
promptDockVisible: boolean;
|
|
8
|
+
bubbleOffset?: FloatingBubbleOffset;
|
|
9
|
+
theme: OpenCodeWidgetTheme;
|
|
10
|
+
sessionListCollapsed: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface UsePersistStateOptions {
|
|
13
|
+
open: Ref<boolean>;
|
|
14
|
+
minimized: Ref<boolean>;
|
|
15
|
+
promptDockVisible: Ref<boolean>;
|
|
16
|
+
bubbleOffset: Ref<FloatingBubbleOffset | undefined>;
|
|
17
|
+
theme: Ref<OpenCodeWidgetTheme>;
|
|
18
|
+
sessionListCollapsed: Ref<boolean>;
|
|
19
|
+
onRestore?: (state: Partial<WidgetPersistState>) => void;
|
|
20
|
+
}
|
|
21
|
+
export declare function usePersistState(options: UsePersistStateOptions): {
|
|
22
|
+
restoreState: () => Partial<WidgetPersistState> | null;
|
|
23
|
+
persistState: () => void;
|
|
24
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { watch, onMounted } from "vue";
|
|
2
|
+
const STORAGE_KEY = "opencode-widget-state";
|
|
3
|
+
function loadState() {
|
|
4
|
+
if (typeof window === "undefined") return null;
|
|
5
|
+
try {
|
|
6
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
7
|
+
if (stored) {
|
|
8
|
+
return JSON.parse(stored);
|
|
9
|
+
}
|
|
10
|
+
} catch (e) {
|
|
11
|
+
console.warn("[OpenCodeWidget] Failed to load persisted state:", e);
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
function saveState(state) {
|
|
16
|
+
if (typeof window === "undefined") return;
|
|
17
|
+
try {
|
|
18
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
|
|
19
|
+
} catch (e) {
|
|
20
|
+
console.warn("[OpenCodeWidget] Failed to save state:", e);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function usePersistState(options) {
|
|
24
|
+
const restoreState = () => {
|
|
25
|
+
const saved = loadState();
|
|
26
|
+
if (options.onRestore) {
|
|
27
|
+
options.onRestore(saved || {});
|
|
28
|
+
}
|
|
29
|
+
return saved;
|
|
30
|
+
};
|
|
31
|
+
const getCurrentState = () => ({
|
|
32
|
+
open: options.open.value,
|
|
33
|
+
minimized: options.minimized.value,
|
|
34
|
+
promptDockVisible: options.promptDockVisible.value,
|
|
35
|
+
bubbleOffset: options.bubbleOffset.value,
|
|
36
|
+
theme: options.theme.value,
|
|
37
|
+
sessionListCollapsed: options.sessionListCollapsed.value
|
|
38
|
+
});
|
|
39
|
+
const persistState = () => {
|
|
40
|
+
saveState(getCurrentState());
|
|
41
|
+
};
|
|
42
|
+
onMounted(() => {
|
|
43
|
+
restoreState();
|
|
44
|
+
watch(
|
|
45
|
+
[options.open, options.minimized, options.promptDockVisible, options.bubbleOffset, options.theme, options.sessionListCollapsed],
|
|
46
|
+
() => {
|
|
47
|
+
persistState();
|
|
48
|
+
},
|
|
49
|
+
{ deep: true }
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
restoreState,
|
|
54
|
+
persistState
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
usePersistState
|
|
59
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.floating-bubble{position:fixed;top:0;left:0;z-index:999999;cursor:grab;-webkit-user-select:none;-moz-user-select:none;user-select:none;touch-action:none;will-change:transform}.floating-bubble:active{cursor:grabbing}
|
|
1
|
+
.floating-bubble{position:fixed;top:0;left:0;z-index:999999;cursor:grab;-webkit-user-select:none;-moz-user-select:none;user-select:none;touch-action:none;will-change:transform}.floating-bubble:active{cursor:grabbing}body.floating-bubble-dragging *{pointer-events:none!important}body.floating-bubble-dragging .floating-bubble,body.floating-bubble-dragging .floating-bubble *{pointer-events:auto!important}
|
|
@@ -11,20 +11,19 @@ type __VLS_Slots = {} & {
|
|
|
11
11
|
default?: (props: typeof __VLS_5) => any;
|
|
12
12
|
};
|
|
13
13
|
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {
|
|
14
|
-
isOnRightSide: import("vue").ComputedRef<boolean>;
|
|
15
14
|
offset: import("vue").ComputedRef<{
|
|
16
15
|
x: number;
|
|
17
16
|
y: number;
|
|
18
17
|
}>;
|
|
19
18
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
20
|
-
click: (event: MouseEvent) => any;
|
|
21
19
|
"update:offset": (value: FloatingBubbleOffset) => any;
|
|
20
|
+
click: (event: MouseEvent) => any;
|
|
22
21
|
"offset-change": (offset: FloatingBubbleOffset) => any;
|
|
23
22
|
"drag-start": () => any;
|
|
24
23
|
"drag-end": () => any;
|
|
25
24
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
26
|
-
onClick?: ((event: MouseEvent) => any) | undefined;
|
|
27
25
|
"onUpdate:offset"?: ((value: FloatingBubbleOffset) => any) | undefined;
|
|
26
|
+
onClick?: ((event: MouseEvent) => any) | undefined;
|
|
28
27
|
"onOffset-change"?: ((offset: FloatingBubbleOffset) => any) | undefined;
|
|
29
28
|
"onDrag-start"?: (() => any) | undefined;
|
|
30
29
|
"onDrag-end"?: (() => any) | undefined;
|
|
@@ -36,26 +36,12 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
36
36
|
const props = __props;
|
|
37
37
|
const emit = __emit;
|
|
38
38
|
const rootRef = ref(null);
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
height: 0
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
if (typeof window !== "undefined") {
|
|
49
|
-
return {
|
|
50
|
-
x: window.innerWidth - 42 - 24,
|
|
51
|
-
y: window.innerHeight - 42 - 24,
|
|
52
|
-
width: 0,
|
|
53
|
-
height: 0
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
return { x: 0, y: 0, width: 0, height: 0 };
|
|
57
|
-
};
|
|
58
|
-
const state = ref(getInitialState());
|
|
39
|
+
const state = ref({
|
|
40
|
+
x: 0,
|
|
41
|
+
y: 0,
|
|
42
|
+
width: 0,
|
|
43
|
+
height: 0
|
|
44
|
+
});
|
|
59
45
|
const isObject = (val) => val !== null && typeof val === "object";
|
|
60
46
|
const gapX = computed(
|
|
61
47
|
() => isObject(props.gap) ? props.gap.x : props.gap
|
|
@@ -71,6 +57,27 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
71
57
|
bottom: windowHeight.value - state.value.height - gapY.value,
|
|
72
58
|
left: gapX.value
|
|
73
59
|
}));
|
|
60
|
+
const closest = (arr, target) => {
|
|
61
|
+
return arr.reduce(
|
|
62
|
+
(pre, cur) => Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
const applyMagnetic = () => {
|
|
66
|
+
if (props.magnetic === "x") {
|
|
67
|
+
const nextX = closest(
|
|
68
|
+
[boundary.value.left, boundary.value.right],
|
|
69
|
+
state.value.x
|
|
70
|
+
);
|
|
71
|
+
state.value.x = nextX;
|
|
72
|
+
}
|
|
73
|
+
if (props.magnetic === "y") {
|
|
74
|
+
const nextY = closest(
|
|
75
|
+
[boundary.value.top, boundary.value.bottom],
|
|
76
|
+
state.value.y
|
|
77
|
+
);
|
|
78
|
+
state.value.y = nextY;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
74
81
|
const dragging = ref(false);
|
|
75
82
|
const initialized = ref(false);
|
|
76
83
|
const rootStyle = computed(() => {
|
|
@@ -78,20 +85,16 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
78
85
|
const x = `${state.value.x}px`;
|
|
79
86
|
const y = `${state.value.y}px`;
|
|
80
87
|
style.transform = `translate3d(${x}, ${y}, 0)`;
|
|
81
|
-
if (dragging.value) {
|
|
88
|
+
if (dragging.value || !initialized.value) {
|
|
82
89
|
style.transition = "none";
|
|
83
90
|
} else {
|
|
84
91
|
style.transition = "transform 0.3s ease";
|
|
85
92
|
}
|
|
86
93
|
return style;
|
|
87
94
|
});
|
|
88
|
-
const show = ref(true);
|
|
89
95
|
const updateState = () => {
|
|
90
|
-
if (!
|
|
96
|
+
if (!rootRef.value || typeof window === "undefined") return;
|
|
91
97
|
const rect = rootRef.value.getBoundingClientRect();
|
|
92
|
-
if (rect.width === 0 || rect.height === 0) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
98
|
const { offset } = props;
|
|
96
99
|
let x = offset ? offset.x : windowWidth.value - rect.width - gapX.value;
|
|
97
100
|
let y = offset ? offset.y : windowHeight.value - rect.height - gapY.value;
|
|
@@ -101,12 +104,22 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
101
104
|
if (x > maxX) x = maxX;
|
|
102
105
|
if (y < gapY.value) y = gapY.value;
|
|
103
106
|
if (y > maxY) y = maxY;
|
|
107
|
+
const oldX = state.value.x;
|
|
108
|
+
const oldY = state.value.y;
|
|
104
109
|
state.value = {
|
|
105
110
|
x,
|
|
106
111
|
y,
|
|
107
112
|
width: rect.width,
|
|
108
113
|
height: rect.height
|
|
109
114
|
};
|
|
115
|
+
if (!dragging.value) {
|
|
116
|
+
applyMagnetic();
|
|
117
|
+
if (state.value.x !== oldX || state.value.y !== oldY) {
|
|
118
|
+
const offset2 = { x: state.value.x, y: state.value.y };
|
|
119
|
+
emit("update:offset", offset2);
|
|
120
|
+
emit("offset-change", offset2);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
110
123
|
};
|
|
111
124
|
const touch = {
|
|
112
125
|
startX: ref(0),
|
|
@@ -145,6 +158,7 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
145
158
|
dragging.value = true;
|
|
146
159
|
prevX = state.value.x;
|
|
147
160
|
prevY = state.value.y;
|
|
161
|
+
document.body.classList.add("floating-bubble-dragging");
|
|
148
162
|
if (!("touches" in e)) {
|
|
149
163
|
window.addEventListener("mousemove", onTouchMove, { passive: false });
|
|
150
164
|
window.addEventListener("mouseup", onTouchEnd);
|
|
@@ -177,32 +191,15 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
177
191
|
emit("update:offset", offset);
|
|
178
192
|
}
|
|
179
193
|
};
|
|
180
|
-
const closest = (arr, target) => {
|
|
181
|
-
return arr.reduce(
|
|
182
|
-
(pre, cur) => Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur
|
|
183
|
-
);
|
|
184
|
-
};
|
|
185
194
|
const onTouchEnd = (e) => {
|
|
186
195
|
dragging.value = false;
|
|
196
|
+
document.body.classList.remove("floating-bubble-dragging");
|
|
187
197
|
if (e && !("touches" in e) && e.type === "mouseup") {
|
|
188
198
|
window.removeEventListener("mousemove", onTouchMove);
|
|
189
199
|
window.removeEventListener("mouseup", onTouchEnd);
|
|
190
200
|
}
|
|
191
201
|
requestAnimationFrame(() => {
|
|
192
|
-
|
|
193
|
-
const nextX = closest(
|
|
194
|
-
[boundary.value.left, boundary.value.right],
|
|
195
|
-
state.value.x
|
|
196
|
-
);
|
|
197
|
-
state.value.x = nextX;
|
|
198
|
-
}
|
|
199
|
-
if (props.magnetic === "y") {
|
|
200
|
-
const nextY = closest(
|
|
201
|
-
[boundary.value.top, boundary.value.bottom],
|
|
202
|
-
state.value.y
|
|
203
|
-
);
|
|
204
|
-
state.value.y = nextY;
|
|
205
|
-
}
|
|
202
|
+
applyMagnetic();
|
|
206
203
|
if (!touch.isTap.value) {
|
|
207
204
|
emit("drag-end");
|
|
208
205
|
const offset = { x: state.value.x, y: state.value.y };
|
|
@@ -227,11 +224,9 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
227
224
|
}
|
|
228
225
|
};
|
|
229
226
|
onMounted(() => {
|
|
227
|
+
updateState();
|
|
230
228
|
requestAnimationFrame(() => {
|
|
231
|
-
|
|
232
|
-
requestAnimationFrame(() => {
|
|
233
|
-
initialized.value = true;
|
|
234
|
-
});
|
|
229
|
+
initialized.value = true;
|
|
235
230
|
});
|
|
236
231
|
if (typeof window !== "undefined") {
|
|
237
232
|
window.addEventListener("resize", handleResize);
|
|
@@ -243,6 +238,7 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
243
238
|
}
|
|
244
239
|
});
|
|
245
240
|
onUnmounted(() => {
|
|
241
|
+
document.body.classList.remove("floating-bubble-dragging");
|
|
246
242
|
if (typeof window !== "undefined") {
|
|
247
243
|
window.removeEventListener("resize", handleResize);
|
|
248
244
|
window.removeEventListener("mousemove", onTouchMove);
|
|
@@ -257,14 +253,10 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
257
253
|
updateState,
|
|
258
254
|
{ deep: true }
|
|
259
255
|
);
|
|
260
|
-
const isOnRightSide = computed(() => {
|
|
261
|
-
return state.value.x > windowWidth.value / 2;
|
|
262
|
-
});
|
|
263
256
|
__expose({
|
|
264
|
-
isOnRightSide,
|
|
265
257
|
offset: computed(() => ({ x: state.value.x, y: state.value.y }))
|
|
266
258
|
});
|
|
267
|
-
const __returned__ = { props, emit, rootRef,
|
|
259
|
+
const __returned__ = { props, emit, rootRef, state, isObject, gapX, gapY, windowWidth, windowHeight, boundary, closest, applyMagnetic, dragging, initialized, rootStyle, updateState, touch, get prevX() {
|
|
268
260
|
return prevX;
|
|
269
261
|
}, set prevX(v) {
|
|
270
262
|
prevX = v;
|
|
@@ -272,15 +264,15 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent(__spreadProps(__spreadValue
|
|
|
272
264
|
return prevY;
|
|
273
265
|
}, set prevY(v) {
|
|
274
266
|
prevY = v;
|
|
275
|
-
}, onTouchStart, onTouchMove,
|
|
267
|
+
}, onTouchStart, onTouchMove, onTouchEnd, onClick, handleResize };
|
|
276
268
|
Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
|
|
277
269
|
return __returned__;
|
|
278
270
|
}
|
|
279
271
|
}));
|
|
280
|
-
import { renderSlot as _renderSlot,
|
|
272
|
+
import { renderSlot as _renderSlot, normalizeStyle as _normalizeStyle, createElementVNode as _createElementVNode, Teleport as _Teleport, openBlock as _openBlock, createBlock as _createBlock } from "vue";
|
|
281
273
|
function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
|
|
282
274
|
return _openBlock(), _createBlock(_Teleport, { to: $props.teleport }, [
|
|
283
|
-
|
|
275
|
+
_createElementVNode(
|
|
284
276
|
"div",
|
|
285
277
|
{
|
|
286
278
|
ref: "rootRef",
|
|
@@ -297,9 +289,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
297
289
|
],
|
|
298
290
|
36
|
|
299
291
|
/* STYLE, NEED_HYDRATION */
|
|
300
|
-
)
|
|
301
|
-
[_vShow, $setup.show && $setup.initialized]
|
|
302
|
-
])
|
|
292
|
+
)
|
|
303
293
|
], 8, ["to"]);
|
|
304
294
|
}
|
|
305
295
|
__vue_sfc__.render = __vue_render__;
|
|
@@ -4,20 +4,17 @@ type __VLS_Slots = {} & {
|
|
|
4
4
|
default?: (props: typeof __VLS_13) => any;
|
|
5
5
|
};
|
|
6
6
|
declare const __VLS_component: import("vue").DefineComponent<{}, {
|
|
7
|
-
isOnRightSide: import("vue").ComputedRef<boolean>;
|
|
8
7
|
offset: import("vue").Ref<{
|
|
9
8
|
x: number;
|
|
10
9
|
y: number;
|
|
11
|
-
}, FloatingBubbleOffset | {
|
|
10
|
+
} | undefined, FloatingBubbleOffset | {
|
|
12
11
|
x: number;
|
|
13
12
|
y: number;
|
|
14
|
-
}>;
|
|
13
|
+
} | undefined>;
|
|
15
14
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
16
|
-
"offset-change": (offset: FloatingBubbleOffset) => any;
|
|
17
15
|
"drag-start": () => any;
|
|
18
16
|
"drag-end": () => any;
|
|
19
17
|
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
20
|
-
"onOffset-change"?: ((offset: FloatingBubbleOffset) => any) | undefined;
|
|
21
18
|
"onDrag-start"?: (() => any) | undefined;
|
|
22
19
|
"onDrag-end"?: (() => any) | undefined;
|
|
23
20
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|