@vite-plugin-opencode-assistant/components 1.0.23 → 1.0.25

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 (41) hide show
  1. package/es/index.d.ts +1 -1
  2. package/es/index.js +1 -1
  3. package/es/open-code-widget/composables/use-widget.d.ts +0 -1
  4. package/es/open-code-widget/composables/use-widget.js +0 -1
  5. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble-sfc.css +1 -0
  6. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.d.ts +44 -0
  7. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +309 -0
  8. package/es/open-code-widget/src/components/FloatingBubble/index.d.ts +3 -0
  9. package/es/open-code-widget/src/components/FloatingBubble/index.js +5 -0
  10. package/es/open-code-widget/src/components/FloatingBubble/types.d.ts +24 -0
  11. package/es/open-code-widget/src/components/FloatingBubble/types.js +0 -0
  12. package/es/open-code-widget/src/components/Trigger-sfc.css +1 -1
  13. package/es/open-code-widget/src/components/Trigger.vue.d.ts +21 -3
  14. package/es/open-code-widget/src/components/Trigger.vue.js +127 -48
  15. package/es/open-code-widget/src/index-sfc.css +1 -1
  16. package/es/open-code-widget/src/index.vue.d.ts +10 -11
  17. package/es/open-code-widget/src/index.vue.js +82 -17
  18. package/es/open-code-widget/src/types.d.ts +1 -2
  19. package/lib/@vite-plugin-opencode-assistant/components.cjs.js +562 -99
  20. package/lib/@vite-plugin-opencode-assistant/components.es.js +558 -95
  21. package/lib/components.css +3 -2
  22. package/lib/index.d.ts +1 -1
  23. package/lib/index.js +1 -1
  24. package/lib/open-code-widget/composables/use-widget.d.ts +0 -1
  25. package/lib/open-code-widget/composables/use-widget.js +0 -1
  26. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble-sfc.css +1 -0
  27. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.d.ts +44 -0
  28. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +326 -0
  29. package/lib/open-code-widget/src/components/FloatingBubble/index.d.ts +3 -0
  30. package/lib/open-code-widget/src/components/FloatingBubble/index.js +35 -0
  31. package/lib/open-code-widget/src/components/FloatingBubble/types.d.ts +24 -0
  32. package/lib/open-code-widget/src/components/FloatingBubble/types.js +15 -0
  33. package/lib/open-code-widget/src/components/Trigger-sfc.css +1 -1
  34. package/lib/open-code-widget/src/components/Trigger.vue.d.ts +21 -3
  35. package/lib/open-code-widget/src/components/Trigger.vue.js +137 -48
  36. package/lib/open-code-widget/src/index-sfc.css +1 -1
  37. package/lib/open-code-widget/src/index.vue.d.ts +10 -11
  38. package/lib/open-code-widget/src/index.vue.js +80 -15
  39. package/lib/open-code-widget/src/types.d.ts +1 -2
  40. package/lib/web-types.json +1 -1
  41. package/package.json +2 -2
@@ -13,24 +13,24 @@ function useOpenCodeWidgetContext() {
13
13
  }
14
14
  //#endregion
15
15
  //#region es/open-code-widget/src/components/Frame.vue.js
16
- var __defProp$1 = Object.defineProperty;
17
- var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
18
- var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
19
- var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
20
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, {
16
+ var __defProp$2 = Object.defineProperty;
17
+ var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
18
+ var __hasOwnProp$2 = Object.prototype.hasOwnProperty;
19
+ var __propIsEnum$2 = Object.prototype.propertyIsEnumerable;
20
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, {
21
21
  enumerable: true,
22
22
  configurable: true,
23
23
  writable: true,
24
24
  value
25
25
  }) : obj[key] = value;
26
- var __spreadValues$1 = (a, b) => {
27
- for (var prop in b || (b = {})) if (__hasOwnProp$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]);
28
- if (__getOwnPropSymbols$1) {
29
- for (var prop of __getOwnPropSymbols$1(b)) if (__propIsEnum$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]);
26
+ var __spreadValues$2 = (a, b) => {
27
+ for (var prop in b || (b = {})) if (__hasOwnProp$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]);
28
+ if (__getOwnPropSymbols$2) {
29
+ for (var prop of __getOwnPropSymbols$2(b)) if (__propIsEnum$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]);
30
30
  }
31
31
  return a;
32
32
  };
33
- var __vue_sfc__$6 = /* @__PURE__ */ defineComponent({
33
+ var __vue_sfc__$7 = /* @__PURE__ */ defineComponent({
34
34
  __name: "Frame",
35
35
  setup(__props, { expose: __expose }) {
36
36
  const iframeRef = ref(null);
@@ -38,7 +38,7 @@ var __vue_sfc__$6 = /* @__PURE__ */ defineComponent({
38
38
  function sendMessageToIframe(type, data) {
39
39
  var _a;
40
40
  if (!((_a = iframeRef.value) == null ? void 0 : _a.contentWindow)) return;
41
- iframeRef.value.contentWindow.postMessage(__spreadValues$1({ type }, data), "*");
41
+ iframeRef.value.contentWindow.postMessage(__spreadValues$2({ type }, data), "*");
42
42
  }
43
43
  onMounted(() => {
44
44
  if (iframeRef.value) iframeRef.value.addEventListener("load", () => {
@@ -68,7 +68,7 @@ var __vue_sfc__$6 = /* @__PURE__ */ defineComponent({
68
68
  var _hoisted_1$6 = { class: "opencode-iframe-container" };
69
69
  var _hoisted_2$4 = { class: "opencode-empty-state-text" };
70
70
  var _hoisted_3$4 = ["src"];
71
- function __vue_render__$6(_ctx, _cache, $props, $setup, $data, $options) {
71
+ function __vue_render__$7(_ctx, _cache, $props, $setup, $data, $options) {
72
72
  return openBlock(), createElementBlock("div", _hoisted_1$6, [
73
73
  createElementVNode("div", { class: normalizeClass(["opencode-empty-state-overlay", { visible: $setup.showEmptyState }]) }, [renderSlot(_ctx.$slots, "empty-state", {}, () => [
74
74
  _cache[1] || (_cache[1] = createElementVNode("div", { class: "opencode-empty-state-icon" }, [createElementVNode("svg", {
@@ -102,11 +102,11 @@ function __vue_render__$6(_ctx, _cache, $props, $setup, $data, $options) {
102
102
  }, null, 8, _hoisted_3$4)])
103
103
  ]);
104
104
  }
105
- __vue_sfc__$6.render = __vue_render__$6;
106
- var Frame_vue_default = __vue_sfc__$6;
105
+ __vue_sfc__$7.render = __vue_render__$7;
106
+ var Frame_vue_default = __vue_sfc__$7;
107
107
  //#endregion
108
108
  //#region es/open-code-widget/src/components/Header.vue.js
109
- var __vue_sfc__$5 = /* @__PURE__ */ defineComponent({
109
+ var __vue_sfc__$6 = /* @__PURE__ */ defineComponent({
110
110
  __name: "Header",
111
111
  setup(__props, { expose: __expose }) {
112
112
  __expose();
@@ -220,7 +220,7 @@ var _hoisted_14 = {
220
220
  "stroke-width": "2",
221
221
  "aria-hidden": "true"
222
222
  };
223
- function __vue_render__$5(_ctx, _cache, $props, $setup, $data, $options) {
223
+ function __vue_render__$6(_ctx, _cache, $props, $setup, $data, $options) {
224
224
  return openBlock(), createElementBlock("div", _hoisted_1$5, [
225
225
  createElementVNode("div", _hoisted_2$3, [
226
226
  createElementVNode("button", {
@@ -314,11 +314,11 @@ function __vue_render__$5(_ctx, _cache, $props, $setup, $data, $options) {
314
314
  ])
315
315
  ]);
316
316
  }
317
- __vue_sfc__$5.render = __vue_render__$5;
318
- var Header_vue_default = __vue_sfc__$5;
317
+ __vue_sfc__$6.render = __vue_render__$6;
318
+ var Header_vue_default = __vue_sfc__$6;
319
319
  //#endregion
320
320
  //#region es/open-code-widget/src/components/SelectHint.vue.js
321
- var __vue_sfc__$4 = /* @__PURE__ */ defineComponent({
321
+ var __vue_sfc__$5 = /* @__PURE__ */ defineComponent({
322
322
  __name: "SelectHint",
323
323
  setup(__props, { expose: __expose }) {
324
324
  __expose();
@@ -335,14 +335,14 @@ var __vue_sfc__$4 = /* @__PURE__ */ defineComponent({
335
335
  }
336
336
  });
337
337
  var _hoisted_1$4 = { class: "opencode-hint-shortcut" };
338
- function __vue_render__$4(_ctx, _cache, $props, $setup, $data, $options) {
338
+ function __vue_render__$5(_ctx, _cache, $props, $setup, $data, $options) {
339
339
  return openBlock(), createElementBlock("div", { class: normalizeClass(["opencode-select-mode-hint", { visible: $setup.visible }]) }, [_cache[0] || (_cache[0] = createElementVNode("span", null, "🎯 选择模式已开启 - 点击元素进行选择", -1)), createElementVNode("span", _hoisted_1$4, toDisplayString($setup.shortcutLabel), 1)], 2);
340
340
  }
341
- __vue_sfc__$4.render = __vue_render__$4;
342
- var SelectHint_vue_default = __vue_sfc__$4;
341
+ __vue_sfc__$5.render = __vue_render__$5;
342
+ var SelectHint_vue_default = __vue_sfc__$5;
343
343
  //#endregion
344
344
  //#region es/open-code-widget/src/components/SelectedNodes.vue.js
345
- var __vue_sfc__$3 = /* @__PURE__ */ defineComponent({
345
+ var __vue_sfc__$4 = /* @__PURE__ */ defineComponent({
346
346
  __name: "SelectedNodes",
347
347
  setup(__props, { expose: __expose }) {
348
348
  __expose();
@@ -371,7 +371,7 @@ var _hoisted_3$2 = { class: "opencode-node-content" };
371
371
  var _hoisted_4$2 = { class: "opencode-node-text" };
372
372
  var _hoisted_5$2 = { class: "opencode-node-file" };
373
373
  var _hoisted_6$2 = ["aria-label", "onClick"];
374
- function __vue_render__$3(_ctx, _cache, $props, $setup, $data, $options) {
374
+ function __vue_render__$4(_ctx, _cache, $props, $setup, $data, $options) {
375
375
  return openBlock(), createElementBlock("div", { class: normalizeClass(["opencode-right-toolbar", { collapsed: $setup.items.length === 0 }]) }, [
376
376
  _cache[1] || (_cache[1] = createElementVNode("div", { class: "opencode-selected-nodes-header" }, [createElementVNode("div", { class: "opencode-selected-nodes-title" }, "已选节点"), createElementVNode("div", { class: "opencode-selected-nodes-desc" }, "选中的节点会在对话时一起发送给助手")], -1)),
377
377
  createElementVNode("div", _hoisted_1$3, [(openBlock(true), createElementBlock(Fragment, null, renderList($setup.items, (item, index) => {
@@ -400,11 +400,11 @@ function __vue_render__$3(_ctx, _cache, $props, $setup, $data, $options) {
400
400
  }, " 一键清空 ")) : createCommentVNode("v-if", true)
401
401
  ], 2);
402
402
  }
403
- __vue_sfc__$3.render = __vue_render__$3;
404
- var SelectedNodes_vue_default = __vue_sfc__$3;
403
+ __vue_sfc__$4.render = __vue_render__$4;
404
+ var SelectedNodes_vue_default = __vue_sfc__$4;
405
405
  //#endregion
406
406
  //#region es/open-code-widget/src/components/SessionList.vue.js
407
- var __vue_sfc__$2 = /* @__PURE__ */ defineComponent({
407
+ var __vue_sfc__$3 = /* @__PURE__ */ defineComponent({
408
408
  __name: "SessionList",
409
409
  setup(__props, { expose: __expose }) {
410
410
  __expose();
@@ -469,7 +469,7 @@ var _hoisted_6$1 = { class: "opencode-session-header" };
469
469
  var _hoisted_7$1 = { class: "opencode-session-title" };
470
470
  var _hoisted_8$1 = ["aria-label", "onClick"];
471
471
  var _hoisted_9$1 = { class: "opencode-session-meta" };
472
- function __vue_render__$2(_ctx, _cache, $props, $setup, $data, $options) {
472
+ function __vue_render__$3(_ctx, _cache, $props, $setup, $data, $options) {
473
473
  return openBlock(), createElementBlock("div", { class: normalizeClass(["opencode-session-list", { collapsed: $setup.collapsed }]) }, [
474
474
  createCommentVNode(" Header "),
475
475
  !$setup.showSkeleton ? (openBlock(), createElementBlock("div", _hoisted_1$2, [_cache[1] || (_cache[1] = createElementVNode("span", { id: "opencode-session-list-title" }, "会话列表", -1)), createElementVNode("button", {
@@ -501,21 +501,396 @@ function __vue_render__$2(_ctx, _cache, $props, $setup, $data, $options) {
501
501
  }), 128)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [createCommentVNode(" Empty State "), renderSlot(_ctx.$slots, "empty")], 64))])], 2112))
502
502
  ], 2);
503
503
  }
504
+ __vue_sfc__$3.render = __vue_render__$3;
505
+ var SessionList_vue_default = __vue_sfc__$3;
506
+ //#endregion
507
+ //#region es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js
508
+ var __defProp$1 = Object.defineProperty;
509
+ var __defProps$1 = Object.defineProperties;
510
+ var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
511
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
512
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
513
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
514
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, {
515
+ enumerable: true,
516
+ configurable: true,
517
+ writable: true,
518
+ value
519
+ }) : obj[key] = value;
520
+ var __spreadValues$1 = (a, b) => {
521
+ for (var prop in b || (b = {})) if (__hasOwnProp$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]);
522
+ if (__getOwnPropSymbols$1) {
523
+ for (var prop of __getOwnPropSymbols$1(b)) if (__propIsEnum$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]);
524
+ }
525
+ return a;
526
+ };
527
+ var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
528
+ var __vue_sfc__$2 = /* @__PURE__ */ defineComponent(__spreadProps$1(__spreadValues$1({}, { name: "FloatingBubble" }), {
529
+ __name: "FloatingBubble",
530
+ props: {
531
+ offset: {
532
+ type: Object,
533
+ required: false,
534
+ default: void 0
535
+ },
536
+ axis: {
537
+ type: String,
538
+ required: false,
539
+ default: "xy"
540
+ },
541
+ magnetic: {
542
+ type: String,
543
+ required: false,
544
+ default: void 0
545
+ },
546
+ gap: {
547
+ type: [Number, Object],
548
+ required: false,
549
+ default: 24
550
+ },
551
+ teleport: {
552
+ type: null,
553
+ required: false,
554
+ default: "body"
555
+ }
556
+ },
557
+ emits: [
558
+ "update:offset",
559
+ "click",
560
+ "offset-change",
561
+ "drag-start",
562
+ "drag-end"
563
+ ],
564
+ setup(__props, { expose: __expose, emit: __emit }) {
565
+ const props = __props;
566
+ const emit = __emit;
567
+ const rootRef = ref(null);
568
+ const getInitialState = () => {
569
+ if (props.offset) return {
570
+ x: props.offset.x,
571
+ y: props.offset.y,
572
+ width: 0,
573
+ height: 0
574
+ };
575
+ if (typeof window !== "undefined") return {
576
+ x: window.innerWidth - 42 - 24,
577
+ y: window.innerHeight - 42 - 24,
578
+ width: 0,
579
+ height: 0
580
+ };
581
+ return {
582
+ x: 0,
583
+ y: 0,
584
+ width: 0,
585
+ height: 0
586
+ };
587
+ };
588
+ const state = ref(getInitialState());
589
+ const isObject = (val) => val !== null && typeof val === "object";
590
+ const gapX = computed(() => isObject(props.gap) ? props.gap.x : props.gap);
591
+ const gapY = computed(() => isObject(props.gap) ? props.gap.y : props.gap);
592
+ const windowWidth = ref(typeof window !== "undefined" ? window.innerWidth : 0);
593
+ const windowHeight = ref(typeof window !== "undefined" ? window.innerHeight : 0);
594
+ const boundary = computed(() => ({
595
+ top: gapY.value,
596
+ right: windowWidth.value - state.value.width - gapX.value,
597
+ bottom: windowHeight.value - state.value.height - gapY.value,
598
+ left: gapX.value
599
+ }));
600
+ const dragging = ref(false);
601
+ const initialized = ref(false);
602
+ const rootStyle = computed(() => {
603
+ const style = {};
604
+ style.transform = `translate3d(${`${state.value.x}px`}, ${`${state.value.y}px`}, 0)`;
605
+ if (dragging.value) style.transition = "none";
606
+ else style.transition = "transform 0.3s ease";
607
+ return style;
608
+ });
609
+ const show = ref(true);
610
+ const updateState = () => {
611
+ if (!show.value || !rootRef.value || typeof window === "undefined") return;
612
+ const rect = rootRef.value.getBoundingClientRect();
613
+ if (rect.width === 0 || rect.height === 0) return;
614
+ const { offset } = props;
615
+ let x = offset ? offset.x : windowWidth.value - rect.width - gapX.value;
616
+ let y = offset ? offset.y : windowHeight.value - rect.height - gapY.value;
617
+ const maxX = windowWidth.value - rect.width - gapX.value;
618
+ const maxY = windowHeight.value - rect.height - gapY.value;
619
+ if (x < gapX.value) x = gapX.value;
620
+ if (x > maxX) x = maxX;
621
+ if (y < gapY.value) y = gapY.value;
622
+ if (y > maxY) y = maxY;
623
+ state.value = {
624
+ x,
625
+ y,
626
+ width: rect.width,
627
+ height: rect.height
628
+ };
629
+ };
630
+ const touch = {
631
+ startX: ref(0),
632
+ startY: ref(0),
633
+ deltaX: ref(0),
634
+ deltaY: ref(0),
635
+ offsetX: ref(0),
636
+ offsetY: ref(0),
637
+ isTap: ref(true),
638
+ start(e) {
639
+ this.startX.value = "touches" in e ? e.touches[0].clientX : e.clientX;
640
+ this.startY.value = "touches" in e ? e.touches[0].clientY : e.clientY;
641
+ this.deltaX.value = 0;
642
+ this.deltaY.value = 0;
643
+ this.offsetX.value = 0;
644
+ this.offsetY.value = 0;
645
+ this.isTap.value = true;
646
+ },
647
+ move(e) {
648
+ const clientX = "touches" in e ? e.touches[0].clientX : e.clientX;
649
+ const clientY = "touches" in e ? e.touches[0].clientY : e.clientY;
650
+ this.deltaX.value = clientX - this.startX.value;
651
+ this.deltaY.value = clientY - this.startY.value;
652
+ this.offsetX.value = Math.abs(this.deltaX.value);
653
+ this.offsetY.value = Math.abs(this.deltaY.value);
654
+ const TAP_OFFSET = 5;
655
+ if (this.isTap.value && (this.offsetX.value > TAP_OFFSET || this.offsetY.value > TAP_OFFSET)) this.isTap.value = false;
656
+ }
657
+ };
658
+ let prevX = 0;
659
+ let prevY = 0;
660
+ const onTouchStart = (e) => {
661
+ touch.start(e);
662
+ dragging.value = true;
663
+ prevX = state.value.x;
664
+ prevY = state.value.y;
665
+ if (!("touches" in e)) {
666
+ window.addEventListener("mousemove", onTouchMove, { passive: false });
667
+ window.addEventListener("mouseup", onTouchEnd);
668
+ }
669
+ };
670
+ const onTouchMove = (e) => {
671
+ if (e.cancelable) e.preventDefault();
672
+ const wasTap = touch.isTap.value;
673
+ touch.move(e);
674
+ if (wasTap && !touch.isTap.value) emit("drag-start");
675
+ if (props.axis === "lock") return;
676
+ if (!touch.isTap.value) {
677
+ if (props.axis === "x" || props.axis === "xy") {
678
+ let nextX = prevX + touch.deltaX.value;
679
+ if (nextX < boundary.value.left) nextX = boundary.value.left;
680
+ if (nextX > boundary.value.right) nextX = boundary.value.right;
681
+ state.value.x = nextX;
682
+ }
683
+ if (props.axis === "y" || props.axis === "xy") {
684
+ let nextY = prevY + touch.deltaY.value;
685
+ if (nextY < boundary.value.top) nextY = boundary.value.top;
686
+ if (nextY > boundary.value.bottom) nextY = boundary.value.bottom;
687
+ state.value.y = nextY;
688
+ }
689
+ emit("update:offset", {
690
+ x: state.value.x,
691
+ y: state.value.y
692
+ });
693
+ }
694
+ };
695
+ const closest = (arr, target) => {
696
+ return arr.reduce((pre, cur) => Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur);
697
+ };
698
+ const onTouchEnd = (e) => {
699
+ dragging.value = false;
700
+ if (e && !("touches" in e) && e.type === "mouseup") {
701
+ window.removeEventListener("mousemove", onTouchMove);
702
+ window.removeEventListener("mouseup", onTouchEnd);
703
+ }
704
+ requestAnimationFrame(() => {
705
+ if (props.magnetic === "x") {
706
+ const nextX = closest([boundary.value.left, boundary.value.right], state.value.x);
707
+ state.value.x = nextX;
708
+ }
709
+ if (props.magnetic === "y") {
710
+ const nextY = closest([boundary.value.top, boundary.value.bottom], state.value.y);
711
+ state.value.y = nextY;
712
+ }
713
+ if (!touch.isTap.value) {
714
+ emit("drag-end");
715
+ const offset = {
716
+ x: state.value.x,
717
+ y: state.value.y
718
+ };
719
+ emit("update:offset", offset);
720
+ if (prevX !== offset.x || prevY !== offset.y) emit("offset-change", offset);
721
+ }
722
+ });
723
+ };
724
+ const onClick = (e) => {
725
+ if (touch.isTap.value) emit("click", e);
726
+ else e.stopPropagation();
727
+ };
728
+ const handleResize = () => {
729
+ if (typeof window !== "undefined") {
730
+ windowWidth.value = window.innerWidth;
731
+ windowHeight.value = window.innerHeight;
732
+ }
733
+ };
734
+ onMounted(() => {
735
+ requestAnimationFrame(() => {
736
+ updateState();
737
+ requestAnimationFrame(() => {
738
+ initialized.value = true;
739
+ });
740
+ });
741
+ if (typeof window !== "undefined") window.addEventListener("resize", handleResize);
742
+ if (rootRef.value) rootRef.value.addEventListener("touchmove", onTouchMove, { passive: false });
743
+ });
744
+ onUnmounted(() => {
745
+ if (typeof window !== "undefined") {
746
+ window.removeEventListener("resize", handleResize);
747
+ window.removeEventListener("mousemove", onTouchMove);
748
+ window.removeEventListener("mouseup", onTouchEnd);
749
+ }
750
+ if (rootRef.value) rootRef.value.removeEventListener("touchmove", onTouchMove);
751
+ });
752
+ watch([
753
+ windowWidth,
754
+ windowHeight,
755
+ gapX,
756
+ gapY,
757
+ () => props.offset
758
+ ], updateState, { deep: true });
759
+ const isOnRightSide = computed(() => {
760
+ return state.value.x > windowWidth.value / 2;
761
+ });
762
+ __expose({
763
+ isOnRightSide,
764
+ offset: computed(() => ({
765
+ x: state.value.x,
766
+ y: state.value.y
767
+ }))
768
+ });
769
+ const __returned__ = {
770
+ props,
771
+ emit,
772
+ rootRef,
773
+ getInitialState,
774
+ state,
775
+ isObject,
776
+ gapX,
777
+ gapY,
778
+ windowWidth,
779
+ windowHeight,
780
+ boundary,
781
+ dragging,
782
+ initialized,
783
+ rootStyle,
784
+ show,
785
+ updateState,
786
+ touch,
787
+ get prevX() {
788
+ return prevX;
789
+ },
790
+ set prevX(v) {
791
+ prevX = v;
792
+ },
793
+ get prevY() {
794
+ return prevY;
795
+ },
796
+ set prevY(v) {
797
+ prevY = v;
798
+ },
799
+ onTouchStart,
800
+ onTouchMove,
801
+ closest,
802
+ onTouchEnd,
803
+ onClick,
804
+ handleResize,
805
+ isOnRightSide
806
+ };
807
+ Object.defineProperty(__returned__, "__isScriptSetup", {
808
+ enumerable: false,
809
+ value: true
810
+ });
811
+ return __returned__;
812
+ }
813
+ }));
814
+ function __vue_render__$2(_ctx, _cache, $props, $setup, $data, $options) {
815
+ return openBlock(), createBlock(Teleport, { to: $props.teleport }, [withDirectives(createElementVNode("div", {
816
+ ref: "rootRef",
817
+ class: "floating-bubble",
818
+ style: normalizeStyle($setup.rootStyle),
819
+ onTouchstartPassive: $setup.onTouchStart,
820
+ onTouchend: $setup.onTouchEnd,
821
+ onTouchcancel: $setup.onTouchEnd,
822
+ onMousedown: $setup.onTouchStart,
823
+ onClickCapture: $setup.onClick
824
+ }, [renderSlot(_ctx.$slots, "default")], 36), [[vShow, $setup.show && $setup.initialized]])], 8, ["to"]);
825
+ }
504
826
  __vue_sfc__$2.render = __vue_render__$2;
505
- var SessionList_vue_default = __vue_sfc__$2;
827
+ var FloatingBubble_vue_default = __vue_sfc__$2;
506
828
  //#endregion
507
829
  //#region es/open-code-widget/src/components/Trigger.vue.js
830
+ var STORAGE_KEY = "opencode-bubble-offset";
508
831
  var __vue_sfc__$1 = /* @__PURE__ */ defineComponent({
509
832
  __name: "Trigger",
510
- setup(__props, { expose: __expose }) {
511
- __expose();
512
- const { buttonActive: active, open, hotkeyLabel, thinking, handleToggle } = useOpenCodeWidgetContext();
833
+ emits: [
834
+ "offset-change",
835
+ "drag-start",
836
+ "drag-end"
837
+ ],
838
+ setup(__props, { expose: __expose, emit: __emit }) {
839
+ const { buttonActive: active, open, hotkeyLabel, thinking, resolvedTheme, handleToggle } = useOpenCodeWidgetContext();
840
+ const loadOffset = () => {
841
+ try {
842
+ const saved = localStorage.getItem(STORAGE_KEY);
843
+ if (saved) {
844
+ const parsed = JSON.parse(saved);
845
+ if (parsed && (parsed.x !== 0 || parsed.y !== 0)) return parsed;
846
+ }
847
+ } catch (e) {}
848
+ return {
849
+ x: 0,
850
+ y: 0
851
+ };
852
+ };
853
+ const offset = ref(loadOffset());
854
+ const emit = __emit;
855
+ const saveOffset = (value) => {
856
+ try {
857
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
858
+ } catch (e) {}
859
+ };
860
+ const handleOffsetChange = (value) => {
861
+ offset.value = value;
862
+ saveOffset(value);
863
+ emit("offset-change", value);
864
+ };
865
+ const bubbleRef = ref(null);
866
+ const isOnRightSide = computed(() => {
867
+ if (typeof window === "undefined") return true;
868
+ const centerX = window.innerWidth / 2;
869
+ return offset.value.x > centerX;
870
+ });
871
+ onMounted(() => {
872
+ if (offset.value.x !== 0 || offset.value.y !== 0) emit("offset-change", offset.value);
873
+ });
874
+ __expose({
875
+ isOnRightSide,
876
+ offset
877
+ });
513
878
  const __returned__ = {
514
879
  active,
515
880
  open,
516
881
  hotkeyLabel,
517
882
  thinking,
518
- handleToggle
883
+ resolvedTheme,
884
+ handleToggle,
885
+ STORAGE_KEY,
886
+ loadOffset,
887
+ offset,
888
+ emit,
889
+ saveOffset,
890
+ handleOffsetChange,
891
+ bubbleRef,
892
+ isOnRightSide,
893
+ FloatingBubble: FloatingBubble_vue_default
519
894
  };
520
895
  Object.defineProperty(__returned__, "__isScriptSetup", {
521
896
  enumerable: false,
@@ -526,43 +901,70 @@ var __vue_sfc__$1 = /* @__PURE__ */ defineComponent({
526
901
  });
527
902
  var _hoisted_1$1 = ["aria-expanded", "title"];
528
903
  function __vue_render__$1(_ctx, _cache, $props, $setup, $data, $options) {
529
- return openBlock(), createElementBlock("button", {
530
- class: normalizeClass(["opencode-button", {
531
- active: $setup.active,
532
- thinking: $setup.thinking
533
- }]),
534
- type: "button",
535
- "aria-expanded": $setup.open,
536
- "aria-label": "打开 AI 助手",
537
- title: `AI \u52A9\u624B (${$setup.hotkeyLabel})`,
538
- onClick: _cache[0] || (_cache[0] = (...args) => $setup.handleToggle && $setup.handleToggle(...args))
539
- }, [renderSlot(_ctx.$slots, "default", {}, () => [_cache[1] || (_cache[1] = createElementVNode("svg", {
540
- t: "1775402599580",
541
- class: "icon",
542
- viewBox: "0 0 1024 1024",
543
- version: "1.1",
544
- xmlns: "http://www.w3.org/2000/svg",
545
- "p-id": "5390",
546
- "xmlns:xlink": "http://www.w3.org/1999/xlink",
547
- width: "100%",
548
- height: "100%"
549
- }, [
550
- createElementVNode("path", {
551
- d: "M512 981.33H85.34c-15.85 0-30.38-8.77-37.77-22.81a42.624 42.624 0 0 1 2.6-44.02L135 791.08C75.25 710.5 42.67 612.6 42.67 512 42.67 253.21 253.21 42.67 512 42.67S981.34 253.21 981.34 512 770.8 981.33 512 981.33zM166.44 896H512c211.73 0 384-172.27 384-384S723.73 128 512 128 128 300.27 128 512c0 91.29 32.83 179.9 92.46 249.46 12.58 14.69 13.73 36 2.77 51.94L166.44 896z",
552
- fill: "white",
553
- "p-id": "5391"
554
- }),
555
- createElementVNode("path", {
556
- d: "M384 448m-64 0a64 64 0 1 0 128 0 64 64 0 1 0 -128 0Z",
557
- fill: "white",
558
- "p-id": "5392"
559
- }),
560
- createElementVNode("path", {
561
- d: "M640 448m-64 0a64 64 0 1 0 128 0 64 64 0 1 0 -128 0Z",
562
- fill: "white",
563
- "p-id": "5393"
564
- })
565
- ], -1))])], 10, _hoisted_1$1);
904
+ return openBlock(), createBlock($setup["FloatingBubble"], {
905
+ ref: "bubbleRef",
906
+ offset: $setup.offset,
907
+ "onUpdate:offset": _cache[0] || (_cache[0] = ($event) => $setup.offset = $event),
908
+ axis: "xy",
909
+ magnetic: "x",
910
+ gap: 24,
911
+ onClick: $setup.handleToggle,
912
+ onOffsetChange: $setup.handleOffsetChange,
913
+ onDragStart: _cache[1] || (_cache[1] = ($event) => $setup.emit("drag-start")),
914
+ onDragEnd: _cache[2] || (_cache[2] = ($event) => $setup.emit("drag-end"))
915
+ }, {
916
+ default: withCtx(() => [createElementVNode("button", {
917
+ class: normalizeClass(["opencode-button", {
918
+ active: $setup.active,
919
+ thinking: $setup.thinking,
920
+ "opencode-theme-dark": $setup.resolvedTheme === "dark"
921
+ }]),
922
+ type: "button",
923
+ "aria-expanded": $setup.open,
924
+ "aria-label": "打开 AI 助手",
925
+ title: `AI \u52A9\u624B (${$setup.hotkeyLabel})`
926
+ }, [renderSlot(_ctx.$slots, "default", {}, () => [_cache[3] || (_cache[3] = createElementVNode("svg", {
927
+ t: "1775402599580",
928
+ class: "icon",
929
+ viewBox: "0 0 1024 1024",
930
+ version: "1.1",
931
+ xmlns: "http://www.w3.org/2000/svg",
932
+ "p-id": "5390",
933
+ "xmlns:xlink": "http://www.w3.org/1999/xlink",
934
+ width: "100%",
935
+ height: "100%"
936
+ }, [
937
+ createElementVNode("defs", null, [createElementVNode("linearGradient", {
938
+ id: "opencode-logo-gradient",
939
+ x1: "0%",
940
+ y1: "0%",
941
+ x2: "100%",
942
+ y2: "100%"
943
+ }, [createElementVNode("stop", {
944
+ offset: "0%",
945
+ style: { "stop-color": "#667eea" }
946
+ }), createElementVNode("stop", {
947
+ offset: "100%",
948
+ style: { "stop-color": "#764ba2" }
949
+ })])]),
950
+ createElementVNode("path", {
951
+ d: "M512 981.33H85.34c-15.85 0-30.38-8.77-37.77-22.81a42.624 42.624 0 0 1 2.6-44.02L135 791.08C75.25 710.5 42.67 612.6 42.67 512 42.67 253.21 253.21 42.67 512 42.67S981.34 253.21 981.34 512 770.8 981.33 512 981.33zM166.44 896H512c211.73 0 384-172.27 384-384S723.73 128 512 128 128 300.27 128 512c0 91.29 32.83 179.9 92.46 249.46 12.58 14.69 13.73 36 2.77 51.94L166.44 896z",
952
+ fill: "url(#opencode-logo-gradient)",
953
+ "p-id": "5391"
954
+ }),
955
+ createElementVNode("path", {
956
+ d: "M384 448m-64 0a64 64 0 1 0 128 0 64 64 0 1 0 -128 0Z",
957
+ fill: "url(#opencode-logo-gradient)",
958
+ "p-id": "5392"
959
+ }),
960
+ createElementVNode("path", {
961
+ d: "M640 448m-64 0a64 64 0 1 0 128 0 64 64 0 1 0 -128 0Z",
962
+ fill: "url(#opencode-logo-gradient)",
963
+ "p-id": "5393"
964
+ })
965
+ ], -1))])], 10, _hoisted_1$1)]),
966
+ _: 3
967
+ }, 8, ["offset", "onClick"]);
566
968
  }
567
969
  __vue_sfc__$1.render = __vue_render__$1;
568
970
  var Trigger_vue_default = __vue_sfc__$1;
@@ -775,11 +1177,7 @@ function useWidget(options) {
775
1177
  if (options.theme.value === "auto") return systemTheme.value;
776
1178
  return options.theme.value;
777
1179
  });
778
- const containerClasses = computed(() => [
779
- "opencode-widget",
780
- options.position.value,
781
- `opencode-theme-${resolvedTheme.value}`
782
- ]);
1180
+ const containerClasses = computed(() => ["opencode-widget", `opencode-theme-${resolvedTheme.value}`]);
783
1181
  const buttonActive = computed(() => !!(options.open.value || options.selectMode.value));
784
1182
  const iframeSource = computed(() => options.iframeSrc.value || "about:blank");
785
1183
  const sessionListTitle = computed(() => options.sessionListCollapsed.value ? "展开会话列表" : "折叠会话列表");
@@ -1228,11 +1626,6 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
1228
1626
  var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({}, { name: "OpencodeWidget" }), {
1229
1627
  __name: "index",
1230
1628
  props: {
1231
- position: {
1232
- type: String,
1233
- required: false,
1234
- default: "bottom-right"
1235
- },
1236
1629
  open: {
1237
1630
  type: Boolean,
1238
1631
  required: false,
@@ -1403,6 +1796,7 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1403
1796
  if (dialogResolve) dialogResolve(false);
1404
1797
  };
1405
1798
  const frameRef = ref(null);
1799
+ const triggerRef = ref(null);
1406
1800
  const sendMessageToIframe = (type, data) => {
1407
1801
  var _a;
1408
1802
  (_a = frameRef.value) == null || _a.sendMessageToIframe(type, data);
@@ -1422,7 +1816,6 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1422
1816
  localSessionListCollapsed.value = val;
1423
1817
  });
1424
1818
  const { buttonActive, containerClasses, iframeSource, sessionListTitle, resolvedTheme, handleClose, handleEmptyAction, handleToggle, handleToggleSessionList, handleToggleTheme } = useWidget({
1425
- position: toRef(props, "position"),
1426
1819
  theme: toRef(props, "theme"),
1427
1820
  open: toRef(props, "open"),
1428
1821
  selectMode: toRef(props, "selectMode"),
@@ -1503,6 +1896,59 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1503
1896
  promptDockVisible.value = !promptDockVisible.value;
1504
1897
  sendMessageToIframe("prompt-dock-visibility-change", { visible: promptDockVisible.value });
1505
1898
  };
1899
+ const bubbleOffset = ref({
1900
+ x: 0,
1901
+ y: 0
1902
+ });
1903
+ const isBubbleOnRightSide = computed(() => {
1904
+ if (typeof window === "undefined") return true;
1905
+ const centerX = window.innerWidth / 2;
1906
+ return bubbleOffset.value.x > centerX;
1907
+ });
1908
+ const chatPositionStyle = computed(() => {
1909
+ if (typeof window === "undefined") return {};
1910
+ const windowWidth = window.innerWidth;
1911
+ const windowHeight = window.innerHeight;
1912
+ const chatWidth = minimized.value ? 300 : 700;
1913
+ const chatHeight = minimized.value ? 300 : Math.min(windowHeight * .86, windowHeight - 40);
1914
+ const gap = 24;
1915
+ const bubbleSize = 44;
1916
+ const screenMargin = 20;
1917
+ const style = {};
1918
+ if (isBubbleOnRightSide.value) {
1919
+ let rightPos = windowWidth - bubbleOffset.value.x + gap;
1920
+ const maxRight = windowWidth - chatWidth - screenMargin;
1921
+ if (rightPos > maxRight) rightPos = maxRight;
1922
+ style.right = `${rightPos}px`;
1923
+ style.left = "auto";
1924
+ } else {
1925
+ let leftPos = bubbleOffset.value.x + bubbleSize + gap;
1926
+ const maxLeft = windowWidth - chatWidth - screenMargin;
1927
+ if (leftPos > maxLeft) leftPos = maxLeft;
1928
+ style.left = `${leftPos}px`;
1929
+ style.right = "auto";
1930
+ }
1931
+ let bottomPos = windowHeight - bubbleOffset.value.y - bubbleSize;
1932
+ const maxBottom = windowHeight - chatHeight - screenMargin;
1933
+ if (bottomPos > maxBottom) bottomPos = maxBottom;
1934
+ if (bottomPos < screenMargin) bottomPos = screenMargin;
1935
+ style.bottom = `${bottomPos}px`;
1936
+ return style;
1937
+ });
1938
+ const handleBubbleOffsetChange = (offset) => {
1939
+ bubbleOffset.value = offset;
1940
+ };
1941
+ const isDragging = ref(false);
1942
+ let wasOpenBeforeDrag = false;
1943
+ const handleDragStart = () => {
1944
+ isDragging.value = true;
1945
+ wasOpenBeforeDrag = props.open;
1946
+ if (props.open) emit("update:open", false);
1947
+ };
1948
+ const handleDragEnd = () => {
1949
+ isDragging.value = false;
1950
+ if (wasOpenBeforeDrag) emit("update:open", true);
1951
+ };
1506
1952
  provideOpenCodeWidgetContext({
1507
1953
  theme: toRef(props, "theme"),
1508
1954
  resolvedTheme,
@@ -1574,6 +2020,7 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1574
2020
  handleDialogConfirm,
1575
2021
  handleDialogCancel,
1576
2022
  frameRef,
2023
+ triggerRef,
1577
2024
  sendMessageToIframe,
1578
2025
  handleFrameLoaded,
1579
2026
  localSessionListCollapsed,
@@ -1607,6 +2054,19 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1607
2054
  tooltipContent,
1608
2055
  handleToggleMinimize,
1609
2056
  handleTogglePromptDock,
2057
+ bubbleOffset,
2058
+ isBubbleOnRightSide,
2059
+ chatPositionStyle,
2060
+ handleBubbleOffsetChange,
2061
+ isDragging,
2062
+ get wasOpenBeforeDrag() {
2063
+ return wasOpenBeforeDrag;
2064
+ },
2065
+ set wasOpenBeforeDrag(v) {
2066
+ wasOpenBeforeDrag = v;
2067
+ },
2068
+ handleDragStart,
2069
+ handleDragEnd,
1610
2070
  Frame: Frame_vue_default,
1611
2071
  Header: Header_vue_default,
1612
2072
  SelectHint: SelectHint_vue_default,
@@ -1647,16 +2107,24 @@ var _hoisted_9 = {
1647
2107
  };
1648
2108
  function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
1649
2109
  return openBlock(), createElementBlock("div", { class: normalizeClass($setup.containerClasses) }, [
1650
- createVNode($setup["Trigger"], null, createSlots({ _: 2 }, [$setup.slots["button-icon"] ? {
2110
+ createVNode($setup["Trigger"], {
2111
+ ref: "triggerRef",
2112
+ onOffsetChange: $setup.handleBubbleOffsetChange,
2113
+ onDragStart: $setup.handleDragStart,
2114
+ onDragEnd: $setup.handleDragEnd
2115
+ }, createSlots({ _: 2 }, [$setup.slots["button-icon"] ? {
1651
2116
  name: "default",
1652
2117
  fn: withCtx(() => [renderSlot(_ctx.$slots, "button-icon")]),
1653
2118
  key: "0"
1654
- } : void 0]), 1024),
1655
- createCommentVNode(" <SelectedBubbles v-if=\"bubbleVisible\" /> "),
1656
- withDirectives(createElementVNode("div", { class: normalizeClass(["opencode-chat", {
1657
- open: $props.open,
1658
- minimized: $setup.minimized
1659
- }]) }, [
2119
+ } : void 0]), 1536),
2120
+ withDirectives(createElementVNode("div", {
2121
+ class: normalizeClass(["opencode-chat", {
2122
+ open: $props.open,
2123
+ minimized: $setup.minimized,
2124
+ dragging: $setup.isDragging
2125
+ }]),
2126
+ style: normalizeStyle($setup.chatPositionStyle)
2127
+ }, [
1660
2128
  createVNode($setup["Header"], null, createSlots({ _: 2 }, [
1661
2129
  $setup.slots["session-toggle-icon"] ? {
1662
2130
  name: "session-toggle-icon",
@@ -1674,7 +2142,6 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
1674
2142
  key: "2"
1675
2143
  } : void 0
1676
2144
  ]), 1024),
1677
- createCommentVNode(" Notification "),
1678
2145
  $setup.notificationVisible && $setup.notificationMode === "widget" ? (openBlock(), createElementBlock("div", _hoisted_1, toDisplayString($setup.notificationMessage), 1)) : createCommentVNode("v-if", true),
1679
2146
  createElementVNode("div", _hoisted_2, [
1680
2147
  createVNode($setup["SessionList"], null, {
@@ -1705,19 +2172,16 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
1705
2172
  ]), 1536),
1706
2173
  createVNode($setup["SelectedNodes"])
1707
2174
  ])
1708
- ], 2), [[vShow, !$props.selectMode]]),
2175
+ ], 6), [[vShow, !$props.selectMode]]),
1709
2176
  createVNode($setup["SelectHint"]),
1710
- createCommentVNode(" Inspector Highlight "),
1711
2177
  withDirectives(createElementVNode("div", {
1712
2178
  class: "opencode-element-highlight",
1713
2179
  style: normalizeStyle(__spreadValues({ display: $setup.highlightVisible ? "block" : "none" }, $setup.highlightStyle))
1714
2180
  }, null, 4), [[vShow, $setup.highlightVisible]]),
1715
- createCommentVNode(" Inspector Tooltip "),
1716
2181
  withDirectives(createElementVNode("div", {
1717
2182
  class: "opencode-element-tooltip",
1718
2183
  style: normalizeStyle(__spreadValues({ display: $setup.tooltipVisible ? "block" : "none" }, $setup.tooltipStyle))
1719
2184
  }, [createElementVNode("div", _hoisted_3, toDisplayString($setup.tooltipContent.description), 1), createElementVNode("div", _hoisted_4, toDisplayString($setup.tooltipContent.fileInfo), 1)], 4), [[vShow, $setup.tooltipVisible]]),
1720
- createCommentVNode(" Dialog "),
1721
2185
  $setup.dialogVisible ? (openBlock(), createElementBlock("div", _hoisted_5, [createElementVNode("div", _hoisted_6, [createElementVNode("div", _hoisted_7, [createElementVNode("div", _hoisted_8, toDisplayString($setup.dialogMessage), 1)]), createElementVNode("div", { class: "opencode-dialog-actions" }, [createElementVNode("button", {
1722
2186
  class: "opencode-dialog-btn cancel",
1723
2187
  onClick: $setup.handleDialogCancel
@@ -1725,7 +2189,6 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
1725
2189
  class: "opencode-dialog-btn confirm",
1726
2190
  onClick: $setup.handleDialogConfirm
1727
2191
  }, "确认")])])])) : createCommentVNode("v-if", true),
1728
- createCommentVNode(" Page-level Notification "),
1729
2192
  (openBlock(), createBlock(Teleport, { to: "body" }, [$setup.notificationVisible && $setup.notificationMode === "page" ? (openBlock(), createElementBlock("div", _hoisted_9, toDisplayString($setup.notificationMessage), 1)) : createCommentVNode("v-if", true)]))
1730
2193
  ], 2);
1731
2194
  }
@@ -1735,7 +2198,7 @@ __vue_sfc__.render = __vue_render__;
1735
2198
  var open_code_widget_default = __vue_sfc__;
1736
2199
  //#endregion
1737
2200
  //#region es/index.js
1738
- var version = "1.0.23";
2201
+ var version = "1.0.25";
1739
2202
  function install(app, options) {
1740
2203
  [open_code_widget_default].forEach((item) => {
1741
2204
  if (item.install) app.use(item, options);