@vite-plugin-opencode-assistant/components 1.0.11 → 1.0.13

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 (37) 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 +34 -4
  4. package/es/open-code-widget/composables/use-widget.d.ts +4 -0
  5. package/es/open-code-widget/composables/use-widget.js +40 -3
  6. package/es/open-code-widget/src/components/Frame.vue.js +52 -2
  7. package/es/open-code-widget/src/components/Header-sfc.css +1 -1
  8. package/es/open-code-widget/src/components/Header.vue.d.ts +4 -2
  9. package/es/open-code-widget/src/components/Header.vue.js +87 -13
  10. package/es/open-code-widget/src/components/SelectHint-sfc.css +1 -1
  11. package/es/open-code-widget/src/components/SessionList-sfc.css +1 -1
  12. package/es/open-code-widget/src/context.d.ts +2 -0
  13. package/es/open-code-widget/src/index-sfc.css +1 -1
  14. package/es/open-code-widget/src/index.vue.d.ts +5 -1
  15. package/es/open-code-widget/src/index.vue.js +12 -4
  16. package/es/open-code-widget/src/types.d.ts +2 -0
  17. package/lib/@vite-plugin-opencode-assistant/components.cjs.js +239 -57
  18. package/lib/@vite-plugin-opencode-assistant/components.es.js +240 -58
  19. package/lib/components.css +4 -4
  20. package/lib/index.d.ts +1 -1
  21. package/lib/index.js +1 -1
  22. package/lib/open-code-widget/composables/use-inspector.js +34 -4
  23. package/lib/open-code-widget/composables/use-widget.d.ts +4 -0
  24. package/lib/open-code-widget/composables/use-widget.js +39 -2
  25. package/lib/open-code-widget/src/components/Frame.vue.js +69 -21
  26. package/lib/open-code-widget/src/components/Header-sfc.css +1 -1
  27. package/lib/open-code-widget/src/components/Header.vue.d.ts +4 -2
  28. package/lib/open-code-widget/src/components/Header.vue.js +102 -28
  29. package/lib/open-code-widget/src/components/SelectHint-sfc.css +1 -1
  30. package/lib/open-code-widget/src/components/SessionList-sfc.css +1 -1
  31. package/lib/open-code-widget/src/context.d.ts +2 -0
  32. package/lib/open-code-widget/src/index-sfc.css +1 -1
  33. package/lib/open-code-widget/src/index.vue.d.ts +5 -1
  34. package/lib/open-code-widget/src/index.vue.js +12 -4
  35. package/lib/open-code-widget/src/types.d.ts +2 -0
  36. package/lib/web-types.json +1 -1
  37. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createVNode, defineComponent, inject, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, provide, ref, renderList, renderSlot, toDisplayString, toRef, useSlots, vShow, watch, withCtx, withDirectives, withModifiers } from "vue";
1
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createStaticVNode, createVNode, defineComponent, inject, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, provide, ref, renderList, renderSlot, toDisplayString, toRef, useSlots, vShow, watch, withCtx, withDirectives, withModifiers } from "vue";
2
2
  //#region es/open-code-widget/src/context.js
3
3
  var CONTEXT_KEY = /* @__PURE__ */ Symbol("OpenCodeWidgetContext");
4
4
  function provideOpenCodeWidgetContext(context) {
@@ -11,18 +11,68 @@ function useOpenCodeWidgetContext() {
11
11
  }
12
12
  //#endregion
13
13
  //#region es/open-code-widget/src/components/Frame.vue.js
14
+ var __defProp$1 = Object.defineProperty;
15
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
16
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
17
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
18
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, {
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true,
22
+ value
23
+ }) : obj[key] = value;
24
+ var __spreadValues$1 = (a, b) => {
25
+ for (var prop in b || (b = {})) if (__hasOwnProp$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]);
26
+ if (__getOwnPropSymbols$1) {
27
+ for (var prop of __getOwnPropSymbols$1(b)) if (__propIsEnum$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]);
28
+ }
29
+ return a;
30
+ };
14
31
  var __vue_sfc__$7 = /* @__PURE__ */ defineComponent({
15
32
  __name: "Frame",
16
33
  setup(__props, { expose: __expose }) {
17
34
  __expose();
18
- const { loading, showEmptyState, iframeSource: iframeSrc, emptyStateText, emptyStateActionText, handleEmptyAction } = useOpenCodeWidgetContext();
35
+ const iframeRef = ref(null);
36
+ const { loading, showEmptyState, iframeSource: iframeSrc, emptyStateText, emptyStateActionText, handleEmptyAction, theme, resolvedTheme } = useOpenCodeWidgetContext();
37
+ const iframeReady = ref(false);
38
+ function sendMessageToIframe(type, data) {
39
+ var _a;
40
+ if (!((_a = iframeRef.value) == null ? void 0 : _a.contentWindow)) return;
41
+ iframeRef.value.contentWindow.postMessage(__spreadValues$1({ type }, data), "*");
42
+ }
43
+ function syncIframeTheme() {
44
+ sendMessageToIframe("OPENCODE_SET_THEME", { theme: resolvedTheme.value });
45
+ }
46
+ function handleIframeMessage(event) {
47
+ var _a;
48
+ if (((_a = event.data) == null ? void 0 : _a.type) === "OPENCODE_READY") syncIframeTheme();
49
+ }
50
+ watch([theme, resolvedTheme], () => {
51
+ syncIframeTheme();
52
+ });
53
+ onMounted(() => {
54
+ if (iframeRef.value) iframeRef.value.addEventListener("load", () => {
55
+ iframeReady.value = true;
56
+ });
57
+ window.addEventListener("message", handleIframeMessage);
58
+ });
59
+ onUnmounted(() => {
60
+ window.removeEventListener("message", handleIframeMessage);
61
+ });
19
62
  const __returned__ = {
63
+ iframeRef,
20
64
  loading,
21
65
  showEmptyState,
22
66
  iframeSrc,
23
67
  emptyStateText,
24
68
  emptyStateActionText,
25
- handleEmptyAction
69
+ handleEmptyAction,
70
+ theme,
71
+ resolvedTheme,
72
+ iframeReady,
73
+ sendMessageToIframe,
74
+ syncIframeTheme,
75
+ handleIframeMessage
26
76
  };
27
77
  Object.defineProperty(__returned__, "__isScriptSetup", {
28
78
  enumerable: false,
@@ -59,6 +109,7 @@ function __vue_render__$7(_ctx, _cache, $props, $setup, $data, $options) {
59
109
  ])], 2),
60
110
  createElementVNode("div", { class: normalizeClass(["opencode-loading-overlay", { visible: $setup.loading }]) }, [renderSlot(_ctx.$slots, "loading", {}, () => [_cache[2] || (_cache[2] = createElementVNode("div", { class: "opencode-loading-spinner" }, null, -1)), _cache[3] || (_cache[3] = createElementVNode("div", { class: "opencode-loading-text" }, "加载中...", -1))])], 2),
61
111
  renderSlot(_ctx.$slots, "content", {}, () => [createElementVNode("iframe", {
112
+ ref: "iframeRef",
62
113
  class: "opencode-iframe",
63
114
  src: $setup.iframeSrc,
64
115
  allow: "clipboard-write; clipboard-read",
@@ -74,16 +125,33 @@ var __vue_sfc__$6 = /* @__PURE__ */ defineComponent({
74
125
  __name: "Header",
75
126
  setup(__props, { expose: __expose }) {
76
127
  __expose();
77
- const { title, sessionListTitle, sessionListCollapsed, selectMode, selectEnabled, handleToggleSessionList, handleToggleSelectMode, handleClose } = useOpenCodeWidgetContext();
128
+ const { title, sessionListTitle, sessionListCollapsed, selectMode, selectEnabled, theme, resolvedTheme, handleToggleSessionList, handleToggleSelectMode, handleToggleTheme, handleClose } = useOpenCodeWidgetContext();
78
129
  const __returned__ = {
79
130
  title,
80
131
  sessionListTitle,
81
132
  sessionListCollapsed,
82
133
  selectMode,
83
134
  selectEnabled,
135
+ theme,
136
+ resolvedTheme,
84
137
  handleToggleSessionList,
85
138
  handleToggleSelectMode,
86
- handleClose
139
+ handleToggleTheme,
140
+ handleClose,
141
+ themeIconTitle: computed(() => {
142
+ return `\u4E3B\u9898: ${{
143
+ auto: "自动",
144
+ light: "亮色",
145
+ dark: "暗色"
146
+ }[theme.value]} (${resolvedTheme.value})`;
147
+ }),
148
+ themeIconLabel: computed(() => {
149
+ return `\u5207\u6362\u4E3B\u9898 - \u5F53\u524D: ${{
150
+ auto: "自动跟随系统",
151
+ light: "亮色主题",
152
+ dark: "暗色主题"
153
+ }[theme.value]}`;
154
+ })
87
155
  };
88
156
  Object.defineProperty(__returned__, "__isScriptSetup", {
89
157
  enumerable: false,
@@ -100,56 +168,97 @@ var _hoisted_3$4 = [
100
168
  "aria-expanded"
101
169
  ];
102
170
  var _hoisted_4$4 = ["aria-pressed", "disabled"];
103
- var _hoisted_5$4 = { class: "opencode-chat-header-title" };
104
- var _hoisted_6$3 = { class: "opencode-chat-header-actions" };
171
+ var _hoisted_5$4 = ["title", "aria-label"];
172
+ var _hoisted_6$3 = {
173
+ key: 0,
174
+ viewBox: "0 0 24 24",
175
+ width: "16",
176
+ height: "16",
177
+ fill: "none",
178
+ stroke: "currentColor",
179
+ "stroke-width": "2",
180
+ "aria-hidden": "true"
181
+ };
182
+ var _hoisted_7$2 = {
183
+ key: 1,
184
+ viewBox: "0 0 24 24",
185
+ width: "16",
186
+ height: "16",
187
+ fill: "none",
188
+ stroke: "currentColor",
189
+ "stroke-width": "2",
190
+ "aria-hidden": "true"
191
+ };
192
+ var _hoisted_8$2 = {
193
+ key: 2,
194
+ viewBox: "0 0 24 24",
195
+ width: "16",
196
+ height: "16",
197
+ fill: "none",
198
+ stroke: "currentColor",
199
+ "stroke-width": "2",
200
+ "aria-hidden": "true"
201
+ };
202
+ var _hoisted_9$1 = { class: "opencode-chat-header-title" };
203
+ var _hoisted_10 = { class: "opencode-chat-header-actions" };
105
204
  function __vue_render__$6(_ctx, _cache, $props, $setup, $data, $options) {
106
205
  return openBlock(), createElementBlock("div", _hoisted_1$6, [
107
- createElementVNode("div", _hoisted_2$4, [createElementVNode("button", {
108
- class: "opencode-header-btn session-toggle",
109
- type: "button",
110
- title: $setup.sessionListTitle,
111
- "aria-label": $setup.sessionListTitle,
112
- "aria-expanded": !$setup.sessionListCollapsed,
113
- onClick: _cache[0] || (_cache[0] = (...args) => $setup.handleToggleSessionList && $setup.handleToggleSessionList(...args))
114
- }, [renderSlot(_ctx.$slots, "session-toggle-icon", {}, () => [_cache[3] || (_cache[3] = createElementVNode("svg", {
115
- viewBox: "0 0 24 24",
116
- width: "16",
117
- height: "16",
118
- fill: "none",
119
- stroke: "currentColor",
120
- "stroke-width": "2",
121
- "aria-hidden": "true"
122
- }, [createElementVNode("path", {
123
- d: "M4 6h16M4 12h16M4 18h16",
124
- "stroke-linecap": "round"
125
- })], -1))])], 8, _hoisted_3$4), createElementVNode("button", {
126
- class: normalizeClass(["opencode-header-btn select-btn", { active: $setup.selectMode }]),
127
- type: "button",
128
- title: "选择页面元素 (Ctrl+P)",
129
- "aria-label": "选择页面元素",
130
- "aria-pressed": $setup.selectMode,
131
- disabled: !$setup.selectEnabled,
132
- onClick: _cache[1] || (_cache[1] = (...args) => $setup.handleToggleSelectMode && $setup.handleToggleSelectMode(...args))
133
- }, [renderSlot(_ctx.$slots, "select-icon", {}, () => [_cache[4] || (_cache[4] = createElementVNode("svg", {
134
- viewBox: "0 0 1024 1024",
135
- width: "16",
136
- height: "16",
137
- "aria-hidden": "true"
138
- }, [createElementVNode("path", {
139
- fill: "currentColor",
140
- d: "M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768m0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896"
141
- }), createElementVNode("path", {
142
- fill: "currentColor",
143
- d: "M512 96a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V128a32 32 0 0 1 32-32m0 576a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V704a32 32 0 0 1 32-32M96 512a32 32 0 0 1 32-32h192a32 32 0 0 1 0 64H128a32 32 0 0 1-32-32m576 0a32 32 0 0 1 32-32h192a32 32 0 1 1 0 64H704a32 32 0 0 1-32-32"
144
- })], -1))])], 10, _hoisted_4$4)]),
145
- createElementVNode("span", _hoisted_5$4, toDisplayString($setup.title), 1),
146
- createElementVNode("div", _hoisted_6$3, [createElementVNode("button", {
206
+ createElementVNode("div", _hoisted_2$4, [
207
+ createElementVNode("button", {
208
+ class: normalizeClass(["opencode-header-btn session-toggle", { active: !$setup.sessionListCollapsed }]),
209
+ type: "button",
210
+ title: $setup.sessionListTitle,
211
+ "aria-label": $setup.sessionListTitle,
212
+ "aria-expanded": !$setup.sessionListCollapsed,
213
+ onClick: _cache[0] || (_cache[0] = (...args) => $setup.handleToggleSessionList && $setup.handleToggleSessionList(...args))
214
+ }, [renderSlot(_ctx.$slots, "session-toggle-icon", {}, () => [_cache[4] || (_cache[4] = createElementVNode("svg", {
215
+ viewBox: "0 0 24 24",
216
+ width: "16",
217
+ height: "16",
218
+ fill: "none",
219
+ stroke: "currentColor",
220
+ "stroke-width": "2",
221
+ "aria-hidden": "true"
222
+ }, [createElementVNode("path", {
223
+ d: "M4 6h16M4 12h16M4 18h16",
224
+ "stroke-linecap": "round"
225
+ })], -1))])], 10, _hoisted_3$4),
226
+ createElementVNode("button", {
227
+ class: normalizeClass(["opencode-header-btn select-btn", { active: $setup.selectMode }]),
228
+ type: "button",
229
+ title: "选择页面元素 (Ctrl+P)",
230
+ "aria-label": "选择页面元素",
231
+ "aria-pressed": $setup.selectMode,
232
+ disabled: !$setup.selectEnabled,
233
+ onClick: _cache[1] || (_cache[1] = (...args) => $setup.handleToggleSelectMode && $setup.handleToggleSelectMode(...args))
234
+ }, [renderSlot(_ctx.$slots, "select-icon", {}, () => [_cache[5] || (_cache[5] = createElementVNode("svg", {
235
+ viewBox: "0 0 1024 1024",
236
+ width: "16",
237
+ height: "16",
238
+ "aria-hidden": "true"
239
+ }, [createElementVNode("path", {
240
+ fill: "currentColor",
241
+ d: "M512 896a384 384 0 1 0 0-768 384 384 0 0 0 0 768m0 64a448 448 0 1 1 0-896 448 448 0 0 1 0 896"
242
+ }), createElementVNode("path", {
243
+ fill: "currentColor",
244
+ d: "M512 96a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V128a32 32 0 0 1 32-32m0 576a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V704a32 32 0 0 1 32-32M96 512a32 32 0 0 1 32-32h192a32 32 0 0 1 0 64H128a32 32 0 0 1-32-32m576 0a32 32 0 0 1 32-32h192a32 32 0 1 1 0 64H704a32 32 0 0 1-32-32"
245
+ })], -1))])], 10, _hoisted_4$4),
246
+ createElementVNode("button", {
247
+ class: "opencode-header-btn theme-btn",
248
+ type: "button",
249
+ title: $setup.themeIconTitle,
250
+ "aria-label": $setup.themeIconLabel,
251
+ onClick: _cache[2] || (_cache[2] = (...args) => $setup.handleToggleTheme && $setup.handleToggleTheme(...args))
252
+ }, [renderSlot(_ctx.$slots, "theme-icon", {}, () => [$setup.theme === "light" ? (openBlock(), createElementBlock("svg", _hoisted_6$3, [..._cache[6] || (_cache[6] = [createStaticVNode("<circle cx=\"12\" cy=\"12\" r=\"5\"></circle><line x1=\"12\" y1=\"1\" x2=\"12\" y2=\"3\"></line><line x1=\"12\" y1=\"21\" x2=\"12\" y2=\"23\"></line><line x1=\"4.22\" y1=\"4.22\" x2=\"5.64\" y2=\"5.64\"></line><line x1=\"18.36\" y1=\"18.36\" x2=\"19.78\" y2=\"19.78\"></line><line x1=\"1\" y1=\"12\" x2=\"3\" y2=\"12\"></line><line x1=\"21\" y1=\"12\" x2=\"23\" y2=\"12\"></line><line x1=\"4.22\" y1=\"19.78\" x2=\"5.64\" y2=\"18.36\"></line><line x1=\"18.36\" y1=\"5.64\" x2=\"19.78\" y2=\"4.22\"></line>", 9)])])) : $setup.theme === "dark" ? (openBlock(), createElementBlock("svg", _hoisted_7$2, [..._cache[7] || (_cache[7] = [createElementVNode("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }, null, -1)])])) : (openBlock(), createElementBlock("svg", _hoisted_8$2, [..._cache[8] || (_cache[8] = [createStaticVNode("<rect x=\"2\" y=\"3\" width=\"20\" height=\"14\" rx=\"2\" ry=\"2\"></rect><line x1=\"8\" y1=\"21\" x2=\"16\" y2=\"21\"></line><line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"></line><circle cx=\"12\" cy=\"10\" r=\"3\"></circle><path d=\"M7 7l2 2M17 7l-2 2M7 13l2-2M17 13l-2-2\"></path>", 5)])]))])], 8, _hoisted_5$4)
253
+ ]),
254
+ createElementVNode("span", _hoisted_9$1, toDisplayString($setup.title), 1),
255
+ createElementVNode("div", _hoisted_10, [createElementVNode("button", {
147
256
  class: "opencode-header-btn close",
148
257
  type: "button",
149
258
  title: "关闭",
150
259
  "aria-label": "关闭面板",
151
- onClick: _cache[2] || (_cache[2] = (...args) => $setup.handleClose && $setup.handleClose(...args))
152
- }, [renderSlot(_ctx.$slots, "close-icon", {}, () => [_cache[5] || (_cache[5] = createElementVNode("svg", {
260
+ onClick: _cache[3] || (_cache[3] = (...args) => $setup.handleClose && $setup.handleClose(...args))
261
+ }, [renderSlot(_ctx.$slots, "close-icon", {}, () => [_cache[9] || (_cache[9] = createElementVNode("svg", {
153
262
  viewBox: "0 0 24 24",
154
263
  width: "14",
155
264
  height: "14",
@@ -650,11 +759,39 @@ function useSession(options) {
650
759
  }
651
760
  //#endregion
652
761
  //#region es/open-code-widget/composables/use-widget.js
762
+ var THEME_CYCLE = [
763
+ "auto",
764
+ "light",
765
+ "dark"
766
+ ];
653
767
  function useWidget(options) {
768
+ const systemTheme = ref("light");
769
+ function getSystemTheme() {
770
+ if (typeof window === "undefined") return "light";
771
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
772
+ }
773
+ let mediaQuery = null;
774
+ let handleChange = null;
775
+ onMounted(() => {
776
+ if (typeof window === "undefined") return;
777
+ systemTheme.value = getSystemTheme();
778
+ mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
779
+ handleChange = (e) => {
780
+ systemTheme.value = e.matches ? "dark" : "light";
781
+ };
782
+ mediaQuery.addEventListener("change", handleChange);
783
+ });
784
+ onUnmounted(() => {
785
+ if (mediaQuery && handleChange) mediaQuery.removeEventListener("change", handleChange);
786
+ });
787
+ const resolvedTheme = computed(() => {
788
+ if (options.theme.value === "auto") return systemTheme.value;
789
+ return options.theme.value;
790
+ });
654
791
  const containerClasses = computed(() => [
655
792
  "opencode-widget",
656
793
  options.position.value,
657
- `opencode-theme-${options.theme.value}`
794
+ `opencode-theme-${resolvedTheme.value}`
658
795
  ]);
659
796
  const buttonActive = computed(() => !!(options.open.value || options.selectMode.value));
660
797
  const iframeSource = computed(() => options.iframeSrc.value || "about:blank");
@@ -677,15 +814,22 @@ function useWidget(options) {
677
814
  function handleEmptyAction() {
678
815
  options.onEmptyAction();
679
816
  }
817
+ function handleToggleTheme() {
818
+ var _a;
819
+ const nextTheme = THEME_CYCLE[(THEME_CYCLE.indexOf(options.theme.value) + 1) % THEME_CYCLE.length];
820
+ (_a = options.onToggleTheme) == null || _a.call(options, nextTheme);
821
+ }
680
822
  return {
681
823
  buttonActive,
682
824
  containerClasses,
683
825
  iframeSource,
684
826
  sessionListTitle,
827
+ resolvedTheme,
685
828
  handleClose,
686
829
  handleEmptyAction,
687
830
  handleToggle,
688
- handleToggleSessionList
831
+ handleToggleSessionList,
832
+ handleToggleTheme
689
833
  };
690
834
  }
691
835
  //#endregion
@@ -719,6 +863,32 @@ function getElementDescription(element) {
719
863
  if (href && href !== "#") parts.push(`[href]`);
720
864
  return parts.join("");
721
865
  }
866
+ function getPreciseElementAtPoint(x, y, boundary) {
867
+ var _a, _b;
868
+ const highlight = document.querySelector(".opencode-element-highlight");
869
+ const tooltip = document.querySelector(".opencode-element-tooltip");
870
+ const highlightDisplay = ((_a = highlight == null ? void 0 : highlight.getAttribute("style")) == null ? void 0 : _a.includes("display: block")) ? "block" : "none";
871
+ const tooltipDisplay = ((_b = tooltip == null ? void 0 : tooltip.getAttribute("style")) == null ? void 0 : _b.includes("display: block")) ? "block" : "none";
872
+ if (highlight) highlight.style.display = "none";
873
+ if (tooltip) tooltip.style.display = "none";
874
+ let element = null;
875
+ try {
876
+ const elements = document.elementsFromPoint(x, y);
877
+ for (const el of elements) {
878
+ if (el.closest("#vue-inspector-container")) continue;
879
+ if (el.closest(".opencode-widget")) continue;
880
+ if (el.hasAttribute("data-v-inspector-ignore")) continue;
881
+ if (boundary.contains(el) || el === boundary) {
882
+ element = el;
883
+ break;
884
+ }
885
+ }
886
+ } finally {
887
+ if (highlight) highlight.style.display = highlightDisplay;
888
+ if (tooltip) tooltip.style.display = tooltipDisplay;
889
+ }
890
+ return element;
891
+ }
722
892
  function useInspector(options) {
723
893
  const highlightVisible = ref(false);
724
894
  const highlightStyle = ref({
@@ -744,7 +914,8 @@ function useInspector(options) {
744
914
  if (!inspector) return;
745
915
  const { targetNode, params } = inspector.getTargetNode(e);
746
916
  if (targetNode && params) {
747
- const rect = targetNode.getBoundingClientRect();
917
+ const elementToHighlight = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode) || targetNode;
918
+ const rect = elementToHighlight.getBoundingClientRect();
748
919
  const widget = document.querySelector(".opencode-widget");
749
920
  let primary = "#3b82f6";
750
921
  let primaryBg = "rgba(59, 130, 246, 0.1)";
@@ -762,7 +933,7 @@ function useInspector(options) {
762
933
  border: `2px solid ${primary}`,
763
934
  background: primaryBg
764
935
  };
765
- const description = getElementDescription(targetNode);
936
+ const description = getElementDescription(elementToHighlight);
766
937
  const fileName = params.file ? params.file.split("/").pop() : "";
767
938
  let lineInfo = "";
768
939
  if (params.line) {
@@ -798,8 +969,9 @@ function useInspector(options) {
798
969
  if (options.selectMode.value) {
799
970
  const { targetNode, params } = inspector.getTargetNode(e);
800
971
  if (targetNode && params) {
801
- const innerText = getDirectText(targetNode);
802
- const description = getElementDescription(targetNode);
972
+ const elementToSelect = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode) || targetNode;
973
+ const innerText = getDirectText(elementToSelect);
974
+ const description = getElementDescription(elementToSelect);
803
975
  const elementInfo = {
804
976
  filePath: (_a = params.file) != null ? _a : null,
805
977
  line: (_b = params.line) != null ? _b : null,
@@ -899,7 +1071,7 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
899
1071
  theme: {
900
1072
  type: String,
901
1073
  required: false,
902
- default: "light"
1074
+ default: "auto"
903
1075
  },
904
1076
  title: {
905
1077
  type: String,
@@ -992,10 +1164,12 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
992
1164
  "update:sessionListCollapsed",
993
1165
  "update:currentSessionId",
994
1166
  "update:selectedElements",
1167
+ "update:theme",
995
1168
  "toggle",
996
1169
  "close",
997
1170
  "toggle-session-list",
998
1171
  "toggle-select-mode",
1172
+ "toggle-theme",
999
1173
  "create-session",
1000
1174
  "select-session",
1001
1175
  "delete-session",
@@ -1045,7 +1219,7 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1045
1219
  watch(() => props.sessionListCollapsed, (val) => {
1046
1220
  localSessionListCollapsed.value = val;
1047
1221
  });
1048
- const { buttonActive, containerClasses, iframeSource, sessionListTitle, handleClose, handleEmptyAction, handleToggle, handleToggleSessionList } = useWidget({
1222
+ const { buttonActive, containerClasses, iframeSource, sessionListTitle, resolvedTheme, handleClose, handleEmptyAction, handleToggle, handleToggleSessionList, handleToggleTheme } = useWidget({
1049
1223
  position: toRef(props, "position"),
1050
1224
  theme: toRef(props, "theme"),
1051
1225
  open: toRef(props, "open"),
@@ -1071,6 +1245,10 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1071
1245
  },
1072
1246
  onEmptyAction: () => {
1073
1247
  emit("empty-action");
1248
+ },
1249
+ onToggleTheme: (newTheme) => {
1250
+ emit("update:theme", newTheme);
1251
+ emit("toggle-theme", newTheme);
1074
1252
  }
1075
1253
  });
1076
1254
  const { sessionItems, handleCreateSession, handleDeleteSession, handleSelectSession } = useSession({
@@ -1115,6 +1293,7 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1115
1293
  });
1116
1294
  provideOpenCodeWidgetContext({
1117
1295
  theme: toRef(props, "theme"),
1296
+ resolvedTheme,
1118
1297
  title: toRef(props, "title"),
1119
1298
  hotkeyLabel: toRef(props, "hotkeyLabel"),
1120
1299
  selectShortcutLabel: toRef(props, "selectShortcutLabel"),
@@ -1139,6 +1318,7 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1139
1318
  handleToggle,
1140
1319
  handleClose,
1141
1320
  handleToggleSessionList,
1321
+ handleToggleTheme,
1142
1322
  handleEmptyAction,
1143
1323
  handleCreateSession,
1144
1324
  handleSelectSession,
@@ -1177,10 +1357,12 @@ var __vue_sfc__ = /* @__PURE__ */ defineComponent(__spreadProps(__spreadValues({
1177
1357
  containerClasses,
1178
1358
  iframeSource,
1179
1359
  sessionListTitle,
1360
+ resolvedTheme,
1180
1361
  handleClose,
1181
1362
  handleEmptyAction,
1182
1363
  handleToggle,
1183
1364
  handleToggleSessionList,
1365
+ handleToggleTheme,
1184
1366
  sessionItems,
1185
1367
  handleCreateSession,
1186
1368
  handleDeleteSession,
@@ -1311,7 +1493,7 @@ __vue_sfc__.render = __vue_render__;
1311
1493
  var open_code_widget_default = __vue_sfc__;
1312
1494
  //#endregion
1313
1495
  //#region es/index.js
1314
- var version = "1.0.11";
1496
+ var version = "1.0.13";
1315
1497
  function install(app, options) {
1316
1498
  [open_code_widget_default].forEach((item) => {
1317
1499
  if (item.install) app.use(item, options);
@@ -1,9 +1,9 @@
1
- .opencode-widget{--oc-bg-main: #ffffff;--oc-bg-secondary: #f8f9fa;--oc-bg-tertiary: #f3f4f6;--oc-overlay-bg: rgba(255, 255, 255, .9);--oc-bg-inverse: #1e1e1e;--oc-text-primary: #282828;--oc-text-secondary: #4b5563;--oc-text-tertiary: #6b7280;--oc-text-placeholder: #9ca3af;--oc-text-inverse: #ffffff;--oc-border-primary: #e5e7eb;--oc-border-secondary: #d1d5db;--oc-primary: #3b82f6;--oc-primary-hover: #2563eb;--oc-primary-bg: rgba(59, 130, 246, .1);--oc-danger: #ef4444;--oc-danger-hover: #dc2626;--oc-danger-active: #b91c1c;--oc-success: #10b981;--oc-overlay: rgba(0, 0, 0, .5);--oc-tooltip-bg: #1e1e1e;--oc-dialog-overlay: rgba(0, 0, 0, .5);--oc-skeleton-bg: #e5e7eb;--oc-skeleton-gradient: linear-gradient(90deg, #e5e7eb 25%, #f3f4f6 50%, #e5e7eb 75%);--oc-shadow-sm: 0 2px 4px rgba(0, 0, 0, .1);--oc-shadow-md: 0 4px 12px rgba(0, 0, 0, .15);--oc-shadow-lg: 0 8px 32px rgba(0, 0, 0, .12);--oc-shadow-xl: 0 20px 60px rgba(0, 0, 0, .3);--oc-shadow-primary: 0 2px 4px rgba(59, 130, 246, .2);--oc-shadow-primary-hover: 0 4px 6px rgba(59, 130, 246, .3);--oc-shadow-danger: 0 4px 12px rgba(239, 68, 68, .3);--oc-trigger-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);--oc-trigger-bg-hover: linear-gradient(135deg, #764ba2 0%, #667eea 100%);--oc-trigger-bg-active: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);--oc-trigger-shadow: 0 4px 15px rgba(102, 126, 234, .4);--oc-trigger-shadow-hover: 0 6px 20px rgba(102, 126, 234, .6);--oc-trigger-shadow-active: 0 6px 20px rgba(240, 147, 251, .4);position:fixed;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.opencode-widget.opencode-theme-dark{--oc-bg-main: #1a1a1a;--oc-bg-secondary: #1e1e1e;--oc-bg-tertiary: #282828;--oc-overlay-bg: rgba(26, 26, 26, .9);--oc-bg-inverse: #ffffff;--oc-text-primary: #f3f4f6;--oc-text-secondary: #d1d5db;--oc-text-tertiary: #9ca3af;--oc-text-placeholder: #6b7280;--oc-text-inverse: #282828;--oc-border-primary: #282828;--oc-border-secondary: #4b5563;--oc-primary: #3b82f6;--oc-primary-hover: #2563eb;--oc-primary-bg: rgba(59, 130, 246, .15);--oc-danger: #ef4444;--oc-danger-hover: #dc2626;--oc-danger-active: #b91c1c;--oc-success: #10b981;--oc-overlay: rgba(26, 26, 26, .9);--oc-tooltip-bg: #282828;--oc-dialog-overlay: rgba(0, 0, 0, .7);--oc-skeleton-bg: #151515;--oc-skeleton-gradient: linear-gradient(90deg, #282828 25%, #4b5563 50%, #282828 75%);--oc-shadow-sm: 0 2px 4px rgba(0, 0, 0, .3);--oc-shadow-md: 0 4px 12px rgba(0, 0, 0, .4);--oc-shadow-lg: 0 8px 32px rgba(0, 0, 0, .4);--oc-shadow-xl: 0 20px 60px rgba(0, 0, 0, .6);--oc-shadow-primary: 0 2px 4px rgba(59, 130, 246, .3);--oc-shadow-primary-hover: 0 4px 6px rgba(59, 130, 246, .4);--oc-shadow-danger: 0 4px 12px rgba(239, 68, 68, .4);--oc-trigger-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);--oc-trigger-bg-hover: linear-gradient(135deg, #764ba2 0%, #667eea 100%);--oc-trigger-bg-active: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);--oc-trigger-shadow: 0 4px 15px rgba(102, 126, 234, .5);--oc-trigger-shadow-hover: 0 6px 20px rgba(102, 126, 234, .7);--oc-trigger-shadow-active: 0 6px 20px rgba(240, 147, 251, .5)}.opencode-widget.bottom-right{bottom:20px;right:20px}.opencode-widget.bottom-left{bottom:20px;left:20px}.opencode-widget.top-right{top:20px;right:20px}.opencode-widget.top-left{top:20px;left:20px}.opencode-chat{position:absolute;width:700px;height:86vh;background:var(--oc-bg-main);border-radius:16px;box-shadow:var(--oc-shadow-lg);overflow:hidden;opacity:0;visibility:hidden;transform:translateY(20px) scale(.95);transition:all .3s ease;display:flex;flex-direction:column}.opencode-chat-content{display:flex;flex:1;overflow:hidden}.opencode-widget.bottom-right .opencode-chat{bottom:56px;right:0}.opencode-widget.bottom-left .opencode-chat{bottom:56px;left:0}.opencode-widget.top-right .opencode-chat{top:56px;right:0}.opencode-widget.top-left .opencode-chat{top:56px;left:0}.opencode-widget.bottom-right .opencode-selected-bubbles{bottom:56px;right:0}.opencode-widget.bottom-left .opencode-selected-bubbles{bottom:56px;left:0}.opencode-widget.top-right .opencode-selected-bubbles{top:56px;bottom:auto;right:0}.opencode-widget.top-left .opencode-selected-bubbles{top:56px;bottom:auto;left:0}.opencode-chat.open{opacity:1;visibility:visible;transform:translateY(0) scale(1)}.opencode-notification{position:absolute;top:20px;left:50%;transform:translate(-50%);padding:12px 20px;background:var(--oc-bg-main);color:var(--oc-text-primary);border:1px solid var(--oc-border-primary);border-radius:8px;font-size:14px;box-shadow:var(--oc-shadow-lg);animation:slideDown .3s ease;z-index:10000000}.opencode-dialog-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:var(--oc-dialog-overlay);display:flex;align-items:center;justify-content:center;z-index:9999999;animation:fadeIn .2s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.opencode-dialog{background:var(--oc-bg-main);border-radius:12px;padding:24px;min-width:320px;max-width:400px;box-shadow:var(--oc-shadow-xl);animation:scaleIn .2s ease}@keyframes scaleIn{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}.opencode-dialog-content{margin-bottom:20px}.opencode-dialog-message{font-size:15px;color:var(--oc-text-primary);line-height:1.5}.opencode-dialog-actions{display:flex;gap:12px;justify-content:flex-end}.opencode-dialog-btn{padding:10px 20px;border-radius:8px;border:none;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.opencode-dialog-btn.cancel{background:var(--oc-bg-tertiary);color:var(--oc-text-primary)}.opencode-dialog-btn.cancel:hover{background:var(--oc-text-primary);color:var(--oc-bg-main)}.opencode-dialog-btn.confirm{background:var(--oc-danger);color:#fff}.opencode-dialog-btn.confirm:hover{background:var(--oc-danger-hover)}@keyframes slideDown{0%{transform:translate(-50%) translateY(-100%);opacity:0}to{transform:translate(-50%) translateY(0);opacity:1}}.opencode-element-highlight{position:fixed;pointer-events:none;z-index:999998;display:none;transition:all .1s ease;border-radius:4px}#vue-inspector-container{display:none!important}.opencode-element-tooltip{position:fixed;background:var(--oc-tooltip-bg);color:#fff;padding:8px 12px;border-radius:6px;font-size:12px;z-index:9999998;display:none;box-shadow:var(--oc-shadow-md);max-width:300px;pointer-events:none}.opencode-tooltip-tag{font-weight:500;margin-bottom:4px;word-break:break-all}.opencode-tooltip-file{font-size:11px;color:var(--oc-text-placeholder);word-break:break-all}.opencode-element-highlight-temp{position:absolute;pointer-events:none;z-index:999998;border-radius:4px;animation:highlight-pulse 2s ease-out forwards}@keyframes highlight-pulse{0%{opacity:1;transform:scale(1)}50%{opacity:.8;transform:scale(1.02)}to{opacity:0;transform:scale(1)}}@media(max-width:768px){.opencode-chat{width:calc(100vw - 40px);height:calc(100vh - 100px)}}
1
+ .opencode-widget{--oc-bg-main: #ffffff;--oc-bg-secondary: #f8f9fa;--oc-bg-tertiary: #f3f4f6;--oc-overlay-bg: rgba(255, 255, 255, .9);--oc-bg-inverse: #1e1e1e;--oc-text-primary: #282828;--oc-text-secondary: #4b5563;--oc-text-tertiary: #6b7280;--oc-text-placeholder: #9ca3af;--oc-text-inverse: #ffffff;--oc-border-primary: #e5e7eb;--oc-border-secondary: #d1d5db;--oc-primary: #3b82f6;--oc-primary-hover: #2563eb;--oc-primary-bg: rgba(59, 130, 246, .1);--oc-danger: #ef4444;--oc-danger-hover: #dc2626;--oc-danger-active: #b91c1c;--oc-success: #10b981;--oc-overlay: rgba(0, 0, 0, .5);--oc-tooltip-bg: #1e1e1e;--oc-dialog-overlay: rgba(0, 0, 0, .5);--oc-skeleton-bg: #e5e7eb;--oc-skeleton-gradient: linear-gradient(90deg, #e5e7eb 25%, #f3f4f6 50%, #e5e7eb 75%);--oc-shadow-sm: 0 2px 4px rgba(0, 0, 0, .1);--oc-shadow-md: 0 4px 12px rgba(0, 0, 0, .15);--oc-shadow-lg: 0 8px 32px rgba(0, 0, 0, .12);--oc-shadow-xl: 0 20px 60px rgba(0, 0, 0, .3);--oc-shadow-primary: 0 2px 4px rgba(59, 130, 246, .2);--oc-shadow-primary-hover: 0 4px 6px rgba(59, 130, 246, .3);--oc-shadow-danger: 0 4px 12px rgba(239, 68, 68, .3);--oc-trigger-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);--oc-trigger-bg-hover: linear-gradient(135deg, #764ba2 0%, #667eea 100%);--oc-trigger-bg-active: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);--oc-trigger-shadow: 0 4px 15px rgba(102, 126, 234, .4);--oc-trigger-shadow-hover: 0 6px 20px rgba(102, 126, 234, .6);--oc-trigger-shadow-active: 0 6px 20px rgba(240, 147, 251, .4);position:fixed;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.opencode-widget.opencode-theme-dark{--oc-bg-main: #1a1a1a;--oc-bg-secondary: #1e1e1e;--oc-bg-tertiary: #282828;--oc-overlay-bg: rgba(26, 26, 26, .9);--oc-bg-inverse: #ffffff;--oc-text-primary: #f3f4f6;--oc-text-secondary: #d1d5db;--oc-text-tertiary: #9ca3af;--oc-text-placeholder: #6b7280;--oc-text-inverse: #282828;--oc-border-primary: #282828;--oc-border-secondary: #4b5563;--oc-primary: #3b82f6;--oc-primary-hover: #2563eb;--oc-primary-bg: rgba(59, 130, 246, .15);--oc-danger: #ef4444;--oc-danger-hover: #dc2626;--oc-danger-active: #b91c1c;--oc-success: #10b981;--oc-overlay: rgba(26, 26, 26, .9);--oc-tooltip-bg: #282828;--oc-dialog-overlay: rgba(0, 0, 0, .7);--oc-skeleton-bg: #151515;--oc-skeleton-gradient: linear-gradient(90deg, #282828 25%, #4b5563 50%, #282828 75%);--oc-shadow-sm: 0 2px 4px rgba(0, 0, 0, .3);--oc-shadow-md: 0 4px 12px rgba(0, 0, 0, .4);--oc-shadow-lg: 0 8px 32px rgba(0, 0, 0, .4);--oc-shadow-xl: 0 20px 60px rgba(0, 0, 0, .6);--oc-shadow-primary: 0 2px 4px rgba(59, 130, 246, .3);--oc-shadow-primary-hover: 0 4px 6px rgba(59, 130, 246, .4);--oc-shadow-danger: 0 4px 12px rgba(239, 68, 68, .4);--oc-trigger-bg: linear-gradient(135deg, #667eea 0%, #764ba2 100%);--oc-trigger-bg-hover: linear-gradient(135deg, #764ba2 0%, #667eea 100%);--oc-trigger-bg-active: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);--oc-trigger-shadow: 0 4px 15px rgba(102, 126, 234, .5);--oc-trigger-shadow-hover: 0 6px 20px rgba(102, 126, 234, .7);--oc-trigger-shadow-active: 0 6px 20px rgba(240, 147, 251, .5)}.opencode-widget.bottom-right{bottom:20px;right:20px}.opencode-widget.bottom-left{bottom:20px;left:20px}.opencode-widget.top-right{top:20px;right:20px}.opencode-widget.top-left{top:20px;left:20px}.opencode-chat{position:absolute;width:700px;height:86vh;background:var(--oc-bg-main);border-radius:16px;box-shadow:var(--oc-shadow-lg);overflow:hidden;opacity:0;visibility:hidden;transform:translateY(20px) scale(.95);transition:all .3s ease;display:flex;flex-direction:column}.opencode-chat-content{display:flex;flex:1;overflow:hidden}.opencode-widget.bottom-right .opencode-chat{bottom:56px;right:0}.opencode-widget.bottom-left .opencode-chat{bottom:56px;left:0}.opencode-widget.top-right .opencode-chat{top:56px;right:0}.opencode-widget.top-left .opencode-chat{top:56px;left:0}.opencode-widget.bottom-right .opencode-selected-bubbles{bottom:56px;right:0}.opencode-widget.bottom-left .opencode-selected-bubbles{bottom:56px;left:0}.opencode-widget.top-right .opencode-selected-bubbles{top:56px;bottom:auto;right:0}.opencode-widget.top-left .opencode-selected-bubbles{top:56px;bottom:auto;left:0}.opencode-chat.open{opacity:1;visibility:visible;transform:translateY(0) scale(1)}.opencode-notification{position:absolute;top:20px;left:50%;transform:translate(-50%);padding:12px 24px;background:linear-gradient(135deg,#3b82f6,#2563eb);color:#fff;border-radius:10px;font-size:14px;font-weight:500;box-shadow:0 4px 16px rgba(59,130,246,.4),0 0 0 2px rgba(59,130,246,.2);animation:slideDown .3s ease;z-index:10000000;display:flex;align-items:center;gap:10px}.opencode-notification:before{content:"\1f4a1";font-size:16px}.opencode-dialog-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:var(--oc-dialog-overlay);display:flex;align-items:center;justify-content:center;z-index:9999999;animation:fadeIn .2s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.opencode-dialog{background:var(--oc-bg-main);border-radius:12px;padding:24px;min-width:320px;max-width:400px;box-shadow:var(--oc-shadow-xl);animation:scaleIn .2s ease}@keyframes scaleIn{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}.opencode-dialog-content{margin-bottom:20px}.opencode-dialog-message{font-size:15px;color:var(--oc-text-primary);line-height:1.5}.opencode-dialog-actions{display:flex;gap:12px;justify-content:flex-end}.opencode-dialog-btn{padding:10px 20px;border-radius:8px;border:none;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s}.opencode-dialog-btn.cancel{background:var(--oc-bg-tertiary);color:var(--oc-text-primary)}.opencode-dialog-btn.cancel:hover{background:var(--oc-text-primary);color:var(--oc-bg-main)}.opencode-dialog-btn.confirm{background:var(--oc-danger);color:#fff}.opencode-dialog-btn.confirm:hover{background:var(--oc-danger-hover)}@keyframes slideDown{0%{transform:translate(-50%) translateY(-100%);opacity:0}to{transform:translate(-50%) translateY(0);opacity:1}}.opencode-element-highlight{position:fixed;pointer-events:none;z-index:999998;display:none;transition:all .1s ease;border-radius:4px}#vue-inspector-container{display:none!important}.opencode-element-tooltip{position:fixed;background:var(--oc-tooltip-bg);color:#fff;padding:8px 12px;border-radius:6px;font-size:12px;z-index:9999998;display:none;box-shadow:var(--oc-shadow-md);max-width:300px;pointer-events:none}.opencode-tooltip-tag{font-weight:500;margin-bottom:4px;word-break:break-all}.opencode-tooltip-file{font-size:11px;color:var(--oc-text-placeholder);word-break:break-all}.opencode-element-highlight-temp{position:absolute;pointer-events:none;z-index:999998;border-radius:4px;animation:highlight-pulse 2s ease-out forwards}@keyframes highlight-pulse{0%{opacity:1;transform:scale(1)}50%{opacity:.8;transform:scale(1.02)}to{opacity:0;transform:scale(1)}}@media(max-width:768px){.opencode-chat{width:calc(100vw - 40px);height:calc(100vh - 100px)}}
2
2
  .opencode-iframe-container{flex:1;position:relative;overflow:hidden;display:flex;flex-direction:column;margin-top:-42px}.opencode-loading-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-overlay-bg);display:none;flex-direction:column;align-items:center;justify-content:center;z-index:10;transition:opacity .3s ease}.opencode-loading-overlay.visible{display:flex}.opencode-loading-spinner{width:40px;height:40px;border:3px solid var(--oc-border-primary);border-top-color:var(--oc-primary);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.opencode-loading-text{margin-top:12px;font-size:14px;color:var(--oc-text-placeholder)}.opencode-empty-state-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-bg-secondary);display:none;flex-direction:column;align-items:center;justify-content:center;z-index:5;transition:opacity .3s ease;margin-top:42px}.opencode-empty-state-overlay.visible{display:flex}.opencode-empty-state-icon{color:var(--oc-text-placeholder);margin-bottom:16px}.opencode-empty-state-text{color:var(--oc-text-primary);font-size:16px;font-weight:500;margin-bottom:24px}.opencode-empty-state-btn{padding:10px 24px;border-radius:8px;border:none;background:var(--oc-primary);color:#fff;font-size:14px;font-weight:500;cursor:pointer;transition:all .2s;box-shadow:var(--oc-shadow-primary)}.opencode-empty-state-btn:hover{background:var(--oc-primary-hover);transform:translateY(-1px);box-shadow:var(--oc-shadow-primary-hover)}.opencode-empty-state-btn:active{transform:translateY(0)}.opencode-iframe{width:100%;height:100%;border:none}
3
- .opencode-chat-header{position:relative;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:0 12px;height:40px;background:var(--oc-bg-secondary);border-bottom:1px solid var(--oc-border-primary);z-index:5}.opencode-chat-header-left{display:flex;align-items:center;gap:4px}.opencode-chat-header-title{font-size:14px;font-weight:600;color:var(--oc-text-primary);position:absolute;left:50%;transform:translate(-50%)}.opencode-chat-header-actions{display:flex;gap:4px}.opencode-header-btn{width:28px;height:28px;border-radius:6px;border:none;background:transparent;color:var(--oc-text-placeholder);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.opencode-header-btn:hover{background:var(--oc-bg-tertiary);color:var(--oc-text-primary)}.opencode-header-btn.close:hover{background:var(--oc-danger);color:#fff}.opencode-header-btn.select-btn.active{background:var(--oc-primary);color:#fff}
4
- .opencode-select-mode-hint{position:fixed;top:20px;left:50%;transform:translate(-50%);padding:10px 16px;background:var(--oc-danger);color:#fff;border-radius:8px;font-size:13px;box-shadow:var(--oc-shadow-danger);z-index:9999999;display:none;align-items:center;gap:12px}.opencode-select-mode-hint.visible{display:flex;animation:slideDown .3s ease}.opencode-hint-shortcut{padding:2px 6px;background:rgba(255,255,255,.2);border-radius:4px;font-size:12px}
3
+ .opencode-chat-header{position:relative;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:0 12px;height:40px;background:var(--oc-bg-secondary);border-bottom:1px solid var(--oc-border-primary);z-index:5}.opencode-chat-header-left{display:flex;align-items:center;gap:4px}.opencode-chat-header-title{font-size:14px;font-weight:600;color:var(--oc-text-primary);position:absolute;left:50%;transform:translate(-50%)}.opencode-chat-header-actions{display:flex;gap:4px}.opencode-header-btn{width:28px;height:28px;border-radius:6px;border:none;background:transparent;color:var(--oc-text-placeholder);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.opencode-header-btn:hover{background:var(--oc-bg-tertiary);color:var(--oc-text-primary)}.opencode-header-btn.close:hover{background:var(--oc-danger);color:#fff}.opencode-header-btn.select-btn.active,.opencode-header-btn.session-toggle.active{background:var(--oc-primary);color:#fff}
4
+ .opencode-select-mode-hint{position:fixed;top:20px;left:50%;transform:translate(-50%);padding:14px 20px;background:linear-gradient(135deg,#ef4444,#dc2626);color:#fff;border-radius:12px;font-size:15px;font-weight:500;box-shadow:0 6px 20px rgba(239,68,68,.5),0 0 0 3px rgba(239,68,68,.3);z-index:9999999;display:none;align-items:center;gap:12px;border:2px solid rgba(255,255,255,.3)}.opencode-select-mode-hint.visible{display:flex;animation:slideDown .3s ease,pulseHint 2s ease-in-out infinite}.opencode-hint-shortcut{padding:4px 10px;background:rgba(255,255,255,.25);border-radius:6px;font-size:13px;font-weight:600;border:1px solid rgba(255,255,255,.4)}@keyframes pulseHint{0%,to{box-shadow:0 6px 20px rgba(239,68,68,.5),0 0 0 3px rgba(239,68,68,.3)}50%{box-shadow:0 6px 20px rgba(239,68,68,.6),0 0 0 6px rgba(239,68,68,.4)}}
5
5
  .opencode-selected-bubbles{position:absolute;display:none;flex-direction:column;gap:6px;max-width:220px;max-height:300px;overflow-y:auto}.opencode-selected-bubbles.visible{display:flex}.opencode-selected-bubble{display:flex;flex-direction:column;gap:2px;padding:8px 24px 8px 10px;background:var(--oc-bg-main);border:1px solid var(--oc-border-primary);border-radius:8px;font-size:12px;box-shadow:var(--oc-shadow-sm);position:relative;cursor:pointer;transition:all .2s}.opencode-selected-bubble:hover{border-color:var(--oc-primary);box-shadow:var(--oc-shadow-primary)}.opencode-bubble-text{color:var(--oc-text-primary);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-bubble-file{color:var(--oc-text-placeholder);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-bubble-remove{position:absolute;top:8px;right:6px;width:16px;height:16px;border-radius:50%;border:none;background:transparent;color:var(--oc-text-placeholder);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px;transition:all .2s}.opencode-bubble-remove:hover{background:var(--oc-danger);color:#fff}.opencode-bubble-empty{padding:8px 12px;background:var(--oc-bg-main);border:1px dashed var(--oc-border-secondary);border-radius:8px;color:var(--oc-text-placeholder);font-size:12px;text-align:center}
6
6
  .opencode-right-toolbar{width:140px;background:var(--oc-bg-secondary);border-left:1px solid var(--oc-border-primary);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease;overflow:hidden}.opencode-right-toolbar.collapsed{width:0;overflow:hidden}.opencode-right-toolbar.collapsed .opencode-selected-nodes-header,.opencode-right-toolbar.collapsed .opencode-selected-nodes,.opencode-right-toolbar.collapsed .opencode-clear-all-btn{display:none}.opencode-selected-nodes-header{padding:12px 8px 8px;border-bottom:1px solid var(--oc-border-primary)}.opencode-selected-nodes-title{font-size:14px;font-weight:600;color:var(--oc-text-primary);margin-bottom:4px}.opencode-selected-nodes-desc{font-size:11px;color:var(--oc-text-placeholder);line-height:1.4}.opencode-selected-nodes{flex:1;display:flex;flex-direction:column;padding:8px;gap:6px;overflow-y:auto;overflow-x:hidden}.opencode-selected-nodes:empty:before{content:"\6682\65e0\9009\4e2d\5143\7d20";color:var(--oc-text-placeholder);font-size:12px;text-align:center;padding:20px 10px}.opencode-selected-node{display:flex;align-items:center;gap:8px;padding:8px 10px;background:var(--oc-bg-main);border:1px solid var(--oc-border-primary);border-radius:6px;font-size:12px;transition:all .2s}.opencode-selected-node:hover{border-color:var(--oc-primary);box-shadow:var(--oc-shadow-primary)}.opencode-node-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.opencode-node-text{color:var(--oc-text-primary);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-node-file{color:var(--oc-text-placeholder);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-node-remove{width:18px;height:18px;border-radius:4px;border:none;background:transparent;color:var(--oc-text-placeholder);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px;transition:all .2s;flex-shrink:0}.opencode-node-remove:hover{background:var(--oc-danger);color:#fff}.opencode-clear-all-btn{width:calc(100% - 16px);margin:8px;padding:8px 12px;border-radius:6px;border:none;background:var(--oc-danger);color:#fff;font-size:12px;font-weight:500;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:4px;transition:all .2s}.opencode-clear-all-btn:hover{background:var(--oc-danger-hover);transform:scale(1.02)}
7
- .opencode-session-list{width:240px;background:var(--oc-bg-secondary);border-right:1px solid var(--oc-border-primary);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease}.opencode-session-list.collapsed{width:0;overflow:hidden}.opencode-session-list.collapsed .opencode-session-list-header,.opencode-session-list.collapsed .opencode-session-list-content{display:none}.opencode-session-list-header{padding:16px;border-bottom:1px solid var(--oc-border-primary);display:flex;justify-content:space-between;align-items:center;font-weight:600;font-size:14px;color:var(--oc-text-primary)}.opencode-new-session-btn{width:28px;height:28px;border-radius:6px;border:none;background:var(--oc-primary);color:#fff;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.opencode-new-session-btn:hover{background:var(--oc-primary-hover);transform:scale(1.05)}.opencode-session-list-content{flex:1;overflow-y:auto;padding:8px;position:relative}.opencode-session-list-loading-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-overlay-bg);display:flex;align-items:center;justify-content:center;z-index:10;border-radius:8px}.opencode-loading-spinner.small{width:24px;height:24px;border-width:2px}.opencode-session-item{padding:12px;border-radius:8px;cursor:pointer;transition:all .2s;margin-bottom:4px;color:var(--oc-text-primary)}.opencode-session-item:hover{background:var(--oc-bg-tertiary)}.opencode-session-item.active{background:var(--oc-primary);color:#fff}.opencode-session-title{font-size:14px;font-weight:500;margin-bottom:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-session-meta{font-size:12px;opacity:.6}.opencode-session-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.opencode-session-delete-btn{width:20px;height:20px;border-radius:4px;border:none;background:transparent;color:var(--oc-text-placeholder);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;opacity:0;flex-shrink:0}.opencode-session-item:hover .opencode-session-delete-btn{opacity:1}.opencode-session-delete-btn:hover{background:var(--oc-danger);color:#fff}.opencode-session-item.active .opencode-session-delete-btn{color:rgba(255,255,255,.7)}.opencode-session-item.active .opencode-session-delete-btn:hover{background:rgba(255,255,255,.2);color:#fff}.opencode-session-header-skeleton{padding:16px;border-bottom:1px solid var(--oc-border-primary);display:none;justify-content:space-between;align-items:center}.opencode-session-header-skeleton.visible{display:flex}.opencode-skeleton-header-title{height:18px;width:80px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.opencode-skeleton-header-btn{width:28px;height:28px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:6px}.opencode-session-skeleton{flex:1;overflow-y:auto;padding:8px;display:none}.opencode-session-skeleton.visible{display:block}.opencode-skeleton-item{padding:12px;border-radius:8px;margin-bottom:4px;background:var(--oc-skeleton-bg)}.opencode-skeleton-title{height:16px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px;margin-bottom:8px;width:70%}.opencode-skeleton-meta{height:12px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px;width:50%}.opencode-session-empty{padding:32px 16px;text-align:center;color:var(--oc-text-placeholder);font-size:13px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}
7
+ .opencode-session-list{width:240px;background:var(--oc-bg-secondary);border-right:1px solid var(--oc-border-primary);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease}.opencode-session-list.collapsed{width:0;overflow:hidden}.opencode-session-list.collapsed .opencode-session-list-header,.opencode-session-list.collapsed .opencode-session-list-content{display:none}.opencode-session-list-header{padding:16px;border-bottom:1px solid var(--oc-border-primary);display:flex;justify-content:space-between;align-items:center;font-weight:600;font-size:14px;color:var(--oc-text-primary)}.opencode-new-session-btn{width:28px;height:28px;border-radius:6px;border:none;background:var(--oc-primary);color:#fff;font-size:18px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}.opencode-new-session-btn:hover{background:var(--oc-primary-hover);transform:scale(1.05)}.opencode-session-list-content{flex:1;overflow-y:auto;padding:8px;position:relative}.opencode-session-list-loading-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--oc-overlay-bg);display:flex;align-items:center;justify-content:center;z-index:10;border-radius:8px}.opencode-loading-spinner.small{width:24px;height:24px;border-width:2px}.opencode-session-item{padding:12px;border-radius:8px;cursor:pointer;transition:transform .2s;margin-bottom:4px;color:var(--oc-text-primary)}.opencode-session-item:hover{background:var(--oc-bg-tertiary)}.opencode-session-item.active{background:var(--oc-primary);color:#fff;transition:none}.opencode-session-title{font-size:14px;font-weight:500;margin-bottom:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.opencode-session-meta{font-size:12px;opacity:.6}.opencode-session-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.opencode-session-delete-btn{width:20px;height:20px;border-radius:4px;border:none;background:transparent;color:var(--oc-text-placeholder);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s;opacity:0;flex-shrink:0}.opencode-session-item:hover .opencode-session-delete-btn{opacity:1}.opencode-session-delete-btn:hover{background:var(--oc-danger);color:#fff}.opencode-session-item.active .opencode-session-delete-btn{color:rgba(255,255,255,.7)}.opencode-session-item.active .opencode-session-delete-btn:hover{background:rgba(255,255,255,.2);color:#fff}.opencode-session-header-skeleton{padding:16px;border-bottom:1px solid var(--oc-border-primary);display:none;justify-content:space-between;align-items:center}.opencode-session-header-skeleton.visible{display:flex}.opencode-skeleton-header-title{height:18px;width:80px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.opencode-skeleton-header-btn{width:28px;height:28px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:6px}.opencode-session-skeleton{flex:1;overflow-y:auto;padding:8px;display:none}.opencode-session-skeleton.visible{display:block}.opencode-skeleton-item{padding:12px;border-radius:8px;margin-bottom:4px;background:var(--oc-skeleton-bg)}.opencode-skeleton-title{height:16px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px;margin-bottom:8px;width:70%}.opencode-skeleton-meta{height:12px;background:var(--oc-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px;width:50%}.opencode-session-empty{padding:32px 16px;text-align:center;color:var(--oc-text-placeholder);font-size:13px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}
8
8
  .opencode-button{width:44px;height:44px;border-radius:50%;background:var(--oc-trigger-bg);border:none;cursor:pointer;box-shadow:var(--oc-trigger-shadow);transition:all .3s ease;display:flex;align-items:center;justify-content:center;color:#fff;padding:0;position:relative}.opencode-button:before{content:"";position:absolute;top:-8px;left:-8px;right:-8px;bottom:-8px;border-radius:50%}.opencode-button:hover{transform:scale(1.1);box-shadow:var(--oc-trigger-shadow-hover);background:var(--oc-trigger-bg-hover)}.opencode-button.active{background:var(--oc-trigger-bg-active);box-shadow:var(--oc-trigger-shadow-active)}.opencode-button.active svg{transform:rotate(180deg)}.opencode-button svg{transition:transform .3s ease}.opencode-button.loading{animation:pulse 1s infinite}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}
9
9
  /*$vite$:1*/
package/lib/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.11";
3
+ declare const version = "1.0.13";
4
4
  declare function install(app: App<any>, options?: any): void;
5
5
  export { install, version, OpenCodeWidget };
6
6
  export default install;
package/lib/index.js CHANGED
@@ -34,7 +34,7 @@ __export(lib_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(lib_exports);
36
36
  var import_open_code_widget = __toESM(require("./open-code-widget"));
37
- const version = "1.0.11";
37
+ const version = "1.0.13";
38
38
  function install(app, options) {
39
39
  const components = [
40
40
  import_open_code_widget.default
@@ -54,6 +54,32 @@ function getElementDescription(element) {
54
54
  if (href && href !== "#") parts.push(`[href]`);
55
55
  return parts.join("");
56
56
  }
57
+ function getPreciseElementAtPoint(x, y, boundary) {
58
+ var _a, _b;
59
+ const highlight = document.querySelector(".opencode-element-highlight");
60
+ const tooltip = document.querySelector(".opencode-element-tooltip");
61
+ const highlightDisplay = ((_a = highlight == null ? void 0 : highlight.getAttribute("style")) == null ? void 0 : _a.includes("display: block")) ? "block" : "none";
62
+ const tooltipDisplay = ((_b = tooltip == null ? void 0 : tooltip.getAttribute("style")) == null ? void 0 : _b.includes("display: block")) ? "block" : "none";
63
+ if (highlight) highlight.style.display = "none";
64
+ if (tooltip) tooltip.style.display = "none";
65
+ let element = null;
66
+ try {
67
+ const elements = document.elementsFromPoint(x, y);
68
+ for (const el of elements) {
69
+ if (el.closest("#vue-inspector-container")) continue;
70
+ if (el.closest(".opencode-widget")) continue;
71
+ if (el.hasAttribute("data-v-inspector-ignore")) continue;
72
+ if (boundary.contains(el) || el === boundary) {
73
+ element = el;
74
+ break;
75
+ }
76
+ }
77
+ } finally {
78
+ if (highlight) highlight.style.display = highlightDisplay;
79
+ if (tooltip) tooltip.style.display = tooltipDisplay;
80
+ }
81
+ return element;
82
+ }
57
83
  function useInspector(options) {
58
84
  const highlightVisible = (0, import_vue.ref)(false);
59
85
  const highlightStyle = (0, import_vue.ref)({
@@ -73,7 +99,9 @@ function useInspector(options) {
73
99
  if (!inspector) return;
74
100
  const { targetNode, params } = inspector.getTargetNode(e);
75
101
  if (targetNode && params) {
76
- const rect = targetNode.getBoundingClientRect();
102
+ const preciseElement = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode);
103
+ const elementToHighlight = preciseElement || targetNode;
104
+ const rect = elementToHighlight.getBoundingClientRect();
77
105
  const widget = document.querySelector(".opencode-widget");
78
106
  let primary = "#3b82f6";
79
107
  let primaryBg = "rgba(59, 130, 246, 0.1)";
@@ -91,7 +119,7 @@ function useInspector(options) {
91
119
  border: `2px solid ${primary}`,
92
120
  background: primaryBg
93
121
  };
94
- const description = getElementDescription(targetNode);
122
+ const description = getElementDescription(elementToHighlight);
95
123
  const fileName = params.file ? params.file.split("/").pop() : "";
96
124
  let lineInfo = "";
97
125
  if (params.line) {
@@ -133,8 +161,10 @@ function useInspector(options) {
133
161
  if (options.selectMode.value) {
134
162
  const { targetNode, params } = inspector.getTargetNode(e);
135
163
  if (targetNode && params) {
136
- const innerText = getDirectText(targetNode);
137
- const description = getElementDescription(targetNode);
164
+ const preciseElement = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode);
165
+ const elementToSelect = preciseElement || targetNode;
166
+ const innerText = getDirectText(elementToSelect);
167
+ const description = getElementDescription(elementToSelect);
138
168
  const elementInfo = {
139
169
  filePath: (_a = params.file) != null ? _a : null,
140
170
  line: (_b = params.line) != null ? _b : null,