@vite-plugin-opencode-assistant/components 1.0.26 → 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.
Files changed (33) 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-inspector.js +118 -79
  4. package/es/open-code-widget/composables/use-persist-state.d.ts +24 -0
  5. package/es/open-code-widget/composables/use-persist-state.js +59 -0
  6. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble-sfc.css +1 -1
  7. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.d.ts +2 -2
  8. package/es/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +37 -21
  9. package/es/open-code-widget/src/components/Trigger.vue.d.ts +0 -2
  10. package/es/open-code-widget/src/components/Trigger.vue.js +10 -27
  11. package/es/open-code-widget/src/context.d.ts +3 -0
  12. package/es/open-code-widget/src/index-sfc.css +1 -1
  13. package/es/open-code-widget/src/index.vue.d.ts +10 -10
  14. package/es/open-code-widget/src/index.vue.js +107 -29
  15. package/lib/@vite-plugin-opencode-assistant/components.cjs.js +304 -140
  16. package/lib/@vite-plugin-opencode-assistant/components.es.js +305 -141
  17. package/lib/components.css +2 -2
  18. package/lib/index.d.ts +1 -1
  19. package/lib/index.js +1 -1
  20. package/lib/open-code-widget/composables/use-inspector.js +118 -79
  21. package/lib/open-code-widget/composables/use-persist-state.d.ts +24 -0
  22. package/lib/open-code-widget/composables/use-persist-state.js +78 -0
  23. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble-sfc.css +1 -1
  24. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.d.ts +2 -2
  25. package/lib/open-code-widget/src/components/FloatingBubble/FloatingBubble.vue.js +37 -21
  26. package/lib/open-code-widget/src/components/Trigger.vue.d.ts +0 -2
  27. package/lib/open-code-widget/src/components/Trigger.vue.js +10 -27
  28. package/lib/open-code-widget/src/context.d.ts +3 -0
  29. package/lib/open-code-widget/src/index-sfc.css +1 -1
  30. package/lib/open-code-widget/src/index.vue.d.ts +10 -10
  31. package/lib/open-code-widget/src/index.vue.js +106 -28
  32. package/lib/web-types.json +1 -1
  33. package/package.json +2 -2
@@ -609,6 +609,19 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps$1(__s
609
609
  bottom: windowHeight.value - state.value.height - gapY.value,
610
610
  left: gapX.value
611
611
  }));
612
+ const closest = (arr, target) => {
613
+ return arr.reduce((pre, cur) => Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur);
614
+ };
615
+ const applyMagnetic = () => {
616
+ if (props.magnetic === "x") {
617
+ const nextX = closest([boundary.value.left, boundary.value.right], state.value.x);
618
+ state.value.x = nextX;
619
+ }
620
+ if (props.magnetic === "y") {
621
+ const nextY = closest([boundary.value.top, boundary.value.bottom], state.value.y);
622
+ state.value.y = nextY;
623
+ }
624
+ };
612
625
  const dragging = (0, vue.ref)(false);
613
626
  const initialized = (0, vue.ref)(false);
614
627
  const rootStyle = (0, vue.computed)(() => {
@@ -630,12 +643,25 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps$1(__s
630
643
  if (x > maxX) x = maxX;
631
644
  if (y < gapY.value) y = gapY.value;
632
645
  if (y > maxY) y = maxY;
646
+ const oldX = state.value.x;
647
+ const oldY = state.value.y;
633
648
  state.value = {
634
649
  x,
635
650
  y,
636
651
  width: rect.width,
637
652
  height: rect.height
638
653
  };
654
+ if (!dragging.value) {
655
+ applyMagnetic();
656
+ if (state.value.x !== oldX || state.value.y !== oldY) {
657
+ const offset2 = {
658
+ x: state.value.x,
659
+ y: state.value.y
660
+ };
661
+ emit("update:offset", offset2);
662
+ emit("offset-change", offset2);
663
+ }
664
+ }
639
665
  };
640
666
  const touch = {
641
667
  startX: (0, vue.ref)(0),
@@ -672,6 +698,7 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps$1(__s
672
698
  dragging.value = true;
673
699
  prevX = state.value.x;
674
700
  prevY = state.value.y;
701
+ document.body.classList.add("floating-bubble-dragging");
675
702
  if (!("touches" in e)) {
676
703
  window.addEventListener("mousemove", onTouchMove, { passive: false });
677
704
  window.addEventListener("mouseup", onTouchEnd);
@@ -702,24 +729,15 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps$1(__s
702
729
  });
703
730
  }
704
731
  };
705
- const closest = (arr, target) => {
706
- return arr.reduce((pre, cur) => Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur);
707
- };
708
732
  const onTouchEnd = (e) => {
709
733
  dragging.value = false;
734
+ document.body.classList.remove("floating-bubble-dragging");
710
735
  if (e && !("touches" in e) && e.type === "mouseup") {
711
736
  window.removeEventListener("mousemove", onTouchMove);
712
737
  window.removeEventListener("mouseup", onTouchEnd);
713
738
  }
714
739
  requestAnimationFrame(() => {
715
- if (props.magnetic === "x") {
716
- const nextX = closest([boundary.value.left, boundary.value.right], state.value.x);
717
- state.value.x = nextX;
718
- }
719
- if (props.magnetic === "y") {
720
- const nextY = closest([boundary.value.top, boundary.value.bottom], state.value.y);
721
- state.value.y = nextY;
722
- }
740
+ applyMagnetic();
723
741
  if (!touch.isTap.value) {
724
742
  emit("drag-end");
725
743
  const offset = {
@@ -750,6 +768,7 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps$1(__s
750
768
  if (rootRef.value) rootRef.value.addEventListener("touchmove", onTouchMove, { passive: false });
751
769
  });
752
770
  (0, vue.onUnmounted)(() => {
771
+ document.body.classList.remove("floating-bubble-dragging");
753
772
  if (typeof window !== "undefined") {
754
773
  window.removeEventListener("resize", handleResize);
755
774
  window.removeEventListener("mousemove", onTouchMove);
@@ -779,6 +798,8 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps$1(__s
779
798
  windowWidth,
780
799
  windowHeight,
781
800
  boundary,
801
+ closest,
802
+ applyMagnetic,
782
803
  dragging,
783
804
  initialized,
784
805
  rootStyle,
@@ -798,7 +819,6 @@ var __vue_sfc__$2 = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps$1(__s
798
819
  },
799
820
  onTouchStart,
800
821
  onTouchMove,
801
- closest,
802
822
  onTouchEnd,
803
823
  onClick,
804
824
  handleResize
@@ -826,38 +846,20 @@ __vue_sfc__$2.render = __vue_render__$2;
826
846
  var FloatingBubble_vue_default = __vue_sfc__$2;
827
847
  //#endregion
828
848
  //#region es/open-code-widget/src/components/Trigger.vue.js
829
- var STORAGE_KEY = "opencode-bubble-offset";
830
849
  var __vue_sfc__$1 = /* @__PURE__ */ (0, vue.defineComponent)({
831
850
  __name: "Trigger",
832
- emits: [
833
- "offset-change",
834
- "drag-start",
835
- "drag-end"
836
- ],
851
+ emits: ["drag-start", "drag-end"],
837
852
  setup(__props, { expose: __expose, emit: __emit }) {
838
- const { buttonActive: active, open, hotkeyLabel, thinking, resolvedTheme, handleToggle } = useOpenCodeWidgetContext();
839
- const loadOffset = () => {
840
- try {
841
- const saved = localStorage.getItem(STORAGE_KEY);
842
- if (saved) {
843
- const parsed = JSON.parse(saved);
844
- if (parsed && (parsed.x !== 0 || parsed.y !== 0)) return parsed;
845
- }
846
- } catch (e) {}
847
- };
848
- const offset = (0, vue.ref)(loadOffset());
853
+ const { buttonActive: active, open, hotkeyLabel, thinking, resolvedTheme, handleToggle, bubbleOffset, handleBubbleOffsetChange } = useOpenCodeWidgetContext();
854
+ const offset = (0, vue.ref)(bubbleOffset.value);
849
855
  const emit = __emit;
850
- const saveOffset = (value) => {
851
- try {
852
- localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
853
- } catch (e) {}
854
- };
855
856
  const handleOffsetChange = (value) => {
856
857
  offset.value = value;
857
- saveOffset(value);
858
- emit("offset-change", value);
858
+ handleBubbleOffsetChange(value);
859
859
  };
860
- (0, vue.watch)(offset, handleOffsetChange, { immediate: true });
860
+ (0, vue.watch)(bubbleOffset, (newOffset) => {
861
+ offset.value = newOffset;
862
+ });
861
863
  __expose({ offset });
862
864
  const __returned__ = {
863
865
  active,
@@ -866,11 +868,10 @@ var __vue_sfc__$1 = /* @__PURE__ */ (0, vue.defineComponent)({
866
868
  thinking,
867
869
  resolvedTheme,
868
870
  handleToggle,
869
- STORAGE_KEY,
870
- loadOffset,
871
+ bubbleOffset,
872
+ handleBubbleOffsetChange,
871
873
  offset,
872
874
  emit,
873
- saveOffset,
874
875
  handleOffsetChange,
875
876
  FloatingBubble: FloatingBubble_vue_default
876
877
  };
@@ -1374,35 +1375,16 @@ function findFileInfo(element, inspector) {
1374
1375
  };
1375
1376
  }
1376
1377
  function getPreciseElementAtPoint(x, y, boundary) {
1377
- var _a, _b;
1378
- const highlight = document.querySelector(".opencode-element-highlight");
1379
- const tooltip = document.querySelector(".opencode-element-tooltip");
1380
- const highlightDisplay = ((_a = highlight == null ? void 0 : highlight.getAttribute("style")) == null ? void 0 : _a.includes("display: block")) ? "block" : "none";
1381
- const tooltipDisplay = ((_b = tooltip == null ? void 0 : tooltip.getAttribute("style")) == null ? void 0 : _b.includes("display: block")) ? "block" : "none";
1382
- if (highlight) highlight.style.display = "none";
1383
- if (tooltip) tooltip.style.display = "none";
1384
- let element = null;
1385
- try {
1386
- const elements = document.elementsFromPoint(x, y);
1387
- for (const el of elements) {
1388
- if (el.closest("#vue-inspector-container")) continue;
1389
- if (el.closest(".opencode-widget")) continue;
1390
- if (el.hasAttribute("data-v-inspector-ignore")) continue;
1391
- if (boundary) {
1392
- if (boundary.contains(el) || el === boundary) {
1393
- element = el;
1394
- break;
1395
- }
1396
- } else {
1397
- element = el;
1398
- break;
1399
- }
1400
- }
1401
- } finally {
1402
- if (highlight) highlight.style.display = highlightDisplay;
1403
- if (tooltip) tooltip.style.display = tooltipDisplay;
1378
+ const elements = document.elementsFromPoint(x, y);
1379
+ for (const el of elements) {
1380
+ if (el.closest("#vue-inspector-container")) continue;
1381
+ if (el.closest(".opencode-widget")) continue;
1382
+ if (el.hasAttribute("data-v-inspector-ignore")) continue;
1383
+ if (boundary) {
1384
+ if (boundary.contains(el) || el === boundary) return el;
1385
+ } else return el;
1404
1386
  }
1405
- return element;
1387
+ return null;
1406
1388
  }
1407
1389
  function useInspector(options) {
1408
1390
  const highlightVisible = (0, vue.ref)(false);
@@ -1423,74 +1405,117 @@ function useInspector(options) {
1423
1405
  });
1424
1406
  const INSPECTOR_CHECK_INTERVAL = 500;
1425
1407
  let inspectorCheckTimer = null;
1408
+ let currentHighlightElement = null;
1409
+ let currentFileInfo = {
1410
+ file: null,
1411
+ line: null,
1412
+ column: null
1413
+ };
1414
+ let currentPrimary = "#3b82f6";
1415
+ let currentPrimaryBg = "rgba(59, 130, 246, 0.1)";
1416
+ let currentDescription = "";
1417
+ let currentFileInfoText = "";
1426
1418
  function handleMouseMoveCore(e) {
1427
1419
  var _a, _b;
1428
1420
  if (!options.selectMode.value) return;
1429
1421
  const inspector = window.__VUE_INSPECTOR__;
1422
+ const highlight = document.querySelector(".opencode-element-highlight");
1423
+ const tooltip = document.querySelector(".opencode-element-tooltip");
1424
+ if (highlight) highlight.style.pointerEvents = "none";
1425
+ if (tooltip) tooltip.style.pointerEvents = "none";
1430
1426
  let elementToHighlight = null;
1427
+ let targetNode = null;
1431
1428
  let fileInfo = {
1432
1429
  file: null,
1433
1430
  line: null,
1434
1431
  column: null
1435
1432
  };
1436
- if (inspector) {
1437
- const { targetNode, params } = inspector.getTargetNode(e);
1438
- if (targetNode) {
1439
- elementToHighlight = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode) || targetNode;
1440
- if (params && params.file) fileInfo = {
1441
- file: params.file,
1442
- line: (_a = params.line) != null ? _a : null,
1443
- column: (_b = params.column) != null ? _b : null
1444
- };
1445
- else if (elementToHighlight) fileInfo = findFileInfo(elementToHighlight, inspector);
1433
+ try {
1434
+ if (inspector) {
1435
+ const result = inspector.getTargetNode(e);
1436
+ targetNode = result.targetNode;
1437
+ const params = result.params;
1438
+ if (targetNode) {
1439
+ elementToHighlight = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode) || targetNode;
1440
+ if (params && params.file) fileInfo = {
1441
+ file: params.file,
1442
+ line: (_a = params.line) != null ? _a : null,
1443
+ column: (_b = params.column) != null ? _b : null
1444
+ };
1445
+ else fileInfo = findFileInfo(targetNode, inspector);
1446
+ }
1446
1447
  }
1448
+ if (!elementToHighlight) elementToHighlight = getPreciseElementAtPoint(e.clientX, e.clientY, null);
1449
+ if (elementToHighlight && !fileInfo.file) fileInfo = getFileInfoFromVueInstance(elementToHighlight) || fileInfo;
1450
+ } finally {
1451
+ if (highlight) highlight.style.pointerEvents = "";
1452
+ if (tooltip) tooltip.style.pointerEvents = "";
1447
1453
  }
1448
- if (!elementToHighlight) elementToHighlight = getPreciseElementAtPoint(e.clientX, e.clientY, null);
1449
- if (elementToHighlight && !fileInfo.file) fileInfo = getFileInfoFromVueInstance(elementToHighlight) || fileInfo;
1450
1454
  if (elementToHighlight) {
1451
- const rect = elementToHighlight.getBoundingClientRect();
1452
- const widget = document.querySelector(".opencode-widget");
1453
- let primary = "#3b82f6";
1454
- let primaryBg = "rgba(59, 130, 246, 0.1)";
1455
- if (widget) {
1456
- const style = getComputedStyle(widget);
1457
- primary = style.getPropertyValue("--oc-primary").trim() || primary;
1458
- primaryBg = style.getPropertyValue("--oc-primary-bg").trim() || primaryBg;
1459
- }
1460
- highlightVisible.value = true;
1461
- highlightStyle.value = {
1462
- top: `${rect.top}px`,
1463
- left: `${rect.left}px`,
1464
- width: `${rect.width}px`,
1465
- height: `${rect.height}px`,
1466
- border: `2px solid ${primary}`,
1467
- background: primaryBg
1468
- };
1469
- const description = getElementDescription(elementToHighlight);
1470
- const fileName = fileInfo.file ? fileInfo.file.split("/").pop() : "";
1455
+ const elementChanged = currentHighlightElement !== elementToHighlight;
1456
+ if (elementChanged) {
1457
+ currentHighlightElement = elementToHighlight;
1458
+ currentFileInfo = fileInfo;
1459
+ const widget = document.querySelector(".opencode-widget");
1460
+ if (widget) {
1461
+ const style = getComputedStyle(widget);
1462
+ currentPrimary = style.getPropertyValue("--oc-primary").trim() || currentPrimary;
1463
+ currentPrimaryBg = style.getPropertyValue("--oc-primary-bg").trim() || currentPrimaryBg;
1464
+ }
1465
+ currentDescription = getElementDescription(elementToHighlight);
1466
+ } else if (!currentFileInfo.file && fileInfo.file) currentFileInfo = fileInfo;
1467
+ const fileName = currentFileInfo.file ? currentFileInfo.file.split("/").pop() : "";
1471
1468
  let lineInfo = "";
1472
- if (fileInfo.line) {
1473
- lineInfo = `:${fileInfo.line}`;
1474
- if (fileInfo.column) lineInfo += `:${fileInfo.column}`;
1469
+ if (currentFileInfo.line) {
1470
+ lineInfo = `:${currentFileInfo.line}`;
1471
+ if (currentFileInfo.column) lineInfo += `:${currentFileInfo.column}`;
1472
+ }
1473
+ const newFileInfoText = fileName ? `${fileName}${lineInfo}` : "";
1474
+ if (elementChanged || currentFileInfoText !== newFileInfoText) {
1475
+ currentFileInfoText = newFileInfoText;
1476
+ tooltipContent.value = {
1477
+ description: currentDescription,
1478
+ fileInfo: currentFileInfoText
1479
+ };
1475
1480
  }
1476
- tooltipContent.value = {
1477
- description,
1478
- fileInfo: fileName ? `${fileName}${lineInfo}` : ""
1481
+ const rect = elementToHighlight.getBoundingClientRect();
1482
+ const newTop = `${rect.top}px`;
1483
+ const newLeft = `${rect.left}px`;
1484
+ const newWidth = `${rect.width}px`;
1485
+ const newHeight = `${rect.height}px`;
1486
+ if (highlightStyle.value.top !== newTop || highlightStyle.value.left !== newLeft || highlightStyle.value.width !== newWidth || highlightStyle.value.height !== newHeight) highlightStyle.value = {
1487
+ top: newTop,
1488
+ left: newLeft,
1489
+ width: newWidth,
1490
+ height: newHeight,
1491
+ border: `2px solid ${currentPrimary}`,
1492
+ background: currentPrimaryBg
1479
1493
  };
1480
- tooltipVisible.value = true;
1481
1494
  const tooltipHeight = 50;
1482
1495
  const tooltipWidth = 200;
1483
1496
  let tooltipTop = rect.top - tooltipHeight - 8;
1484
1497
  let tooltipLeft = rect.left;
1485
1498
  if (tooltipTop < 10) tooltipTop = rect.bottom + 8;
1486
1499
  if (tooltipLeft + tooltipWidth > window.innerWidth - 10) tooltipLeft = window.innerWidth - tooltipWidth - 10;
1487
- tooltipStyle.value = {
1488
- top: `${tooltipTop}px`,
1489
- left: `${tooltipLeft}px`
1500
+ const newTooltipTop = `${tooltipTop}px`;
1501
+ const newTooltipLeft = `${tooltipLeft}px`;
1502
+ if (tooltipStyle.value.top !== newTooltipTop || tooltipStyle.value.left !== newTooltipLeft) tooltipStyle.value = {
1503
+ top: newTooltipTop,
1504
+ left: newTooltipLeft
1490
1505
  };
1506
+ if (!highlightVisible.value) highlightVisible.value = true;
1507
+ if (!tooltipVisible.value) tooltipVisible.value = true;
1491
1508
  } else {
1492
- highlightVisible.value = false;
1493
- tooltipVisible.value = false;
1509
+ currentHighlightElement = null;
1510
+ currentDescription = "";
1511
+ currentFileInfoText = "";
1512
+ currentFileInfo = {
1513
+ file: null,
1514
+ line: null,
1515
+ column: null
1516
+ };
1517
+ if (highlightVisible.value) highlightVisible.value = false;
1518
+ if (tooltipVisible.value) tooltipVisible.value = false;
1494
1519
  }
1495
1520
  }
1496
1521
  const handleMouseMove = throttle(handleMouseMoveCore, 16);
@@ -1554,6 +1579,14 @@ function useInspector(options) {
1554
1579
  if (inspector) inspector.disable();
1555
1580
  document.removeEventListener("mousemove", handleMouseMove);
1556
1581
  document.removeEventListener("keydown", handleKeydown, true);
1582
+ currentHighlightElement = null;
1583
+ currentDescription = "";
1584
+ currentFileInfoText = "";
1585
+ currentFileInfo = {
1586
+ file: null,
1587
+ line: null,
1588
+ column: null
1589
+ };
1557
1590
  highlightVisible.value = false;
1558
1591
  tooltipVisible.value = false;
1559
1592
  }
@@ -1584,6 +1617,62 @@ function useInspector(options) {
1584
1617
  };
1585
1618
  }
1586
1619
  //#endregion
1620
+ //#region es/open-code-widget/composables/use-persist-state.js
1621
+ var STORAGE_KEY = "opencode-widget-state";
1622
+ function loadState() {
1623
+ if (typeof window === "undefined") return null;
1624
+ try {
1625
+ const stored = localStorage.getItem(STORAGE_KEY);
1626
+ if (stored) return JSON.parse(stored);
1627
+ } catch (e) {
1628
+ console.warn("[OpenCodeWidget] Failed to load persisted state:", e);
1629
+ }
1630
+ return null;
1631
+ }
1632
+ function saveState(state) {
1633
+ if (typeof window === "undefined") return;
1634
+ try {
1635
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
1636
+ } catch (e) {
1637
+ console.warn("[OpenCodeWidget] Failed to save state:", e);
1638
+ }
1639
+ }
1640
+ function usePersistState(options) {
1641
+ const restoreState = () => {
1642
+ const saved = loadState();
1643
+ if (options.onRestore) options.onRestore(saved || {});
1644
+ return saved;
1645
+ };
1646
+ const getCurrentState = () => ({
1647
+ open: options.open.value,
1648
+ minimized: options.minimized.value,
1649
+ promptDockVisible: options.promptDockVisible.value,
1650
+ bubbleOffset: options.bubbleOffset.value,
1651
+ theme: options.theme.value,
1652
+ sessionListCollapsed: options.sessionListCollapsed.value
1653
+ });
1654
+ const persistState = () => {
1655
+ saveState(getCurrentState());
1656
+ };
1657
+ (0, vue.onMounted)(() => {
1658
+ restoreState();
1659
+ (0, vue.watch)([
1660
+ options.open,
1661
+ options.minimized,
1662
+ options.promptDockVisible,
1663
+ options.bubbleOffset,
1664
+ options.theme,
1665
+ options.sessionListCollapsed
1666
+ ], () => {
1667
+ persistState();
1668
+ }, { deep: true });
1669
+ });
1670
+ return {
1671
+ restoreState,
1672
+ persistState
1673
+ };
1674
+ }
1675
+ //#endregion
1587
1676
  //#region es/open-code-widget/src/index.vue.js
1588
1677
  var __defProp = Object.defineProperty;
1589
1678
  var __defProps = Object.defineProperties;
@@ -1787,17 +1876,26 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1787
1876
  var _a;
1788
1877
  (_a = frameRef.value) == null || _a.sendMessageToIframe(type, data);
1789
1878
  };
1879
+ const localSessionListCollapsed = (0, vue.ref)(props.sessionListCollapsed);
1880
+ const minimized = (0, vue.ref)(false);
1881
+ const promptDockVisible = (0, vue.ref)(true);
1882
+ const isRestoring = (0, vue.ref)(true);
1883
+ const iframeLoaded = (0, vue.ref)(false);
1884
+ const syncStateToIframe = () => {
1885
+ if (!iframeLoaded.value) return;
1886
+ sendMessageToIframe("prompt-dock-visibility-change", { visible: promptDockVisible.value });
1887
+ sendMessageToIframe("minimize-state-change", { minimized: minimized.value });
1888
+ };
1790
1889
  const handleFrameLoaded = () => {
1791
1890
  emit("frame-loaded");
1891
+ iframeLoaded.value = true;
1892
+ syncStateToIframe();
1792
1893
  };
1793
1894
  __expose({
1794
1895
  showNotification,
1795
1896
  showConfirmDialog,
1796
1897
  sendMessageToIframe
1797
1898
  });
1798
- const localSessionListCollapsed = (0, vue.ref)(props.sessionListCollapsed);
1799
- const minimized = (0, vue.ref)(false);
1800
- const promptDockVisible = (0, vue.ref)(true);
1801
1899
  (0, vue.watch)(() => props.sessionListCollapsed, (val) => {
1802
1900
  localSessionListCollapsed.value = val;
1803
1901
  });
@@ -1872,6 +1970,48 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1872
1970
  emit("toggle-select-mode", false);
1873
1971
  }
1874
1972
  });
1973
+ const bubbleOffset = (0, vue.ref)(void 0);
1974
+ usePersistState({
1975
+ open: (0, vue.toRef)(props, "open"),
1976
+ minimized,
1977
+ promptDockVisible,
1978
+ bubbleOffset,
1979
+ theme: (0, vue.toRef)(props, "theme"),
1980
+ sessionListCollapsed: localSessionListCollapsed,
1981
+ onRestore: (state) => {
1982
+ if (state.open !== void 0 && state.open !== props.open) {
1983
+ emit("update:open", state.open);
1984
+ emit("toggle", state.open);
1985
+ }
1986
+ if (state.minimized !== void 0) minimized.value = state.minimized;
1987
+ if (state.bubbleOffset !== void 0) {
1988
+ const bubbleSize = 44;
1989
+ const margin = 10;
1990
+ const maxX = window.innerWidth - bubbleSize - margin;
1991
+ const maxY = window.innerHeight - bubbleSize - margin;
1992
+ bubbleOffset.value = {
1993
+ x: Math.max(margin, Math.min(state.bubbleOffset.x, maxX)),
1994
+ y: Math.max(margin, Math.min(state.bubbleOffset.y, maxY))
1995
+ };
1996
+ }
1997
+ if (state.theme !== void 0 && state.theme !== props.theme) {
1998
+ emit("update:theme", state.theme);
1999
+ emit("toggle-theme", state.theme);
2000
+ }
2001
+ if (state.sessionListCollapsed !== void 0 && state.sessionListCollapsed !== props.sessionListCollapsed) {
2002
+ localSessionListCollapsed.value = state.sessionListCollapsed;
2003
+ emit("update:sessionListCollapsed", state.sessionListCollapsed);
2004
+ }
2005
+ if (state.promptDockVisible !== void 0) promptDockVisible.value = state.promptDockVisible;
2006
+ else if (minimized.value) promptDockVisible.value = false;
2007
+ (0, vue.nextTick)(() => {
2008
+ syncStateToIframe();
2009
+ setTimeout(() => {
2010
+ isRestoring.value = false;
2011
+ }, 50);
2012
+ });
2013
+ }
2014
+ });
1875
2015
  const handleToggleMinimize = () => {
1876
2016
  minimized.value = !minimized.value;
1877
2017
  promptDockVisible.value = !minimized.value;
@@ -1882,15 +2022,29 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1882
2022
  promptDockVisible.value = !promptDockVisible.value;
1883
2023
  sendMessageToIframe("prompt-dock-visibility-change", { visible: promptDockVisible.value });
1884
2024
  };
1885
- const bubbleOffset = (0, vue.ref)(void 0);
2025
+ const windowWidth = (0, vue.ref)(typeof window !== "undefined" ? window.innerWidth : 0);
2026
+ const windowHeight = (0, vue.ref)(typeof window !== "undefined" ? window.innerHeight : 0);
2027
+ const handleWindowResize = () => {
2028
+ if (typeof window !== "undefined") {
2029
+ windowWidth.value = window.innerWidth;
2030
+ windowHeight.value = window.innerHeight;
2031
+ }
2032
+ };
2033
+ (0, vue.onMounted)(() => {
2034
+ if (typeof window !== "undefined") window.addEventListener("resize", handleWindowResize);
2035
+ });
2036
+ (0, vue.onUnmounted)(() => {
2037
+ if (typeof window !== "undefined") window.removeEventListener("resize", handleWindowResize);
2038
+ });
1886
2039
  const bubbleQuadrant = (0, vue.computed)(() => {
1887
2040
  var _a, _b, _c, _d;
1888
2041
  if (typeof window === "undefined") return "bottom-right";
1889
- const centerX = window.innerWidth / 2;
1890
- const centerY = window.innerHeight / 2;
2042
+ const centerX = windowWidth.value / 2;
2043
+ const centerY = windowHeight.value / 2;
1891
2044
  const bubbleSize = 44;
1892
- const effectiveX = ((_b = (_a = bubbleOffset.value) == null ? void 0 : _a.x) != null ? _b : window.innerWidth - bubbleSize - 24) + bubbleSize / 2;
1893
- const effectiveY = ((_d = (_c = bubbleOffset.value) == null ? void 0 : _c.y) != null ? _d : window.innerHeight - bubbleSize - 24) + bubbleSize / 2;
2045
+ const currentOffset = (_b = (_a = triggerRef.value) == null ? void 0 : _a.offset) != null ? _b : bubbleOffset.value;
2046
+ const effectiveX = ((_c = currentOffset == null ? void 0 : currentOffset.x) != null ? _c : windowWidth.value - bubbleSize - 24) + bubbleSize / 2;
2047
+ const effectiveY = ((_d = currentOffset == null ? void 0 : currentOffset.y) != null ? _d : windowHeight.value - bubbleSize - 24) + bubbleSize / 2;
1894
2048
  if (effectiveX >= centerX && effectiveY >= centerY) return "bottom-right";
1895
2049
  else if (effectiveX < centerX && effectiveY >= centerY) return "bottom-left";
1896
2050
  else if (effectiveX >= centerX && effectiveY < centerY) return "top-right";
@@ -1901,35 +2055,37 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1901
2055
  return quadrant === "top-right" || quadrant === "bottom-right";
1902
2056
  });
1903
2057
  const chatPositionStyle = (0, vue.computed)(() => {
1904
- var _a;
2058
+ var _a, _b, _c;
1905
2059
  if (typeof window === "undefined") return {};
1906
- const windowWidth = window.innerWidth;
1907
- const windowHeight = window.innerHeight;
1908
2060
  const chatWidth = minimized.value ? 300 : 700;
1909
- const chatHeight = minimized.value ? 300 : Math.min(windowHeight * .86, windowHeight - 40);
2061
+ const chatHeight = minimized.value ? 300 : Math.min(windowHeight.value * .86, windowHeight.value - 40);
1910
2062
  const gap = 24;
1911
2063
  const bubbleSize = 44;
1912
2064
  const screenMargin = 20;
1913
- const effectiveOffset = (_a = bubbleOffset.value) != null ? _a : {
1914
- x: windowWidth - bubbleSize - gap,
1915
- y: windowHeight - bubbleSize - gap
2065
+ const effectiveOffset = (_c = (_b = (_a = triggerRef.value) == null ? void 0 : _a.offset) != null ? _b : bubbleOffset.value) != null ? _c : {
2066
+ x: windowWidth.value - bubbleSize - gap,
2067
+ y: windowHeight.value - bubbleSize - gap
1916
2068
  };
1917
2069
  const style = {};
1918
2070
  if (isBubbleOnRightSide.value) {
1919
- let rightPos = windowWidth - effectiveOffset.x + gap;
1920
- const maxRight = windowWidth - chatWidth - screenMargin;
2071
+ let rightPos = windowWidth.value - effectiveOffset.x + gap;
2072
+ const minRight = screenMargin;
2073
+ const maxRight = windowWidth.value - chatWidth - screenMargin;
1921
2074
  if (rightPos > maxRight) rightPos = maxRight;
2075
+ if (rightPos < minRight) rightPos = minRight;
1922
2076
  style.right = `${rightPos}px`;
1923
2077
  style.left = "auto";
1924
2078
  } else {
1925
2079
  let leftPos = effectiveOffset.x + bubbleSize + gap;
1926
- const maxLeft = windowWidth - chatWidth - screenMargin;
2080
+ const minLeft = screenMargin;
2081
+ const maxLeft = windowWidth.value - chatWidth - screenMargin;
1927
2082
  if (leftPos > maxLeft) leftPos = maxLeft;
2083
+ if (leftPos < minLeft) leftPos = minLeft;
1928
2084
  style.left = `${leftPos}px`;
1929
2085
  style.right = "auto";
1930
2086
  }
1931
- let bottomPos = windowHeight - effectiveOffset.y - bubbleSize;
1932
- const maxBottom = windowHeight - chatHeight - screenMargin;
2087
+ let bottomPos = windowHeight.value - effectiveOffset.y - bubbleSize;
2088
+ const maxBottom = windowHeight.value - chatHeight - screenMargin;
1933
2089
  if (bottomPos > maxBottom) bottomPos = maxBottom;
1934
2090
  if (bottomPos < screenMargin) bottomPos = screenMargin;
1935
2091
  style.bottom = `${bottomPos}px`;
@@ -1991,6 +2147,7 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
1991
2147
  thinking: (0, vue.toRef)(props, "thinking"),
1992
2148
  minimized,
1993
2149
  promptDockVisible,
2150
+ bubbleOffset,
1994
2151
  iframeSource,
1995
2152
  buttonActive,
1996
2153
  sessionListTitle,
@@ -2012,7 +2169,8 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
2012
2169
  handleClickSelectedNode,
2013
2170
  handleRemoveSelectedNode: (payload) => handleRemoveSelectedNode(payload.item, payload.index, payload.source),
2014
2171
  handleClearSelectedNodes,
2015
- handleFrameLoaded
2172
+ handleFrameLoaded,
2173
+ handleBubbleOffsetChange
2016
2174
  });
2017
2175
  const __returned__ = {
2018
2176
  props,
@@ -2042,10 +2200,13 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
2042
2200
  frameRef,
2043
2201
  triggerRef,
2044
2202
  sendMessageToIframe,
2045
- handleFrameLoaded,
2046
2203
  localSessionListCollapsed,
2047
2204
  minimized,
2048
2205
  promptDockVisible,
2206
+ isRestoring,
2207
+ iframeLoaded,
2208
+ syncStateToIframe,
2209
+ handleFrameLoaded,
2049
2210
  buttonActive,
2050
2211
  containerClasses,
2051
2212
  iframeSource,
@@ -2072,9 +2233,12 @@ var __vue_sfc__ = /* @__PURE__ */ (0, vue.defineComponent)(__spreadProps(__sprea
2072
2233
  tooltipVisible,
2073
2234
  tooltipStyle,
2074
2235
  tooltipContent,
2236
+ bubbleOffset,
2075
2237
  handleToggleMinimize,
2076
2238
  handleTogglePromptDock,
2077
- bubbleOffset,
2239
+ windowWidth,
2240
+ windowHeight,
2241
+ handleWindowResize,
2078
2242
  bubbleQuadrant,
2079
2243
  isBubbleOnRightSide,
2080
2244
  chatPositionStyle,
@@ -2131,7 +2295,6 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
2131
2295
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", { class: (0, vue.normalizeClass)($setup.containerClasses) }, [
2132
2296
  (0, vue.createVNode)($setup["Trigger"], {
2133
2297
  ref: "triggerRef",
2134
- onOffsetChange: $setup.handleBubbleOffsetChange,
2135
2298
  onDragStart: $setup.handleDragStart,
2136
2299
  onDragEnd: $setup.handleDragEnd
2137
2300
  }, (0, vue.createSlots)({ _: 2 }, [$setup.slots["button-icon"] ? {
@@ -2143,7 +2306,8 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
2143
2306
  class: (0, vue.normalizeClass)(["opencode-chat", {
2144
2307
  open: $props.open,
2145
2308
  minimized: $setup.minimized,
2146
- dragging: $setup.isDragging
2309
+ dragging: $setup.isDragging,
2310
+ "no-transition": $setup.isRestoring
2147
2311
  }]),
2148
2312
  style: (0, vue.normalizeStyle)($setup.chatPositionStyle)
2149
2313
  }, [
@@ -2198,11 +2362,11 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
2198
2362
  (0, vue.createVNode)($setup["SelectHint"]),
2199
2363
  (0, vue.withDirectives)((0, vue.createElementVNode)("div", {
2200
2364
  class: "opencode-element-highlight",
2201
- style: (0, vue.normalizeStyle)(__spreadValues({ display: $setup.highlightVisible ? "block" : "none" }, $setup.highlightStyle))
2365
+ style: (0, vue.normalizeStyle)($setup.highlightStyle)
2202
2366
  }, null, 4), [[vue.vShow, $setup.highlightVisible]]),
2203
2367
  (0, vue.withDirectives)((0, vue.createElementVNode)("div", {
2204
2368
  class: "opencode-element-tooltip",
2205
- style: (0, vue.normalizeStyle)(__spreadValues({ display: $setup.tooltipVisible ? "block" : "none" }, $setup.tooltipStyle))
2369
+ style: (0, vue.normalizeStyle)($setup.tooltipStyle)
2206
2370
  }, [(0, vue.createElementVNode)("div", _hoisted_3, (0, vue.toDisplayString)($setup.tooltipContent.description), 1), (0, vue.createElementVNode)("div", _hoisted_4, (0, vue.toDisplayString)($setup.tooltipContent.fileInfo), 1)], 4), [[vue.vShow, $setup.tooltipVisible]]),
2207
2371
  $setup.dialogVisible ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_5, [(0, vue.createElementVNode)("div", _hoisted_6, [(0, vue.createElementVNode)("div", _hoisted_7, [(0, vue.createElementVNode)("div", _hoisted_8, (0, vue.toDisplayString)($setup.dialogMessage), 1)]), (0, vue.createElementVNode)("div", { class: "opencode-dialog-actions" }, [(0, vue.createElementVNode)("button", {
2208
2372
  class: "opencode-dialog-btn cancel",
@@ -2220,7 +2384,7 @@ __vue_sfc__.render = __vue_render__;
2220
2384
  var open_code_widget_default = __vue_sfc__;
2221
2385
  //#endregion
2222
2386
  //#region es/index.js
2223
- var version = "1.0.26";
2387
+ var version = "1.0.27";
2224
2388
  function install(app, options) {
2225
2389
  [open_code_widget_default].forEach((item) => {
2226
2390
  if (item.install) app.use(item, options);