@aipanel/ui 1.3.7 → 1.3.9

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.
@@ -7,6 +7,7 @@ interface UseInspectorOptions {
7
7
  }
8
8
  export declare function useInspector(options: UseInspectorOptions): {
9
9
  highlightVisible: Ref<boolean, boolean>;
10
+ highlightBreathing: Ref<boolean, boolean>;
10
11
  highlightStyle: Ref<Record<string, string>, Record<string, string>>;
11
12
  tooltipVisible: Ref<boolean, boolean>;
12
13
  tooltipStyle: Ref<{
@@ -29,5 +30,6 @@ export declare function useInspector(options: UseInspectorOptions): {
29
30
  description: string;
30
31
  fileInfo: string;
31
32
  }>;
33
+ flashElement: (target: Element) => void;
32
34
  };
33
35
  export {};
@@ -1,6 +1,7 @@
1
1
  import { ref, watch, onMounted, onUnmounted, nextTick } from "vue";
2
2
  import {
3
3
  INSPECTOR_CHECK_INTERVAL,
4
+ fileNameOf,
4
5
  listInspectorAdapters,
5
6
  resolveInspectorAdapter,
6
7
  truncate
@@ -107,6 +108,7 @@ function getTargetElement(e) {
107
108
  }
108
109
  function useInspector(options) {
109
110
  const highlightVisible = ref(false);
111
+ const highlightBreathing = ref(false);
110
112
  const highlightStyle = ref({
111
113
  top: "0px",
112
114
  left: "0px",
@@ -117,8 +119,61 @@ function useInspector(options) {
117
119
  const tooltipStyle = ref({ top: "0px", left: "0px" });
118
120
  const tooltipContent = ref({ description: "", fileInfo: "" });
119
121
  let inspectorCheckTimer = null;
122
+ let breathTimer = null;
123
+ let followTarget = null;
120
124
  let currentPrimary = "#4176e6";
121
125
  let currentPrimaryBg = "rgba(65, 118, 230, 0.1)";
126
+ function positionHighlight(target) {
127
+ const widget = document.querySelector(".aipanel-widget");
128
+ if (widget) {
129
+ const style = getComputedStyle(widget);
130
+ currentPrimary = style.getPropertyValue("--ap-accent").trim() || currentPrimary;
131
+ currentPrimaryBg = style.getPropertyValue("--ap-accent-bg").trim() || currentPrimaryBg;
132
+ }
133
+ const rect = target.getBoundingClientRect();
134
+ const next = {
135
+ top: `${rect.top}px`,
136
+ left: `${rect.left}px`,
137
+ width: `${rect.width}px`,
138
+ height: `${rect.height}px`,
139
+ border: `2px solid ${currentPrimary}`,
140
+ background: currentPrimaryBg
141
+ };
142
+ const current = highlightStyle.value;
143
+ const moved = current.top !== next.top || current.left !== next.left || current.width !== next.width || current.height !== next.height || current.border !== next.border;
144
+ if (!moved) return;
145
+ highlightStyle.value = next;
146
+ }
147
+ function handleViewportChange() {
148
+ if (followTarget) positionHighlight(followTarget);
149
+ }
150
+ function startFollowing(target) {
151
+ stopFollowing();
152
+ followTarget = target;
153
+ window.addEventListener("scroll", handleViewportChange, { passive: true, capture: true });
154
+ window.addEventListener("resize", handleViewportChange, { passive: true });
155
+ }
156
+ function stopFollowing() {
157
+ if (followTarget) {
158
+ window.removeEventListener("scroll", handleViewportChange, true);
159
+ window.removeEventListener("resize", handleViewportChange);
160
+ }
161
+ followTarget = null;
162
+ }
163
+ function flashElement(target) {
164
+ target.scrollIntoView({ block: "center" });
165
+ positionHighlight(target);
166
+ highlightVisible.value = true;
167
+ highlightBreathing.value = true;
168
+ startFollowing(target);
169
+ if (breathTimer !== null) window.clearTimeout(breathTimer);
170
+ breathTimer = window.setTimeout(() => {
171
+ breathTimer = null;
172
+ stopFollowing();
173
+ highlightBreathing.value = false;
174
+ highlightVisible.value = false;
175
+ }, 4e3);
176
+ }
122
177
  function setPointerEventsNone(elements) {
123
178
  elements.forEach((el) => {
124
179
  if (el) el.style.pointerEvents = "none";
@@ -141,14 +196,9 @@ function useInspector(options) {
141
196
  const fileInfo = resolveElementSourceLocation(elementToHighlight);
142
197
  setPointerEventsAuto(uiElements);
143
198
  if (elementToHighlight) {
144
- const widget = document.querySelector(".aipanel-widget");
145
- if (widget) {
146
- const style = getComputedStyle(widget);
147
- currentPrimary = style.getPropertyValue("--ap-accent").trim() || currentPrimary;
148
- currentPrimaryBg = style.getPropertyValue("--ap-accent-bg").trim() || currentPrimaryBg;
149
- }
199
+ positionHighlight(elementToHighlight);
150
200
  const description = getElementDescription(elementToHighlight);
151
- const fileName = fileInfo?.file ? fileInfo.file.split("/").pop() : "";
201
+ const fileName = fileInfo?.file ? fileNameOf(fileInfo.file) : "";
152
202
  let lineInfo = "";
153
203
  if (fileInfo?.line) {
154
204
  lineInfo = `:${fileInfo.line}`;
@@ -161,21 +211,6 @@ function useInspector(options) {
161
211
  description,
162
212
  fileInfo: fileInfoText
163
213
  };
164
- const rect = elementToHighlight.getBoundingClientRect();
165
- const newTop = `${rect.top}px`;
166
- const newLeft = `${rect.left}px`;
167
- const newWidth = `${rect.width}px`;
168
- const newHeight = `${rect.height}px`;
169
- if (highlightStyle.value.top !== newTop || highlightStyle.value.left !== newLeft || highlightStyle.value.width !== newWidth || highlightStyle.value.height !== newHeight) {
170
- highlightStyle.value = {
171
- top: newTop,
172
- left: newLeft,
173
- width: newWidth,
174
- height: newHeight,
175
- border: `2px solid ${currentPrimary}`,
176
- background: currentPrimaryBg
177
- };
178
- }
179
214
  highlightVisible.value = true;
180
215
  tooltipVisible.value = true;
181
216
  void nextTick(() => {
@@ -184,6 +219,7 @@ function useInspector(options) {
184
219
  const tooltipWidth = tooltipEl.offsetWidth;
185
220
  const tooltipHeight = tooltipEl.offsetHeight;
186
221
  if (tooltipWidth === 0 || tooltipHeight === 0) return;
222
+ const rect = elementToHighlight.getBoundingClientRect();
187
223
  const margin = 10;
188
224
  const gap = 4;
189
225
  const viewportWidth = window.innerWidth;
@@ -294,6 +330,7 @@ function useInspector(options) {
294
330
  watch(options.selectMode, (newVal) => {
295
331
  resolveInspectorAdapter()?.setEnabled(newVal);
296
332
  if (newVal) {
333
+ stopFollowing();
297
334
  document.addEventListener("mousemove", handleMouseMove);
298
335
  document.addEventListener("keydown", handleKeydown, true);
299
336
  } else {
@@ -317,15 +354,22 @@ function useInspector(options) {
317
354
  if (inspectorCheckTimer) {
318
355
  window.clearInterval(inspectorCheckTimer);
319
356
  }
357
+ if (breathTimer !== null) {
358
+ window.clearTimeout(breathTimer);
359
+ breathTimer = null;
360
+ }
361
+ stopFollowing();
320
362
  document.removeEventListener("mousemove", handleMouseMove);
321
363
  document.removeEventListener("keydown", handleKeydown, true);
322
364
  });
323
365
  return {
324
366
  highlightVisible,
367
+ highlightBreathing,
325
368
  highlightStyle,
326
369
  tooltipVisible,
327
370
  tooltipStyle,
328
- tooltipContent
371
+ tooltipContent,
372
+ flashElement
329
373
  };
330
374
  }
331
375
  export {
@@ -7,13 +7,26 @@ export interface UseSelectionOptions {
7
7
  onRemoveSelectedNode: (payload: AIPanelRemoveSelectedPayload) => void;
8
8
  onClearSelectedNodes: () => void;
9
9
  showConfirmDialog: (message: string) => Promise<boolean>;
10
+ /**
11
+ * 是否在页面内定位(默认 true;可传 getter,显示模式运行时可变)。
12
+ * 扩展模式下挂件在侧栏、页面不在本上下文,置 false 以免去操作侧栏自身的 document。
13
+ */
14
+ locateInPage?: boolean | (() => boolean);
15
+ /** 高亮元素:复用选择模式的高亮框闪烁(由挂件的 inspector 提供) */
16
+ flashHighlight?: (element: Element) => void;
17
+ /** 跳转到目标页(默认 window.location.assign;测试可注入) */
18
+ navigate?: (url: string) => void;
19
+ /** 轻提示(定位失败时给出原因) */
20
+ notify?: (message: string) => void;
10
21
  }
11
22
  export declare function useSelection(options: UseSelectionOptions): {
12
23
  bubbleVisible: import("vue").ComputedRef<boolean>;
13
24
  hasSelectedElements: import("vue").ComputedRef<boolean>;
14
25
  selectedElementItems: import("vue").ComputedRef<AIPanelSelectedElementItem[]>;
26
+ consumePendingLocate: () => Promise<void>;
15
27
  handleClearSelectedNodes: () => Promise<void>;
16
28
  handleClickSelectedNode: (item: AIPanelSelectedElementItem) => void;
29
+ handleLocateSelectedElement: (element: AIPanelSelectedElement) => void;
17
30
  handleRemoveSelectedNode: (item: AIPanelSelectedElementItem, index: number, source: AIPanelRemoveSelectedPayload["source"]) => void;
18
31
  handleToggleSelectMode: () => void;
19
32
  };
@@ -1,24 +1,66 @@
1
1
  import { computed } from "vue";
2
- import { truncate } from "@aipanel/core";
2
+ import { fileNameOf, sleep, truncate } from "@aipanel/core";
3
3
  function getElementKey(element, index) {
4
4
  if (element.filePath && element.line) {
5
5
  return `${element.filePath}:${element.line}:${element.column ?? 0}`;
6
6
  }
7
7
  return `${element.description}-${index}`;
8
8
  }
9
+ function takePendingLocate() {
10
+ try {
11
+ const selector = sessionStorage.getItem("__aipanel_pending_locate__");
12
+ sessionStorage.removeItem("__aipanel_pending_locate__");
13
+ return selector || null;
14
+ } catch {
15
+ return null;
16
+ }
17
+ }
18
+ function stashPendingLocate(selector) {
19
+ try {
20
+ sessionStorage.setItem("__aipanel_pending_locate__", selector);
21
+ } catch {
22
+ }
23
+ }
24
+ function isDifferentPage(a, b) {
25
+ try {
26
+ return new URL(a, window.location.href).href !== new URL(b, window.location.href).href;
27
+ } catch {
28
+ return a !== b;
29
+ }
30
+ }
31
+ function isHashOnlyChange(a, b) {
32
+ try {
33
+ const next = new URL(a, window.location.href);
34
+ const current = new URL(b, window.location.href);
35
+ return next.origin === current.origin && next.pathname === current.pathname && next.search === current.search;
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+ function queryPageElement(selector) {
41
+ try {
42
+ return document.querySelector(selector);
43
+ } catch {
44
+ return null;
45
+ }
46
+ }
9
47
  function getBubbleFileText(element) {
10
- const fileName = element.filePath?.split("/").pop() || "";
48
+ const fileName = element.filePath ? fileNameOf(element.filePath) : "";
11
49
  const lineInfo = element.line ? `:${element.line}${element.column ? `:${element.column}` : ""}` : "";
12
50
  return `${fileName}${lineInfo}`;
13
51
  }
14
52
  function getPanelFileText(element) {
15
- const fileName = element.filePath?.split("/").pop() || "\u672A\u77E5\u6587\u4EF6";
53
+ const fileName = element.filePath && fileNameOf(element.filePath) || "\u672A\u77E5\u6587\u4EF6";
16
54
  const lineInfo = element.line ? `:${element.line}${element.column ? `:${element.column}` : ""}` : "";
17
55
  const textPreview = element.innerText?.trim() ? `${truncate(element.innerText.trim(), 30)} \xB7 ` : "";
18
56
  return `${textPreview}${fileName}${lineInfo}`;
19
57
  }
20
58
  function useSelection(options) {
21
59
  const bubbleVisible = computed(() => options.selectMode.value);
60
+ function shouldLocateInPage() {
61
+ const value = options.locateInPage;
62
+ return typeof value === "function" ? value() : value !== false;
63
+ }
22
64
  const selectedElementItems = computed(
23
65
  () => (options.selectedElements.value || []).map(
24
66
  (element, index) => ({
@@ -34,57 +76,49 @@ function useSelection(options) {
34
76
  function handleToggleSelectMode() {
35
77
  options.onToggleSelectMode(!options.selectMode.value);
36
78
  }
37
- function handleClickSelectedNode(item) {
38
- const description = item.element.description;
39
- if (!description) return;
40
- let targetElement = null;
41
- if (description.includes("#")) {
42
- const idMatch = description.match(/#([^.[\s]+)/);
43
- if (idMatch) {
44
- targetElement = document.getElementById(idMatch[1]);
79
+ function handleLocateSelectedElement(element) {
80
+ if (!shouldLocateInPage()) return;
81
+ const selector = element.description?.trim();
82
+ if (!selector) return;
83
+ const navigate = options.navigate ?? ((to) => window.location.assign(to));
84
+ const url = element.previewPageUrl;
85
+ if (url && isDifferentPage(url, window.location.href)) {
86
+ if (isHashOnlyChange(url, window.location.href)) {
87
+ navigate(url);
88
+ void flashWhenRendered(selector);
89
+ return;
45
90
  }
91
+ stashPendingLocate(selector);
92
+ navigate(url);
93
+ return;
46
94
  }
47
- if (!targetElement && description.includes(".")) {
48
- const classMatch = description.match(/^([a-z]+)\.([^[\s]+)/i);
49
- if (classMatch) {
50
- const tagName = classMatch[1];
51
- const classes = classMatch[2].split(".").filter(Boolean);
52
- const selector = `${tagName}.${classes.join(".")}`;
53
- targetElement = document.querySelector(selector);
54
- }
55
- }
56
- if (!targetElement) {
57
- const tagMatch = description.match(/^([a-z]+)/i);
58
- if (tagMatch) {
59
- const simpleSelector = description.split(/[.[\s]/)[0];
60
- targetElement = document.querySelector(simpleSelector);
61
- }
95
+ const target = queryPageElement(selector);
96
+ if (!target) {
97
+ options.notify?.("\u672A\u627E\u5230\u8BE5\u8282\u70B9\uFF0C\u9875\u9762\u53EF\u80FD\u5DF2\u53D8\u5316");
98
+ return;
62
99
  }
63
- if (targetElement) {
64
- targetElement.scrollIntoView({ behavior: "smooth", block: "center" });
65
- const highlightOverlay = document.createElement("div");
66
- highlightOverlay.className = "aipanel-element-highlight-temp";
67
- const widget = document.querySelector(".aipanel-widget");
68
- let primary = "#4176e6";
69
- let primaryBg = "rgba(65, 118, 230, 0.1)";
70
- if (widget) {
71
- const style = getComputedStyle(widget);
72
- primary = style.getPropertyValue("--ap-accent").trim() || primary;
73
- primaryBg = style.getPropertyValue("--ap-accent-bg").trim() || primaryBg;
100
+ options.flashHighlight?.(target);
101
+ }
102
+ function handleClickSelectedNode(item) {
103
+ handleLocateSelectedElement(item.element);
104
+ }
105
+ async function flashWhenRendered(selector) {
106
+ const deadline = Date.now() + 2e3;
107
+ for (; ; ) {
108
+ const target = queryPageElement(selector);
109
+ if (target) {
110
+ options.flashHighlight?.(target);
111
+ return true;
74
112
  }
75
- highlightOverlay.style.border = `2px solid ${primary}`;
76
- highlightOverlay.style.background = primaryBg;
77
- const rect = targetElement.getBoundingClientRect();
78
- highlightOverlay.style.top = `${rect.top + window.scrollY}px`;
79
- highlightOverlay.style.left = `${rect.left + window.scrollX}px`;
80
- highlightOverlay.style.width = `${rect.width}px`;
81
- highlightOverlay.style.height = `${rect.height}px`;
82
- document.body.appendChild(highlightOverlay);
83
- setTimeout(() => {
84
- highlightOverlay.remove();
85
- }, 2e3);
113
+ if (Date.now() >= deadline) return false;
114
+ await sleep(50);
86
115
  }
87
116
  }
117
+ async function consumePendingLocate() {
118
+ if (!shouldLocateInPage()) return;
119
+ const selector = takePendingLocate();
120
+ if (selector) await flashWhenRendered(selector);
121
+ }
88
122
  function handleRemoveSelectedNode(item, index, source) {
89
123
  options.onRemoveSelectedNode({ element: item.element, index, source });
90
124
  }
@@ -101,8 +135,10 @@ function useSelection(options) {
101
135
  bubbleVisible,
102
136
  hasSelectedElements,
103
137
  selectedElementItems,
138
+ consumePendingLocate,
104
139
  handleClearSelectedNodes,
105
140
  handleClickSelectedNode,
141
+ handleLocateSelectedElement,
106
142
  handleRemoveSelectedNode,
107
143
  handleToggleSelectMode
108
144
  };
@@ -1 +1 @@
1
- .aipanel-session-list{width:236px;background:var(--ap-bg-secondary);border-right:1px solid var(--ap-border-faint);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease}.aipanel-session-list.collapsed{width:0;overflow:hidden}.aipanel-session-list.collapsed .aipanel-session-list-header,.aipanel-session-list.collapsed .aipanel-session-list-content{display:none}.aipanel-session-list-header{padding:10px 8px 8px 12px;display:flex;align-items:center;justify-content:space-between;gap:8px;background:var(--ap-bg-secondary);border-bottom:1px solid var(--ap-border-faint)}.aipanel-session-list-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:600;letter-spacing:.02em;line-height:18px;color:var(--ap-text-tertiary)}.aipanel-new-session-btn{flex:none;width:24px;height:24px;border-radius:50%;border:1px solid var(--ap-border-secondary);background:var(--ap-elevated-fill);color:var(--ap-text-primary);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease,border-color .2s ease,color .2s ease}.aipanel-new-session-btn svg{display:block}.aipanel-new-session-btn:hover{background:var(--ap-elevated-hover);color:var(--ap-text-primary)}.aipanel-new-session-btn:active{background:var(--ap-press-bg)}.aipanel-new-session-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--ap-accent-bg)}.aipanel-session-list-content{flex:1;min-height:0;overflow-y:auto;padding:8px;position:relative;display:flex;flex-direction:column;gap:2px}.aipanel-session-item{position:relative;box-sizing:border-box;display:flex;align-items:center;gap:8px;height:32px;padding:0 8px;border-radius:8px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;color:var(--ap-text-primary);transition:background-color .15s ease}.aipanel-session-item:hover{background:var(--ap-hover-bg)}.aipanel-session-item:active{background:var(--ap-press-bg)}.aipanel-session-item.active{background:var(--ap-hover-bg)}.aipanel-session-title-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:400;line-height:20px}.aipanel-session-meta{flex:none;margin-left:auto;font-size:12px;line-height:20px;color:var(--ap-text-tertiary);white-space:nowrap;transition:opacity .15s ease}.aipanel-session-item:hover .aipanel-session-meta{opacity:0}.aipanel-session-delete-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:16px;height:16px;border:none;border-radius:4px;background:transparent;color:var(--ap-text-tertiary);font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s ease,background-color .15s ease,color .15s ease}.aipanel-session-item:hover .aipanel-session-delete-btn{opacity:1}.aipanel-session-delete-btn:hover{background:transparent;color:var(--ap-text-primary)}.aipanel-session-state{position:relative;flex:none;width:10px;height:10px;margin-right:-2px}.aipanel-session-state-pending:before,.aipanel-session-state-completed:before{content:"";position:absolute;inset:0;border-radius:50%;background:currentColor;opacity:.1}.aipanel-session-state-pending:after,.aipanel-session-state-completed:after{content:"";position:absolute;inset:20%;border-radius:50%;background:currentColor}.aipanel-session-state-pending{color:var(--ap-state-pending)}.aipanel-session-state-completed{color:var(--ap-state-completed)}.aipanel-session-state-ongoing{color:var(--ap-state-ongoing)}.aipanel-session-ongoing-cell{fill:currentColor;opacity:.15;animation:aipanel-ongoing-chase 1s infinite}@keyframes aipanel-ongoing-chase{0%,12.4%{opacity:1}12.5%,24.9%{opacity:.6}25%,37.4%{opacity:.35}37.5%,to{opacity:.15}}.aipanel-session-item.active .aipanel-session-state-pending{color:var(--ap-state-pending)}.aipanel-session-item.active .aipanel-session-state-completed{color:var(--ap-state-completed)}.aipanel-session-item.active .aipanel-session-state-ongoing{color:var(--ap-accent)}.aipanel-session-header-skeleton{padding:10px 12px 8px;border-bottom:1px solid var(--ap-border-faint);display:none;align-items:center;gap:8px}.aipanel-session-header-skeleton.visible{display:flex}.aipanel-skeleton-header-title{flex:1;height:12px;width:48px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-skeleton-header-btn{width:24px;height:24px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:50%}.aipanel-session-skeleton{flex:1;min-height:0;overflow-y:auto;padding:8px;display:none}.aipanel-session-skeleton.visible{display:block}.aipanel-skeleton-item{display:flex;align-items:center;gap:8px;height:32px;box-sizing:border-box;padding:0 8px;border-radius:8px;margin-bottom:2px;background:var(--ap-skeleton-bg)}.aipanel-skeleton-title{flex:1 1 auto;height:13px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-skeleton-meta{flex:none;width:32px;height:12px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-session-empty{padding:32px 16px;text-align:center;color:var(--ap-text-tertiary);font-size:12px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}
1
+ .aipanel-session-list{width:236px;background:var(--ap-bg-secondary);border-right:1px solid var(--ap-border-faint);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease}.aipanel-session-list.collapsed{width:0;overflow:hidden}.aipanel-session-list.collapsed .aipanel-session-list-header,.aipanel-session-list.collapsed .aipanel-session-list-content{display:none}.aipanel-session-list-header{padding:10px 8px 8px 12px;display:flex;align-items:center;justify-content:space-between;gap:8px;background:var(--ap-bg-secondary);border-bottom:1px solid var(--ap-border-faint)}.aipanel-session-list-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:600;letter-spacing:.02em;line-height:18px;color:var(--ap-text-tertiary)}.aipanel-new-session-btn{flex:none;width:24px;height:24px;border-radius:50%;border:1px solid var(--ap-border-secondary);background:var(--ap-elevated-fill);color:var(--ap-text-primary);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease,border-color .2s ease,color .2s ease}.aipanel-new-session-btn svg{display:block}.aipanel-new-session-btn:hover{background:var(--ap-elevated-hover);color:var(--ap-text-primary)}.aipanel-new-session-btn:active{background:var(--ap-press-bg)}.aipanel-new-session-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--ap-accent-bg)}.aipanel-session-list-content{flex:1;min-height:0;overflow-y:auto;padding:8px;position:relative;display:flex;flex-direction:column;gap:2px}.aipanel-session-item{position:relative;box-sizing:border-box;display:flex;align-items:center;gap:8px;flex:none;height:32px;padding:0 8px;border-radius:8px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;color:var(--ap-text-primary);transition:background-color .15s ease}.aipanel-session-item:hover{background:var(--ap-hover-bg)}.aipanel-session-item:active{background:var(--ap-press-bg)}.aipanel-session-item.active{background:var(--ap-hover-bg)}.aipanel-session-title-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:400;line-height:20px}.aipanel-session-meta{flex:none;margin-left:auto;font-size:12px;line-height:20px;color:var(--ap-text-tertiary);white-space:nowrap;transition:opacity .15s ease}.aipanel-session-item:hover .aipanel-session-meta{opacity:0}.aipanel-session-delete-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:16px;height:16px;border:none;border-radius:4px;background:transparent;color:var(--ap-text-tertiary);font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s ease,background-color .15s ease,color .15s ease}.aipanel-session-item:hover .aipanel-session-delete-btn{opacity:1}.aipanel-session-delete-btn:hover{background:transparent;color:var(--ap-text-primary)}.aipanel-session-state{position:relative;flex:none;width:10px;height:10px;margin-right:-2px}.aipanel-session-state-pending:before,.aipanel-session-state-completed:before{content:"";position:absolute;inset:0;border-radius:50%;background:currentColor;opacity:.1}.aipanel-session-state-pending:after,.aipanel-session-state-completed:after{content:"";position:absolute;inset:20%;border-radius:50%;background:currentColor}.aipanel-session-state-pending{color:var(--ap-state-pending)}.aipanel-session-state-completed{color:var(--ap-state-completed)}.aipanel-session-state-ongoing{color:var(--ap-state-ongoing)}.aipanel-session-ongoing-cell{fill:currentColor;opacity:.15;animation:aipanel-ongoing-chase 1s infinite}@keyframes aipanel-ongoing-chase{0%,12.4%{opacity:1}12.5%,24.9%{opacity:.6}25%,37.4%{opacity:.35}37.5%,to{opacity:.15}}.aipanel-session-item.active .aipanel-session-state-pending{color:var(--ap-state-pending)}.aipanel-session-item.active .aipanel-session-state-completed{color:var(--ap-state-completed)}.aipanel-session-item.active .aipanel-session-state-ongoing{color:var(--ap-accent)}.aipanel-session-header-skeleton{padding:10px 12px 8px;border-bottom:1px solid var(--ap-border-faint);display:none;align-items:center;gap:8px}.aipanel-session-header-skeleton.visible{display:flex}.aipanel-skeleton-header-title{flex:1;height:12px;width:48px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-skeleton-header-btn{width:24px;height:24px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:50%}.aipanel-session-skeleton{flex:1;min-height:0;overflow-y:auto;padding:8px;display:none}.aipanel-session-skeleton.visible{display:block}.aipanel-skeleton-item{display:flex;align-items:center;gap:8px;height:32px;box-sizing:border-box;padding:0 8px;border-radius:8px;margin-bottom:2px;background:var(--ap-skeleton-bg)}.aipanel-skeleton-title{flex:1 1 auto;height:13px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-skeleton-meta{flex:none;width:32px;height:12px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-session-empty{padding:32px 16px;text-align:center;color:var(--ap-text-tertiary);font-size:12px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}
@@ -1 +1 @@
1
- .aipanel-widget{--ap-bg-main: #ffffff;--ap-bg-secondary: #f9fafb;--ap-bg-tertiary: #ebeef2;--ap-overlay-bg: rgba(249, 250, 251, .92);--ap-text-primary: #0f1115;--ap-text-secondary: #61666b;--ap-text-tertiary: #81858c;--ap-text-placeholder: #adb2b8;--ap-border-faint: rgba(15, 17, 21, .04);--ap-border-primary: rgba(15, 17, 21, .1);--ap-border-secondary: rgba(15, 17, 21, .12);--ap-hover-bg: rgba(38, 49, 72, .06);--ap-elevated-fill: #ffffff;--ap-elevated-hover: #f1f3f5;--ap-press-bg: rgba(38, 49, 72, .1);--ap-primary: #0f1115;--ap-primary-hover: #43454a;--ap-on-primary: #ffffff;--ap-accent: #4176e6;--ap-accent-hover: #5686fe;--ap-accent-bg: rgba(65, 118, 230, .1);--ap-danger: #ec1313;--ap-danger-hover: #c40f0f;--ap-state-pending: #f59e0b;--ap-state-completed: #22c55e;--ap-state-ongoing: #5686fe;--ap-tooltip-bg: #1e1e1e;--ap-dialog-overlay: rgba(0, 0, 0, .24);--ap-dialog-bg: #ffffff;--ap-scrollbar-thumb: #e5e5e5;--ap-scrollbar-thumb-hover: #d4d4d4;--ap-thinking-glow: rgba(86, 134, 254, .3);--ap-thinking-glow-strong: rgba(86, 134, 254, .55);--ap-skeleton-bg: rgba(15, 17, 21, .06);--ap-skeleton-gradient: linear-gradient( 90deg, rgba(15, 17, 21, .04) 25%, rgba(15, 17, 21, .1) 50%, rgba(15, 17, 21, .04) 75% );--ap-shadow-sm: 0 1px 2px rgba(15, 17, 21, .04), 0 1px 3px rgba(15, 17, 21, .06);--ap-shadow-md: 0 2px 8px rgba(15, 17, 21, .06), 0 4px 16px rgba(15, 17, 21, .06);--ap-shadow-lg: 0 0 0 .5px rgba(15, 17, 21, .06), 0 4px 16px rgba(15, 17, 21, .08), 0 16px 48px rgba(15, 17, 21, .1);--ap-shadow-xl: 0 0 0 .5px rgba(15, 17, 21, .08), 0 8px 32px rgba(15, 17, 21, .12), 0 24px 72px rgba(15, 17, 21, .14);--ap-shadow-accent: 0 1px 2px rgba(65, 118, 230, .14), 0 0 0 1px rgba(65, 118, 230, .18);position:fixed;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}.aipanel-widget.aipanel-theme-dark{--ap-bg-main: #151517;--ap-bg-secondary: #1b1b1c;--ap-bg-tertiary: #2c2c2e;--ap-overlay-bg: rgba(21, 21, 23, .92);--ap-text-primary: #f9fafb;--ap-text-secondary: #cfd3d6;--ap-text-tertiary: #adb2b8;--ap-text-placeholder: #81858c;--ap-border-faint: rgba(255, 255, 255, .06);--ap-border-primary: rgba(255, 255, 255, .12);--ap-border-secondary: rgba(255, 255, 255, .16);--ap-hover-bg: rgba(255, 255, 255, .08);--ap-elevated-fill: #43454a;--ap-elevated-hover: #353638;--ap-press-bg: rgba(255, 255, 255, .14);--ap-primary: #f9fafb;--ap-primary-hover: #ebeef2;--ap-on-primary: #0f1115;--ap-accent: #679efe;--ap-accent-hover: #5686fe;--ap-accent-bg: rgba(103, 158, 254, .16);--ap-danger: #f25a5a;--ap-danger-hover: #ff8383;--ap-state-pending: #f59e0b;--ap-state-completed: #22c55e;--ap-state-ongoing: #5686fe;--ap-tooltip-bg: #282828;--ap-dialog-overlay: rgba(0, 0, 0, .5);--ap-dialog-bg: #2c2c2e;--ap-scrollbar-thumb: #3c3c3d;--ap-scrollbar-thumb-hover: #545557;--ap-thinking-glow: rgba(103, 158, 254, .35);--ap-thinking-glow-strong: rgba(103, 158, 254, .6);--ap-skeleton-bg: rgba(255, 255, 255, .07);--ap-skeleton-gradient: linear-gradient( 90deg, rgba(255, 255, 255, .05) 25%, rgba(255, 255, 255, .12) 50%, rgba(255, 255, 255, .05) 75% );--ap-shadow-sm: 0 1px 2px rgba(0, 0, 0, .3), 0 1px 3px rgba(0, 0, 0, .24);--ap-shadow-md: 0 2px 8px rgba(0, 0, 0, .3), 0 4px 16px rgba(0, 0, 0, .2);--ap-shadow-lg: 0 0 0 .5px rgba(255, 255, 255, .06), 0 4px 16px rgba(0, 0, 0, .3), 0 16px 48px rgba(0, 0, 0, .25);--ap-shadow-xl: 0 0 0 .5px rgba(255, 255, 255, .08), 0 8px 32px rgba(0, 0, 0, .36), 0 24px 72px rgba(0, 0, 0, .3);--ap-shadow-accent: 0 1px 2px rgba(103, 158, 254, .2), 0 0 0 1px rgba(103, 158, 254, .25)}@supports not selector(::-webkit-scrollbar){.aipanel-widget,.aipanel-widget *{scrollbar-width:thin;scrollbar-color:var(--ap-scrollbar-thumb) transparent}}.aipanel-widget ::-webkit-scrollbar,.aipanel-widget *::-webkit-scrollbar{width:8px;height:8px}.aipanel-widget ::-webkit-scrollbar-track,.aipanel-widget *::-webkit-scrollbar-track{background:transparent}.aipanel-widget ::-webkit-scrollbar-thumb,.aipanel-widget *::-webkit-scrollbar-thumb{border-radius:4px;background:var(--ap-scrollbar-thumb)}.aipanel-widget ::-webkit-scrollbar-thumb:hover,.aipanel-widget *::-webkit-scrollbar-thumb:hover{background:var(--ap-scrollbar-thumb-hover)}.aipanel-widget ::-webkit-scrollbar-corner,.aipanel-widget *::-webkit-scrollbar-corner{background:transparent}.aipanel-chat{position:fixed;bottom:20px;width:700px;height:86vh;max-height:calc(100vh - 40px);background:var(--ap-bg-main);border-radius:16px;box-shadow:var(--ap-shadow-lg);overflow:hidden;opacity:0;visibility:hidden;transform:translate3d(var(---chatAnimationOrigin\.x),var(---chatAnimationOrigin\.y),0) scale(.95);transition:all .3s ease;display:flex;flex-direction:column;z-index:99999}.aipanel-chat.open{opacity:1;visibility:visible;transform:translateZ(0) scale(1)}.aipanel-chat.no-transition,.aipanel-chat.no-transition.open{transition:none!important}.aipanel-chat.minimized{width:320px;height:320px}.aipanel-chat.minimized .aipanel-iframe-container{margin-top:-146px}.aipanel-chat-content{display:flex;flex:1;overflow:hidden}.aipanel-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 #3b82f666,0 0 0 2px #3b82f633;animation:slideDown .3s ease;z-index:10000000;display:flex;align-items:center;gap:10px}.aipanel-notification:before{content:"\1f4a1";font-size:16px}.aipanel-dialog-overlay{position:fixed;inset:0;background:var(--ap-dialog-overlay);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:9999999;animation:fadeIn .2s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.aipanel-dialog{width:min(380px,100%);background:var(--ap-dialog-bg);border-radius:24px;padding:24px 24px 20px;box-shadow:var(--ap-shadow-xl);animation:scaleIn .2s ease}@keyframes scaleIn{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}.aipanel-dialog-content{margin-bottom:20px}.aipanel-dialog-message{font-size:14px;line-height:22px;font-weight:400;color:var(--ap-text-primary)}.aipanel-dialog-actions{display:flex;gap:8px;justify-content:flex-end}.aipanel-dialog-btn{height:36px;padding:0 20px;border-radius:999px;border:1px solid transparent;font-size:14px;line-height:22px;font-weight:500;cursor:pointer;transition:all .2s}.aipanel-dialog-btn.cancel{background:transparent;border-color:var(--ap-border-primary);color:var(--ap-text-secondary)}.aipanel-dialog-btn.cancel:hover{background:var(--ap-hover-bg);color:var(--ap-text-primary)}.aipanel-dialog-btn.confirm{background:var(--ap-danger);color:#fff}.aipanel-dialog-btn.confirm:hover{background:var(--ap-danger-hover)}@keyframes slideDown{0%{transform:translate(-50%) translateY(-100%);opacity:0}to{transform:translate(-50%) translateY(0);opacity:1}}.aipanel-page-notification{position:fixed;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 #3b82f666,0 0 0 2px #3b82f633;animation:slideDown .3s ease;z-index:2147483647;display:flex;align-items:center;gap:10px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.aipanel-page-notification:before{content:"\1f4a1";font-size:16px}.aipanel-element-highlight{position:fixed;pointer-events:none;z-index:999998;border-radius:4px}#vue-inspector-container{display:none!important}.aipanel-element-tooltip{position:fixed;background:var(--ap-tooltip-bg);color:#fff;padding:8px 12px;border-radius:6px;font-size:12px;z-index:9999998;box-shadow:var(--ap-shadow-md);max-width:300px;pointer-events:none;line-height:1}.aipanel-tooltip-tag{font-weight:500;margin-bottom:4px;word-break:break-all}.aipanel-tooltip-file{font-size:11px;color:var(--ap-text-placeholder);word-break:break-all}.aipanel-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){.aipanel-chat{width:calc(100vw - 40px);height:calc(100vh - 100px)}}body.has-aipanel-split{transition:padding .3s ease;min-width:auto}body.has-aipanel-split-right{padding-right:var(--aipanel-split-width, 500px)}body.has-aipanel-split-left{padding-left:var(--aipanel-split-width, 500px)}.aipanel-widget.extension-mode{position:relative;width:100%;height:100%;display:flex}.aipanel-widget.extension-mode .aipanel-select-mode-hint,.aipanel-widget.extension-mode .aipanel-dialog-overlay{position:absolute}
1
+ .aipanel-widget{--ap-bg-main: #ffffff;--ap-bg-secondary: #f9fafb;--ap-bg-tertiary: #ebeef2;--ap-overlay-bg: rgba(249, 250, 251, .92);--ap-text-primary: #0f1115;--ap-text-secondary: #61666b;--ap-text-tertiary: #81858c;--ap-text-placeholder: #adb2b8;--ap-border-faint: rgba(15, 17, 21, .04);--ap-border-primary: rgba(15, 17, 21, .1);--ap-border-secondary: rgba(15, 17, 21, .12);--ap-hover-bg: rgba(38, 49, 72, .06);--ap-elevated-fill: #ffffff;--ap-elevated-hover: #f1f3f5;--ap-press-bg: rgba(38, 49, 72, .1);--ap-primary: #0f1115;--ap-primary-hover: #43454a;--ap-on-primary: #ffffff;--ap-accent: #4176e6;--ap-accent-hover: #5686fe;--ap-accent-bg: rgba(65, 118, 230, .1);--ap-danger: #ec1313;--ap-danger-hover: #c40f0f;--ap-state-pending: #f59e0b;--ap-state-completed: #22c55e;--ap-state-ongoing: #5686fe;--ap-tooltip-bg: #1e1e1e;--ap-dialog-overlay: rgba(0, 0, 0, .24);--ap-dialog-bg: #ffffff;--ap-scrollbar-thumb: #e5e5e5;--ap-scrollbar-thumb-hover: #d4d4d4;--ap-thinking-glow: rgba(86, 134, 254, .3);--ap-thinking-glow-strong: rgba(86, 134, 254, .55);--ap-skeleton-bg: rgba(15, 17, 21, .06);--ap-skeleton-gradient: linear-gradient( 90deg, rgba(15, 17, 21, .04) 25%, rgba(15, 17, 21, .1) 50%, rgba(15, 17, 21, .04) 75% );--ap-shadow-sm: 0 1px 2px rgba(15, 17, 21, .04), 0 1px 3px rgba(15, 17, 21, .06);--ap-shadow-md: 0 2px 8px rgba(15, 17, 21, .06), 0 4px 16px rgba(15, 17, 21, .06);--ap-shadow-lg: 0 0 0 .5px rgba(15, 17, 21, .06), 0 4px 16px rgba(15, 17, 21, .08), 0 16px 48px rgba(15, 17, 21, .1);--ap-shadow-xl: 0 0 0 .5px rgba(15, 17, 21, .08), 0 8px 32px rgba(15, 17, 21, .12), 0 24px 72px rgba(15, 17, 21, .14);--ap-shadow-accent: 0 1px 2px rgba(65, 118, 230, .14), 0 0 0 1px rgba(65, 118, 230, .18);position:fixed;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}.aipanel-widget.aipanel-theme-dark{--ap-bg-main: #151517;--ap-bg-secondary: #1b1b1c;--ap-bg-tertiary: #2c2c2e;--ap-overlay-bg: rgba(21, 21, 23, .92);--ap-text-primary: #f9fafb;--ap-text-secondary: #cfd3d6;--ap-text-tertiary: #adb2b8;--ap-text-placeholder: #81858c;--ap-border-faint: rgba(255, 255, 255, .06);--ap-border-primary: rgba(255, 255, 255, .12);--ap-border-secondary: rgba(255, 255, 255, .16);--ap-hover-bg: rgba(255, 255, 255, .08);--ap-elevated-fill: #43454a;--ap-elevated-hover: #353638;--ap-press-bg: rgba(255, 255, 255, .14);--ap-primary: #f9fafb;--ap-primary-hover: #ebeef2;--ap-on-primary: #0f1115;--ap-accent: #679efe;--ap-accent-hover: #5686fe;--ap-accent-bg: rgba(103, 158, 254, .16);--ap-danger: #f25a5a;--ap-danger-hover: #ff8383;--ap-state-pending: #f59e0b;--ap-state-completed: #22c55e;--ap-state-ongoing: #5686fe;--ap-tooltip-bg: #282828;--ap-dialog-overlay: rgba(0, 0, 0, .5);--ap-dialog-bg: #2c2c2e;--ap-scrollbar-thumb: #3c3c3d;--ap-scrollbar-thumb-hover: #545557;--ap-thinking-glow: rgba(103, 158, 254, .35);--ap-thinking-glow-strong: rgba(103, 158, 254, .6);--ap-skeleton-bg: rgba(255, 255, 255, .07);--ap-skeleton-gradient: linear-gradient( 90deg, rgba(255, 255, 255, .05) 25%, rgba(255, 255, 255, .12) 50%, rgba(255, 255, 255, .05) 75% );--ap-shadow-sm: 0 1px 2px rgba(0, 0, 0, .3), 0 1px 3px rgba(0, 0, 0, .24);--ap-shadow-md: 0 2px 8px rgba(0, 0, 0, .3), 0 4px 16px rgba(0, 0, 0, .2);--ap-shadow-lg: 0 0 0 .5px rgba(255, 255, 255, .06), 0 4px 16px rgba(0, 0, 0, .3), 0 16px 48px rgba(0, 0, 0, .25);--ap-shadow-xl: 0 0 0 .5px rgba(255, 255, 255, .08), 0 8px 32px rgba(0, 0, 0, .36), 0 24px 72px rgba(0, 0, 0, .3);--ap-shadow-accent: 0 1px 2px rgba(103, 158, 254, .2), 0 0 0 1px rgba(103, 158, 254, .25)}@supports not selector(::-webkit-scrollbar){.aipanel-widget,.aipanel-widget *{scrollbar-width:thin;scrollbar-color:var(--ap-scrollbar-thumb) transparent}}.aipanel-widget ::-webkit-scrollbar,.aipanel-widget *::-webkit-scrollbar{width:8px;height:8px}.aipanel-widget ::-webkit-scrollbar-track,.aipanel-widget *::-webkit-scrollbar-track{background:transparent}.aipanel-widget ::-webkit-scrollbar-thumb,.aipanel-widget *::-webkit-scrollbar-thumb{border-radius:4px;background:var(--ap-scrollbar-thumb)}.aipanel-widget ::-webkit-scrollbar-thumb:hover,.aipanel-widget *::-webkit-scrollbar-thumb:hover{background:var(--ap-scrollbar-thumb-hover)}.aipanel-widget ::-webkit-scrollbar-corner,.aipanel-widget *::-webkit-scrollbar-corner{background:transparent}.aipanel-chat{position:fixed;bottom:20px;width:700px;height:86vh;max-height:calc(100vh - 40px);background:var(--ap-bg-main);border-radius:16px;box-shadow:var(--ap-shadow-lg);overflow:hidden;opacity:0;visibility:hidden;transform:translate3d(var(---chatAnimationOrigin\.x),var(---chatAnimationOrigin\.y),0) scale(.95);transition:all .3s ease;display:flex;flex-direction:column;z-index:99999}.aipanel-chat.open{opacity:1;visibility:visible;transform:translateZ(0) scale(1)}.aipanel-chat.no-transition,.aipanel-chat.no-transition.open{transition:none!important}.aipanel-chat.minimized{width:320px;height:320px}.aipanel-chat.minimized .aipanel-iframe-container{margin-top:-146px}.aipanel-chat-content{display:flex;flex:1;overflow:hidden}.aipanel-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 #3b82f666,0 0 0 2px #3b82f633;animation:slideDown .3s ease;z-index:10000000;display:flex;align-items:center;gap:10px}.aipanel-notification:before{content:"\1f4a1";font-size:16px}.aipanel-dialog-overlay{position:fixed;inset:0;background:var(--ap-dialog-overlay);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:9999999;animation:fadeIn .2s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.aipanel-dialog{width:min(380px,100%);background:var(--ap-dialog-bg);border-radius:24px;padding:24px 24px 20px;box-shadow:var(--ap-shadow-xl);animation:scaleIn .2s ease}@keyframes scaleIn{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}.aipanel-dialog-content{margin-bottom:20px}.aipanel-dialog-message{font-size:14px;line-height:22px;font-weight:400;color:var(--ap-text-primary)}.aipanel-dialog-actions{display:flex;gap:8px;justify-content:flex-end}.aipanel-dialog-btn{height:36px;padding:0 20px;border-radius:999px;border:1px solid transparent;font-size:14px;line-height:22px;font-weight:500;cursor:pointer;transition:all .2s}.aipanel-dialog-btn.cancel{background:transparent;border-color:var(--ap-border-primary);color:var(--ap-text-secondary)}.aipanel-dialog-btn.cancel:hover{background:var(--ap-hover-bg);color:var(--ap-text-primary)}.aipanel-dialog-btn.confirm{background:var(--ap-danger);color:#fff}.aipanel-dialog-btn.confirm:hover{background:var(--ap-danger-hover)}@keyframes slideDown{0%{transform:translate(-50%) translateY(-100%);opacity:0}to{transform:translate(-50%) translateY(0);opacity:1}}.aipanel-page-notification{position:fixed;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 #3b82f666,0 0 0 2px #3b82f633;animation:slideDown .3s ease;z-index:2147483647;display:flex;align-items:center;gap:10px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.aipanel-page-notification:before{content:"\1f4a1";font-size:16px}.aipanel-element-highlight{position:fixed;pointer-events:none;z-index:999998;border-radius:4px}.aipanel-element-highlight.breathing{animation:aipanel-highlight-breath 2s ease-in-out 2}@keyframes aipanel-highlight-breath{0%,to{opacity:.25;transform:scale(1)}50%{opacity:1;transform:scale(1.01)}}#vue-inspector-container{display:none!important}.aipanel-element-tooltip{position:fixed;background:var(--ap-tooltip-bg);color:#fff;padding:8px 12px;border-radius:6px;font-size:12px;z-index:9999998;box-shadow:var(--ap-shadow-md);max-width:300px;pointer-events:none;line-height:1}.aipanel-tooltip-tag{font-weight:500;margin-bottom:4px;word-break:break-all}.aipanel-tooltip-file{font-size:11px;color:var(--ap-text-placeholder);word-break:break-all}@media(max-width:768px){.aipanel-chat{width:calc(100vw - 40px);height:calc(100vh - 100px)}}body.has-aipanel-split{transition:padding .3s ease;min-width:auto}body.has-aipanel-split-right{padding-right:var(--aipanel-split-width, 500px)}body.has-aipanel-split-left{padding-left:var(--aipanel-split-width, 500px)}.aipanel-widget.extension-mode{position:relative;width:100%;height:100%;display:flex}.aipanel-widget.extension-mode .aipanel-select-mode-hint,.aipanel-widget.extension-mode .aipanel-dialog-overlay{position:absolute}
@@ -1,4 +1,5 @@
1
1
  import type { AIPanelWidgetProps } from "./types";
2
+ import { type AIPanelSelectedElement } from "@aipanel/core";
2
3
  declare var __VLS_13: {}, __VLS_29: {}, __VLS_32: {}, __VLS_35: {}, __VLS_38: {}, __VLS_41: {}, __VLS_44: {}, __VLS_47: {}, __VLS_50: {};
3
4
  type __VLS_Slots = {} & {
4
5
  'button-icon'?: (props: typeof __VLS_13) => any;
@@ -57,7 +58,7 @@ declare const __VLS_base: import("vue").DefineComponent<AIPanelWidgetProps, {
57
58
  hotkeyLabel: string;
58
59
  splitPanelWidth: number;
59
60
  currentSessionId: string | null;
60
- selectedElements: import("@aipanel/core").AIPanelSelectedElement[];
61
+ selectedElements: AIPanelSelectedElement[];
61
62
  splitMode: import("@aipanel/core").SplitModeOptions;
62
63
  hideBubble: boolean;
63
64
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -49,7 +49,7 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent({
49
49
  providerSidebar: { type: Boolean, required: false, default: false },
50
50
  sidebarCollapseControl: { type: String, required: false, default: "host" }
51
51
  },
52
- emits: ["update:open", "update:selectMode", "update:sessionListCollapsed", "update:currentSessionId", "update:selectedElements", "update:theme", "update:thinking", "update:splitPanelWidth", "toggle", "close", "toggle-session-list", "toggle-select-mode", "toggle-theme", "create-session", "select-session", "delete-session", "click-selected-node", "remove-selected-node", "clear-selected-nodes", "empty-action", "frame-loaded", "thinking-change", "split-panel-width-change"],
52
+ emits: ["update:open", "update:selectMode", "update:sessionListCollapsed", "update:currentSessionId", "update:selectedElements", "update:theme", "update:thinking", "update:splitPanelWidth", "toggle", "close", "toggle-session-list", "toggle-select-mode", "toggle-theme", "create-session", "select-session", "delete-session", "click-selected-node", "locate-node", "remove-selected-node", "clear-selected-nodes", "empty-action", "frame-loaded", "thinking-change", "split-panel-width-change"],
53
53
  setup(__props, { expose: __expose, emit: __emit }) {
54
54
  _useCssVars((_ctx) => ({
55
55
  "-chatAnimationOrigin.x": chatAnimationOrigin.value.x,
@@ -213,12 +213,32 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent({
213
213
  onDeleteSession: (session) => emit("delete-session", session),
214
214
  showConfirmDialog
215
215
  });
216
+ const {
217
+ highlightVisible,
218
+ highlightBreathing,
219
+ highlightStyle,
220
+ tooltipVisible,
221
+ tooltipStyle,
222
+ tooltipContent,
223
+ flashElement
224
+ } = useInspector({
225
+ selectMode: toRef(props, "selectMode"),
226
+ onAddSelectedNode: (element) => {
227
+ emit("click-selected-node", element);
228
+ },
229
+ onExitSelectMode: () => {
230
+ emit("update:selectMode", false);
231
+ emit("toggle-select-mode", false);
232
+ }
233
+ });
216
234
  const {
217
235
  bubbleVisible,
218
236
  hasSelectedElements,
219
237
  selectedElementItems,
238
+ consumePendingLocate,
220
239
  handleClearSelectedNodes,
221
240
  handleClickSelectedNode,
241
+ handleLocateSelectedElement,
222
242
  handleRemoveSelectedNode,
223
243
  handleToggleSelectMode
224
244
  } = useSelection({
@@ -238,17 +258,11 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent({
238
258
  emit("clear-selected-nodes");
239
259
  emit("update:selectedElements", []);
240
260
  },
241
- showConfirmDialog
242
- });
243
- const { highlightVisible, highlightStyle, tooltipVisible, tooltipStyle, tooltipContent } = useInspector({
244
- selectMode: toRef(props, "selectMode"),
245
- onAddSelectedNode: (element) => {
246
- emit("click-selected-node", element);
247
- },
248
- onExitSelectMode: () => {
249
- emit("update:selectMode", false);
250
- emit("toggle-select-mode", false);
251
- }
261
+ showConfirmDialog,
262
+ // 点已选节点时复用选择模式的高亮框闪烁;扩展模式下挂件在侧栏,不操作页面
263
+ flashHighlight: flashElement,
264
+ locateInPage: () => !isExtensionMode.value,
265
+ notify: (message) => showNotification(message)
252
266
  });
253
267
  const bubbleOffset = ref(void 0);
254
268
  const {
@@ -383,12 +397,21 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent({
383
397
  }
384
398
  }
385
399
  }
400
+ if (event.data?.type === WIDGET_MSG.LOCATE_NODE && event.data.element) {
401
+ const element = event.data.element;
402
+ if (localDisplayMode.value === "extension") {
403
+ emit("locate-node", element);
404
+ } else {
405
+ handleLocateSelectedElement(element);
406
+ }
407
+ }
386
408
  };
387
409
  onMounted(() => {
388
410
  if (typeof window !== "undefined") {
389
411
  window.addEventListener("resize", handleWindowResize);
390
412
  window.addEventListener("message", handleIframeMessage);
391
413
  }
414
+ void consumePendingLocate();
392
415
  });
393
416
  onUnmounted(() => {
394
417
  if (typeof window !== "undefined") {
@@ -577,7 +600,7 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent({
577
600
  return dialogResolve;
578
601
  }, set dialogResolve(v) {
579
602
  dialogResolve = v;
580
- }, showConfirmDialog, handleDialogConfirm, handleDialogCancel, frameRef, triggerRef, sendMessageToIframe, localSessionListCollapsed, localDisplayMode, localSplitPosition, minimized, promptDockVisible, reviewPanelVisible, isRestoring, iframeLoaded, iframeReady, splitPanelWidth, syncStateToIframe, handleFrameLoaded, handleToggleDisplayMode, buttonActive, containerClasses, iframeSource, sessionListTitle, resolvedTheme, handleClose, handleEmptyAction, handleToggle, handleToggleSessionList, handleToggleTheme, sessionItems, handleCreateSession, handleDeleteSession, handleSelectSession, bubbleVisible, hasSelectedElements, selectedElementItems, handleClearSelectedNodes, handleClickSelectedNode, handleRemoveSelectedNode, handleToggleSelectMode, highlightVisible, highlightStyle, tooltipVisible, tooltipStyle, tooltipContent, bubbleOffset, effectiveMode, isSplitMode, isExtensionMode, panelWidth, splitConfig, splitPosition, handleResize, handleSplitToggle, handleTogglePosition, handleToggleMinimize, handleTogglePromptDock, handleToggleReviewPanel, handleRefresh, windowWidth, windowHeight, handleWindowResize, handleIframeMessage, bubbleQuadrant, isBubbleOnRightSide, chatPositionStyle, handleBubbleOffsetChange, handleResizeStart, handleResizeEnd, chatAnimationOrigin, isDragging, get wasOpenBeforeDrag() {
603
+ }, showConfirmDialog, handleDialogConfirm, handleDialogCancel, frameRef, triggerRef, sendMessageToIframe, localSessionListCollapsed, localDisplayMode, localSplitPosition, minimized, promptDockVisible, reviewPanelVisible, isRestoring, iframeLoaded, iframeReady, splitPanelWidth, syncStateToIframe, handleFrameLoaded, handleToggleDisplayMode, buttonActive, containerClasses, iframeSource, sessionListTitle, resolvedTheme, handleClose, handleEmptyAction, handleToggle, handleToggleSessionList, handleToggleTheme, sessionItems, handleCreateSession, handleDeleteSession, handleSelectSession, highlightVisible, highlightBreathing, highlightStyle, tooltipVisible, tooltipStyle, tooltipContent, flashElement, bubbleVisible, hasSelectedElements, selectedElementItems, consumePendingLocate, handleClearSelectedNodes, handleClickSelectedNode, handleLocateSelectedElement, handleRemoveSelectedNode, handleToggleSelectMode, bubbleOffset, effectiveMode, isSplitMode, isExtensionMode, panelWidth, splitConfig, splitPosition, handleResize, handleSplitToggle, handleTogglePosition, handleToggleMinimize, handleTogglePromptDock, handleToggleReviewPanel, handleRefresh, windowWidth, windowHeight, handleWindowResize, handleIframeMessage, bubbleQuadrant, isBubbleOnRightSide, chatPositionStyle, handleBubbleOffsetChange, handleResizeStart, handleResizeEnd, chatAnimationOrigin, isDragging, get wasOpenBeforeDrag() {
581
604
  return wasOpenBeforeDrag;
582
605
  }, set wasOpenBeforeDrag(v) {
583
606
  wasOpenBeforeDrag = v;
@@ -586,7 +609,7 @@ const __vue_sfc__ = /* @__PURE__ */ _defineComponent({
586
609
  return __returned__;
587
610
  }
588
611
  });
589
- import { renderSlot as _renderSlot, withCtx as _withCtx, createSlots as _createSlots, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, createElementVNode as _createElementVNode, createVNode as _createVNode, Fragment as _Fragment, createElementBlock as _createElementBlock, vShow as _vShow, normalizeStyle as _normalizeStyle, withDirectives as _withDirectives, toDisplayString as _toDisplayString, normalizeClass as _normalizeClass, Teleport as _Teleport } from "vue";
612
+ import { renderSlot as _renderSlot, withCtx as _withCtx, createSlots as _createSlots, openBlock as _openBlock, createBlock as _createBlock, createCommentVNode as _createCommentVNode, createElementVNode as _createElementVNode, createVNode as _createVNode, Fragment as _Fragment, createElementBlock as _createElementBlock, vShow as _vShow, normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, withDirectives as _withDirectives, toDisplayString as _toDisplayString, Teleport as _Teleport } from "vue";
590
613
  const _hoisted_1 = { class: "aipanel-tooltip-tag" };
591
614
  const _hoisted_2 = { class: "aipanel-tooltip-file" };
592
615
  const _hoisted_3 = {
@@ -729,12 +752,12 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
729
752
  _withDirectives(_createElementVNode(
730
753
  "div",
731
754
  {
732
- class: "aipanel-element-highlight",
755
+ class: _normalizeClass(["aipanel-element-highlight", { breathing: $setup.highlightBreathing }]),
733
756
  style: _normalizeStyle($setup.highlightStyle)
734
757
  },
735
758
  null,
736
- 4
737
- /* STYLE */
759
+ 6
760
+ /* CLASS, STYLE */
738
761
  ), [
739
762
  [_vShow, $setup.highlightVisible]
740
763
  ]),
package/es/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { App } from 'vue';
2
- declare const version = "1.3.7";
2
+ declare const version = "1.3.9";
3
3
  declare function install(app: App<any>, options?: any): void;
4
4
  export { install, version, };
5
5
  export * from './AI-panel-widget';
package/es/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AIPanelWidget } from "./AI-panel-widget/index.mjs";
2
- const version = "1.3.7";
2
+ const version = "1.3.9";
3
3
  function install(app, options) {
4
4
  const components = [
5
5
  AIPanelWidget
@@ -134,6 +134,7 @@ function getTargetElement(e) {
134
134
  }
135
135
  function useInspector(options) {
136
136
  const highlightVisible = (0, import_vue.ref)(false);
137
+ const highlightBreathing = (0, import_vue.ref)(false);
137
138
  const highlightStyle = (0, import_vue.ref)({
138
139
  top: "0px",
139
140
  left: "0px",
@@ -144,8 +145,61 @@ function useInspector(options) {
144
145
  const tooltipStyle = (0, import_vue.ref)({ top: "0px", left: "0px" });
145
146
  const tooltipContent = (0, import_vue.ref)({ description: "", fileInfo: "" });
146
147
  let inspectorCheckTimer = null;
148
+ let breathTimer = null;
149
+ let followTarget = null;
147
150
  let currentPrimary = "#4176e6";
148
151
  let currentPrimaryBg = "rgba(65, 118, 230, 0.1)";
152
+ function positionHighlight(target) {
153
+ const widget = document.querySelector(".aipanel-widget");
154
+ if (widget) {
155
+ const style = getComputedStyle(widget);
156
+ currentPrimary = style.getPropertyValue("--ap-accent").trim() || currentPrimary;
157
+ currentPrimaryBg = style.getPropertyValue("--ap-accent-bg").trim() || currentPrimaryBg;
158
+ }
159
+ const rect = target.getBoundingClientRect();
160
+ const next = {
161
+ top: `${rect.top}px`,
162
+ left: `${rect.left}px`,
163
+ width: `${rect.width}px`,
164
+ height: `${rect.height}px`,
165
+ border: `2px solid ${currentPrimary}`,
166
+ background: currentPrimaryBg
167
+ };
168
+ const current = highlightStyle.value;
169
+ const moved = current.top !== next.top || current.left !== next.left || current.width !== next.width || current.height !== next.height || current.border !== next.border;
170
+ if (!moved) return;
171
+ highlightStyle.value = next;
172
+ }
173
+ function handleViewportChange() {
174
+ if (followTarget) positionHighlight(followTarget);
175
+ }
176
+ function startFollowing(target) {
177
+ stopFollowing();
178
+ followTarget = target;
179
+ window.addEventListener("scroll", handleViewportChange, { passive: true, capture: true });
180
+ window.addEventListener("resize", handleViewportChange, { passive: true });
181
+ }
182
+ function stopFollowing() {
183
+ if (followTarget) {
184
+ window.removeEventListener("scroll", handleViewportChange, true);
185
+ window.removeEventListener("resize", handleViewportChange);
186
+ }
187
+ followTarget = null;
188
+ }
189
+ function flashElement(target) {
190
+ target.scrollIntoView({ block: "center" });
191
+ positionHighlight(target);
192
+ highlightVisible.value = true;
193
+ highlightBreathing.value = true;
194
+ startFollowing(target);
195
+ if (breathTimer !== null) window.clearTimeout(breathTimer);
196
+ breathTimer = window.setTimeout(() => {
197
+ breathTimer = null;
198
+ stopFollowing();
199
+ highlightBreathing.value = false;
200
+ highlightVisible.value = false;
201
+ }, 4e3);
202
+ }
149
203
  function setPointerEventsNone(elements) {
150
204
  elements.forEach((el) => {
151
205
  if (el) el.style.pointerEvents = "none";
@@ -168,14 +222,9 @@ function useInspector(options) {
168
222
  const fileInfo = resolveElementSourceLocation(elementToHighlight);
169
223
  setPointerEventsAuto(uiElements);
170
224
  if (elementToHighlight) {
171
- const widget = document.querySelector(".aipanel-widget");
172
- if (widget) {
173
- const style = getComputedStyle(widget);
174
- currentPrimary = style.getPropertyValue("--ap-accent").trim() || currentPrimary;
175
- currentPrimaryBg = style.getPropertyValue("--ap-accent-bg").trim() || currentPrimaryBg;
176
- }
225
+ positionHighlight(elementToHighlight);
177
226
  const description = getElementDescription(elementToHighlight);
178
- const fileName = fileInfo?.file ? fileInfo.file.split("/").pop() : "";
227
+ const fileName = fileInfo?.file ? (0, import_core.fileNameOf)(fileInfo.file) : "";
179
228
  let lineInfo = "";
180
229
  if (fileInfo?.line) {
181
230
  lineInfo = `:${fileInfo.line}`;
@@ -188,21 +237,6 @@ function useInspector(options) {
188
237
  description,
189
238
  fileInfo: fileInfoText
190
239
  };
191
- const rect = elementToHighlight.getBoundingClientRect();
192
- const newTop = `${rect.top}px`;
193
- const newLeft = `${rect.left}px`;
194
- const newWidth = `${rect.width}px`;
195
- const newHeight = `${rect.height}px`;
196
- if (highlightStyle.value.top !== newTop || highlightStyle.value.left !== newLeft || highlightStyle.value.width !== newWidth || highlightStyle.value.height !== newHeight) {
197
- highlightStyle.value = {
198
- top: newTop,
199
- left: newLeft,
200
- width: newWidth,
201
- height: newHeight,
202
- border: `2px solid ${currentPrimary}`,
203
- background: currentPrimaryBg
204
- };
205
- }
206
240
  highlightVisible.value = true;
207
241
  tooltipVisible.value = true;
208
242
  void (0, import_vue.nextTick)(() => {
@@ -211,6 +245,7 @@ function useInspector(options) {
211
245
  const tooltipWidth = tooltipEl.offsetWidth;
212
246
  const tooltipHeight = tooltipEl.offsetHeight;
213
247
  if (tooltipWidth === 0 || tooltipHeight === 0) return;
248
+ const rect = elementToHighlight.getBoundingClientRect();
214
249
  const margin = 10;
215
250
  const gap = 4;
216
251
  const viewportWidth = window.innerWidth;
@@ -321,6 +356,7 @@ function useInspector(options) {
321
356
  (0, import_vue.watch)(options.selectMode, (newVal) => {
322
357
  (0, import_core.resolveInspectorAdapter)()?.setEnabled(newVal);
323
358
  if (newVal) {
359
+ stopFollowing();
324
360
  document.addEventListener("mousemove", handleMouseMove);
325
361
  document.addEventListener("keydown", handleKeydown, true);
326
362
  } else {
@@ -344,14 +380,21 @@ function useInspector(options) {
344
380
  if (inspectorCheckTimer) {
345
381
  window.clearInterval(inspectorCheckTimer);
346
382
  }
383
+ if (breathTimer !== null) {
384
+ window.clearTimeout(breathTimer);
385
+ breathTimer = null;
386
+ }
387
+ stopFollowing();
347
388
  document.removeEventListener("mousemove", handleMouseMove);
348
389
  document.removeEventListener("keydown", handleKeydown, true);
349
390
  });
350
391
  return {
351
392
  highlightVisible,
393
+ highlightBreathing,
352
394
  highlightStyle,
353
395
  tooltipVisible,
354
396
  tooltipStyle,
355
- tooltipContent
397
+ tooltipContent,
398
+ flashElement
356
399
  };
357
400
  }
@@ -7,6 +7,7 @@ interface UseInspectorOptions {
7
7
  }
8
8
  export declare function useInspector(options: UseInspectorOptions): {
9
9
  highlightVisible: Ref<boolean, boolean>;
10
+ highlightBreathing: Ref<boolean, boolean>;
10
11
  highlightStyle: Ref<Record<string, string>, Record<string, string>>;
11
12
  tooltipVisible: Ref<boolean, boolean>;
12
13
  tooltipStyle: Ref<{
@@ -29,5 +30,6 @@ export declare function useInspector(options: UseInspectorOptions): {
29
30
  description: string;
30
31
  fileInfo: string;
31
32
  }>;
33
+ flashElement: (target: Element) => void;
32
34
  };
33
35
  export {};
@@ -28,19 +28,61 @@ function getElementKey(element, index) {
28
28
  }
29
29
  return `${element.description}-${index}`;
30
30
  }
31
+ function takePendingLocate() {
32
+ try {
33
+ const selector = sessionStorage.getItem("__aipanel_pending_locate__");
34
+ sessionStorage.removeItem("__aipanel_pending_locate__");
35
+ return selector || null;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+ function stashPendingLocate(selector) {
41
+ try {
42
+ sessionStorage.setItem("__aipanel_pending_locate__", selector);
43
+ } catch {
44
+ }
45
+ }
46
+ function isDifferentPage(a, b) {
47
+ try {
48
+ return new URL(a, window.location.href).href !== new URL(b, window.location.href).href;
49
+ } catch {
50
+ return a !== b;
51
+ }
52
+ }
53
+ function isHashOnlyChange(a, b) {
54
+ try {
55
+ const next = new URL(a, window.location.href);
56
+ const current = new URL(b, window.location.href);
57
+ return next.origin === current.origin && next.pathname === current.pathname && next.search === current.search;
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+ function queryPageElement(selector) {
63
+ try {
64
+ return document.querySelector(selector);
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
31
69
  function getBubbleFileText(element) {
32
- const fileName = element.filePath?.split("/").pop() || "";
70
+ const fileName = element.filePath ? (0, import_core.fileNameOf)(element.filePath) : "";
33
71
  const lineInfo = element.line ? `:${element.line}${element.column ? `:${element.column}` : ""}` : "";
34
72
  return `${fileName}${lineInfo}`;
35
73
  }
36
74
  function getPanelFileText(element) {
37
- const fileName = element.filePath?.split("/").pop() || "\u672A\u77E5\u6587\u4EF6";
75
+ const fileName = element.filePath && (0, import_core.fileNameOf)(element.filePath) || "\u672A\u77E5\u6587\u4EF6";
38
76
  const lineInfo = element.line ? `:${element.line}${element.column ? `:${element.column}` : ""}` : "";
39
77
  const textPreview = element.innerText?.trim() ? `${(0, import_core.truncate)(element.innerText.trim(), 30)} \xB7 ` : "";
40
78
  return `${textPreview}${fileName}${lineInfo}`;
41
79
  }
42
80
  function useSelection(options) {
43
81
  const bubbleVisible = (0, import_vue.computed)(() => options.selectMode.value);
82
+ function shouldLocateInPage() {
83
+ const value = options.locateInPage;
84
+ return typeof value === "function" ? value() : value !== false;
85
+ }
44
86
  const selectedElementItems = (0, import_vue.computed)(
45
87
  () => (options.selectedElements.value || []).map(
46
88
  (element, index) => ({
@@ -56,57 +98,49 @@ function useSelection(options) {
56
98
  function handleToggleSelectMode() {
57
99
  options.onToggleSelectMode(!options.selectMode.value);
58
100
  }
59
- function handleClickSelectedNode(item) {
60
- const description = item.element.description;
61
- if (!description) return;
62
- let targetElement = null;
63
- if (description.includes("#")) {
64
- const idMatch = description.match(/#([^.[\s]+)/);
65
- if (idMatch) {
66
- targetElement = document.getElementById(idMatch[1]);
101
+ function handleLocateSelectedElement(element) {
102
+ if (!shouldLocateInPage()) return;
103
+ const selector = element.description?.trim();
104
+ if (!selector) return;
105
+ const navigate = options.navigate ?? ((to) => window.location.assign(to));
106
+ const url = element.previewPageUrl;
107
+ if (url && isDifferentPage(url, window.location.href)) {
108
+ if (isHashOnlyChange(url, window.location.href)) {
109
+ navigate(url);
110
+ void flashWhenRendered(selector);
111
+ return;
67
112
  }
113
+ stashPendingLocate(selector);
114
+ navigate(url);
115
+ return;
68
116
  }
69
- if (!targetElement && description.includes(".")) {
70
- const classMatch = description.match(/^([a-z]+)\.([^[\s]+)/i);
71
- if (classMatch) {
72
- const tagName = classMatch[1];
73
- const classes = classMatch[2].split(".").filter(Boolean);
74
- const selector = `${tagName}.${classes.join(".")}`;
75
- targetElement = document.querySelector(selector);
76
- }
77
- }
78
- if (!targetElement) {
79
- const tagMatch = description.match(/^([a-z]+)/i);
80
- if (tagMatch) {
81
- const simpleSelector = description.split(/[.[\s]/)[0];
82
- targetElement = document.querySelector(simpleSelector);
83
- }
117
+ const target = queryPageElement(selector);
118
+ if (!target) {
119
+ options.notify?.("\u672A\u627E\u5230\u8BE5\u8282\u70B9\uFF0C\u9875\u9762\u53EF\u80FD\u5DF2\u53D8\u5316");
120
+ return;
84
121
  }
85
- if (targetElement) {
86
- targetElement.scrollIntoView({ behavior: "smooth", block: "center" });
87
- const highlightOverlay = document.createElement("div");
88
- highlightOverlay.className = "aipanel-element-highlight-temp";
89
- const widget = document.querySelector(".aipanel-widget");
90
- let primary = "#4176e6";
91
- let primaryBg = "rgba(65, 118, 230, 0.1)";
92
- if (widget) {
93
- const style = getComputedStyle(widget);
94
- primary = style.getPropertyValue("--ap-accent").trim() || primary;
95
- primaryBg = style.getPropertyValue("--ap-accent-bg").trim() || primaryBg;
122
+ options.flashHighlight?.(target);
123
+ }
124
+ function handleClickSelectedNode(item) {
125
+ handleLocateSelectedElement(item.element);
126
+ }
127
+ async function flashWhenRendered(selector) {
128
+ const deadline = Date.now() + 2e3;
129
+ for (; ; ) {
130
+ const target = queryPageElement(selector);
131
+ if (target) {
132
+ options.flashHighlight?.(target);
133
+ return true;
96
134
  }
97
- highlightOverlay.style.border = `2px solid ${primary}`;
98
- highlightOverlay.style.background = primaryBg;
99
- const rect = targetElement.getBoundingClientRect();
100
- highlightOverlay.style.top = `${rect.top + window.scrollY}px`;
101
- highlightOverlay.style.left = `${rect.left + window.scrollX}px`;
102
- highlightOverlay.style.width = `${rect.width}px`;
103
- highlightOverlay.style.height = `${rect.height}px`;
104
- document.body.appendChild(highlightOverlay);
105
- setTimeout(() => {
106
- highlightOverlay.remove();
107
- }, 2e3);
135
+ if (Date.now() >= deadline) return false;
136
+ await (0, import_core.sleep)(50);
108
137
  }
109
138
  }
139
+ async function consumePendingLocate() {
140
+ if (!shouldLocateInPage()) return;
141
+ const selector = takePendingLocate();
142
+ if (selector) await flashWhenRendered(selector);
143
+ }
110
144
  function handleRemoveSelectedNode(item, index, source) {
111
145
  options.onRemoveSelectedNode({ element: item.element, index, source });
112
146
  }
@@ -123,8 +157,10 @@ function useSelection(options) {
123
157
  bubbleVisible,
124
158
  hasSelectedElements,
125
159
  selectedElementItems,
160
+ consumePendingLocate,
126
161
  handleClearSelectedNodes,
127
162
  handleClickSelectedNode,
163
+ handleLocateSelectedElement,
128
164
  handleRemoveSelectedNode,
129
165
  handleToggleSelectMode
130
166
  };
@@ -7,13 +7,26 @@ export interface UseSelectionOptions {
7
7
  onRemoveSelectedNode: (payload: AIPanelRemoveSelectedPayload) => void;
8
8
  onClearSelectedNodes: () => void;
9
9
  showConfirmDialog: (message: string) => Promise<boolean>;
10
+ /**
11
+ * 是否在页面内定位(默认 true;可传 getter,显示模式运行时可变)。
12
+ * 扩展模式下挂件在侧栏、页面不在本上下文,置 false 以免去操作侧栏自身的 document。
13
+ */
14
+ locateInPage?: boolean | (() => boolean);
15
+ /** 高亮元素:复用选择模式的高亮框闪烁(由挂件的 inspector 提供) */
16
+ flashHighlight?: (element: Element) => void;
17
+ /** 跳转到目标页(默认 window.location.assign;测试可注入) */
18
+ navigate?: (url: string) => void;
19
+ /** 轻提示(定位失败时给出原因) */
20
+ notify?: (message: string) => void;
10
21
  }
11
22
  export declare function useSelection(options: UseSelectionOptions): {
12
23
  bubbleVisible: import("vue").ComputedRef<boolean>;
13
24
  hasSelectedElements: import("vue").ComputedRef<boolean>;
14
25
  selectedElementItems: import("vue").ComputedRef<AIPanelSelectedElementItem[]>;
26
+ consumePendingLocate: () => Promise<void>;
15
27
  handleClearSelectedNodes: () => Promise<void>;
16
28
  handleClickSelectedNode: (item: AIPanelSelectedElementItem) => void;
29
+ handleLocateSelectedElement: (element: AIPanelSelectedElement) => void;
17
30
  handleRemoveSelectedNode: (item: AIPanelSelectedElementItem, index: number, source: AIPanelRemoveSelectedPayload["source"]) => void;
18
31
  handleToggleSelectMode: () => void;
19
32
  };
@@ -1 +1 @@
1
- .aipanel-session-list{width:236px;background:var(--ap-bg-secondary);border-right:1px solid var(--ap-border-faint);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease}.aipanel-session-list.collapsed{width:0;overflow:hidden}.aipanel-session-list.collapsed .aipanel-session-list-header,.aipanel-session-list.collapsed .aipanel-session-list-content{display:none}.aipanel-session-list-header{padding:10px 8px 8px 12px;display:flex;align-items:center;justify-content:space-between;gap:8px;background:var(--ap-bg-secondary);border-bottom:1px solid var(--ap-border-faint)}.aipanel-session-list-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:600;letter-spacing:.02em;line-height:18px;color:var(--ap-text-tertiary)}.aipanel-new-session-btn{flex:none;width:24px;height:24px;border-radius:50%;border:1px solid var(--ap-border-secondary);background:var(--ap-elevated-fill);color:var(--ap-text-primary);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease,border-color .2s ease,color .2s ease}.aipanel-new-session-btn svg{display:block}.aipanel-new-session-btn:hover{background:var(--ap-elevated-hover);color:var(--ap-text-primary)}.aipanel-new-session-btn:active{background:var(--ap-press-bg)}.aipanel-new-session-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--ap-accent-bg)}.aipanel-session-list-content{flex:1;min-height:0;overflow-y:auto;padding:8px;position:relative;display:flex;flex-direction:column;gap:2px}.aipanel-session-item{position:relative;box-sizing:border-box;display:flex;align-items:center;gap:8px;height:32px;padding:0 8px;border-radius:8px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;color:var(--ap-text-primary);transition:background-color .15s ease}.aipanel-session-item:hover{background:var(--ap-hover-bg)}.aipanel-session-item:active{background:var(--ap-press-bg)}.aipanel-session-item.active{background:var(--ap-hover-bg)}.aipanel-session-title-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:400;line-height:20px}.aipanel-session-meta{flex:none;margin-left:auto;font-size:12px;line-height:20px;color:var(--ap-text-tertiary);white-space:nowrap;transition:opacity .15s ease}.aipanel-session-item:hover .aipanel-session-meta{opacity:0}.aipanel-session-delete-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:16px;height:16px;border:none;border-radius:4px;background:transparent;color:var(--ap-text-tertiary);font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s ease,background-color .15s ease,color .15s ease}.aipanel-session-item:hover .aipanel-session-delete-btn{opacity:1}.aipanel-session-delete-btn:hover{background:transparent;color:var(--ap-text-primary)}.aipanel-session-state{position:relative;flex:none;width:10px;height:10px;margin-right:-2px}.aipanel-session-state-pending:before,.aipanel-session-state-completed:before{content:"";position:absolute;inset:0;border-radius:50%;background:currentColor;opacity:.1}.aipanel-session-state-pending:after,.aipanel-session-state-completed:after{content:"";position:absolute;inset:20%;border-radius:50%;background:currentColor}.aipanel-session-state-pending{color:var(--ap-state-pending)}.aipanel-session-state-completed{color:var(--ap-state-completed)}.aipanel-session-state-ongoing{color:var(--ap-state-ongoing)}.aipanel-session-ongoing-cell{fill:currentColor;opacity:.15;animation:aipanel-ongoing-chase 1s infinite}@keyframes aipanel-ongoing-chase{0%,12.4%{opacity:1}12.5%,24.9%{opacity:.6}25%,37.4%{opacity:.35}37.5%,to{opacity:.15}}.aipanel-session-item.active .aipanel-session-state-pending{color:var(--ap-state-pending)}.aipanel-session-item.active .aipanel-session-state-completed{color:var(--ap-state-completed)}.aipanel-session-item.active .aipanel-session-state-ongoing{color:var(--ap-accent)}.aipanel-session-header-skeleton{padding:10px 12px 8px;border-bottom:1px solid var(--ap-border-faint);display:none;align-items:center;gap:8px}.aipanel-session-header-skeleton.visible{display:flex}.aipanel-skeleton-header-title{flex:1;height:12px;width:48px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-skeleton-header-btn{width:24px;height:24px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:50%}.aipanel-session-skeleton{flex:1;min-height:0;overflow-y:auto;padding:8px;display:none}.aipanel-session-skeleton.visible{display:block}.aipanel-skeleton-item{display:flex;align-items:center;gap:8px;height:32px;box-sizing:border-box;padding:0 8px;border-radius:8px;margin-bottom:2px;background:var(--ap-skeleton-bg)}.aipanel-skeleton-title{flex:1 1 auto;height:13px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-skeleton-meta{flex:none;width:32px;height:12px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-session-empty{padding:32px 16px;text-align:center;color:var(--ap-text-tertiary);font-size:12px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}
1
+ .aipanel-session-list{width:236px;background:var(--ap-bg-secondary);border-right:1px solid var(--ap-border-faint);display:flex;flex-direction:column;flex-shrink:0;transition:width .2s ease}.aipanel-session-list.collapsed{width:0;overflow:hidden}.aipanel-session-list.collapsed .aipanel-session-list-header,.aipanel-session-list.collapsed .aipanel-session-list-content{display:none}.aipanel-session-list-header{padding:10px 8px 8px 12px;display:flex;align-items:center;justify-content:space-between;gap:8px;background:var(--ap-bg-secondary);border-bottom:1px solid var(--ap-border-faint)}.aipanel-session-list-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:600;letter-spacing:.02em;line-height:18px;color:var(--ap-text-tertiary)}.aipanel-new-session-btn{flex:none;width:24px;height:24px;border-radius:50%;border:1px solid var(--ap-border-secondary);background:var(--ap-elevated-fill);color:var(--ap-text-primary);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background-color .2s ease,border-color .2s ease,color .2s ease}.aipanel-new-session-btn svg{display:block}.aipanel-new-session-btn:hover{background:var(--ap-elevated-hover);color:var(--ap-text-primary)}.aipanel-new-session-btn:active{background:var(--ap-press-bg)}.aipanel-new-session-btn:focus-visible{outline:none;box-shadow:0 0 0 2px var(--ap-accent-bg)}.aipanel-session-list-content{flex:1;min-height:0;overflow-y:auto;padding:8px;position:relative;display:flex;flex-direction:column;gap:2px}.aipanel-session-item{position:relative;box-sizing:border-box;display:flex;align-items:center;gap:8px;flex:none;height:32px;padding:0 8px;border-radius:8px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;color:var(--ap-text-primary);transition:background-color .15s ease}.aipanel-session-item:hover{background:var(--ap-hover-bg)}.aipanel-session-item:active{background:var(--ap-press-bg)}.aipanel-session-item.active{background:var(--ap-hover-bg)}.aipanel-session-title-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:400;line-height:20px}.aipanel-session-meta{flex:none;margin-left:auto;font-size:12px;line-height:20px;color:var(--ap-text-tertiary);white-space:nowrap;transition:opacity .15s ease}.aipanel-session-item:hover .aipanel-session-meta{opacity:0}.aipanel-session-delete-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);width:16px;height:16px;border:none;border-radius:4px;background:transparent;color:var(--ap-text-tertiary);font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s ease,background-color .15s ease,color .15s ease}.aipanel-session-item:hover .aipanel-session-delete-btn{opacity:1}.aipanel-session-delete-btn:hover{background:transparent;color:var(--ap-text-primary)}.aipanel-session-state{position:relative;flex:none;width:10px;height:10px;margin-right:-2px}.aipanel-session-state-pending:before,.aipanel-session-state-completed:before{content:"";position:absolute;inset:0;border-radius:50%;background:currentColor;opacity:.1}.aipanel-session-state-pending:after,.aipanel-session-state-completed:after{content:"";position:absolute;inset:20%;border-radius:50%;background:currentColor}.aipanel-session-state-pending{color:var(--ap-state-pending)}.aipanel-session-state-completed{color:var(--ap-state-completed)}.aipanel-session-state-ongoing{color:var(--ap-state-ongoing)}.aipanel-session-ongoing-cell{fill:currentColor;opacity:.15;animation:aipanel-ongoing-chase 1s infinite}@keyframes aipanel-ongoing-chase{0%,12.4%{opacity:1}12.5%,24.9%{opacity:.6}25%,37.4%{opacity:.35}37.5%,to{opacity:.15}}.aipanel-session-item.active .aipanel-session-state-pending{color:var(--ap-state-pending)}.aipanel-session-item.active .aipanel-session-state-completed{color:var(--ap-state-completed)}.aipanel-session-item.active .aipanel-session-state-ongoing{color:var(--ap-accent)}.aipanel-session-header-skeleton{padding:10px 12px 8px;border-bottom:1px solid var(--ap-border-faint);display:none;align-items:center;gap:8px}.aipanel-session-header-skeleton.visible{display:flex}.aipanel-skeleton-header-title{flex:1;height:12px;width:48px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-skeleton-header-btn{width:24px;height:24px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:50%}.aipanel-session-skeleton{flex:1;min-height:0;overflow-y:auto;padding:8px;display:none}.aipanel-session-skeleton.visible{display:block}.aipanel-skeleton-item{display:flex;align-items:center;gap:8px;height:32px;box-sizing:border-box;padding:0 8px;border-radius:8px;margin-bottom:2px;background:var(--ap-skeleton-bg)}.aipanel-skeleton-title{flex:1 1 auto;height:13px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-skeleton-meta{flex:none;width:32px;height:12px;background:var(--ap-skeleton-gradient);background-size:200% 100%;animation:skeleton-loading 1.5s ease-in-out infinite;border-radius:4px}.aipanel-session-empty{padding:32px 16px;text-align:center;color:var(--ap-text-tertiary);font-size:12px}@keyframes skeleton-loading{0%{background-position:200% 0}to{background-position:-200% 0}}
@@ -1 +1 @@
1
- .aipanel-widget{--ap-bg-main: #ffffff;--ap-bg-secondary: #f9fafb;--ap-bg-tertiary: #ebeef2;--ap-overlay-bg: rgba(249, 250, 251, .92);--ap-text-primary: #0f1115;--ap-text-secondary: #61666b;--ap-text-tertiary: #81858c;--ap-text-placeholder: #adb2b8;--ap-border-faint: rgba(15, 17, 21, .04);--ap-border-primary: rgba(15, 17, 21, .1);--ap-border-secondary: rgba(15, 17, 21, .12);--ap-hover-bg: rgba(38, 49, 72, .06);--ap-elevated-fill: #ffffff;--ap-elevated-hover: #f1f3f5;--ap-press-bg: rgba(38, 49, 72, .1);--ap-primary: #0f1115;--ap-primary-hover: #43454a;--ap-on-primary: #ffffff;--ap-accent: #4176e6;--ap-accent-hover: #5686fe;--ap-accent-bg: rgba(65, 118, 230, .1);--ap-danger: #ec1313;--ap-danger-hover: #c40f0f;--ap-state-pending: #f59e0b;--ap-state-completed: #22c55e;--ap-state-ongoing: #5686fe;--ap-tooltip-bg: #1e1e1e;--ap-dialog-overlay: rgba(0, 0, 0, .24);--ap-dialog-bg: #ffffff;--ap-scrollbar-thumb: #e5e5e5;--ap-scrollbar-thumb-hover: #d4d4d4;--ap-thinking-glow: rgba(86, 134, 254, .3);--ap-thinking-glow-strong: rgba(86, 134, 254, .55);--ap-skeleton-bg: rgba(15, 17, 21, .06);--ap-skeleton-gradient: linear-gradient( 90deg, rgba(15, 17, 21, .04) 25%, rgba(15, 17, 21, .1) 50%, rgba(15, 17, 21, .04) 75% );--ap-shadow-sm: 0 1px 2px rgba(15, 17, 21, .04), 0 1px 3px rgba(15, 17, 21, .06);--ap-shadow-md: 0 2px 8px rgba(15, 17, 21, .06), 0 4px 16px rgba(15, 17, 21, .06);--ap-shadow-lg: 0 0 0 .5px rgba(15, 17, 21, .06), 0 4px 16px rgba(15, 17, 21, .08), 0 16px 48px rgba(15, 17, 21, .1);--ap-shadow-xl: 0 0 0 .5px rgba(15, 17, 21, .08), 0 8px 32px rgba(15, 17, 21, .12), 0 24px 72px rgba(15, 17, 21, .14);--ap-shadow-accent: 0 1px 2px rgba(65, 118, 230, .14), 0 0 0 1px rgba(65, 118, 230, .18);position:fixed;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}.aipanel-widget.aipanel-theme-dark{--ap-bg-main: #151517;--ap-bg-secondary: #1b1b1c;--ap-bg-tertiary: #2c2c2e;--ap-overlay-bg: rgba(21, 21, 23, .92);--ap-text-primary: #f9fafb;--ap-text-secondary: #cfd3d6;--ap-text-tertiary: #adb2b8;--ap-text-placeholder: #81858c;--ap-border-faint: rgba(255, 255, 255, .06);--ap-border-primary: rgba(255, 255, 255, .12);--ap-border-secondary: rgba(255, 255, 255, .16);--ap-hover-bg: rgba(255, 255, 255, .08);--ap-elevated-fill: #43454a;--ap-elevated-hover: #353638;--ap-press-bg: rgba(255, 255, 255, .14);--ap-primary: #f9fafb;--ap-primary-hover: #ebeef2;--ap-on-primary: #0f1115;--ap-accent: #679efe;--ap-accent-hover: #5686fe;--ap-accent-bg: rgba(103, 158, 254, .16);--ap-danger: #f25a5a;--ap-danger-hover: #ff8383;--ap-state-pending: #f59e0b;--ap-state-completed: #22c55e;--ap-state-ongoing: #5686fe;--ap-tooltip-bg: #282828;--ap-dialog-overlay: rgba(0, 0, 0, .5);--ap-dialog-bg: #2c2c2e;--ap-scrollbar-thumb: #3c3c3d;--ap-scrollbar-thumb-hover: #545557;--ap-thinking-glow: rgba(103, 158, 254, .35);--ap-thinking-glow-strong: rgba(103, 158, 254, .6);--ap-skeleton-bg: rgba(255, 255, 255, .07);--ap-skeleton-gradient: linear-gradient( 90deg, rgba(255, 255, 255, .05) 25%, rgba(255, 255, 255, .12) 50%, rgba(255, 255, 255, .05) 75% );--ap-shadow-sm: 0 1px 2px rgba(0, 0, 0, .3), 0 1px 3px rgba(0, 0, 0, .24);--ap-shadow-md: 0 2px 8px rgba(0, 0, 0, .3), 0 4px 16px rgba(0, 0, 0, .2);--ap-shadow-lg: 0 0 0 .5px rgba(255, 255, 255, .06), 0 4px 16px rgba(0, 0, 0, .3), 0 16px 48px rgba(0, 0, 0, .25);--ap-shadow-xl: 0 0 0 .5px rgba(255, 255, 255, .08), 0 8px 32px rgba(0, 0, 0, .36), 0 24px 72px rgba(0, 0, 0, .3);--ap-shadow-accent: 0 1px 2px rgba(103, 158, 254, .2), 0 0 0 1px rgba(103, 158, 254, .25)}@supports not selector(::-webkit-scrollbar){.aipanel-widget,.aipanel-widget *{scrollbar-width:thin;scrollbar-color:var(--ap-scrollbar-thumb) transparent}}.aipanel-widget ::-webkit-scrollbar,.aipanel-widget *::-webkit-scrollbar{width:8px;height:8px}.aipanel-widget ::-webkit-scrollbar-track,.aipanel-widget *::-webkit-scrollbar-track{background:transparent}.aipanel-widget ::-webkit-scrollbar-thumb,.aipanel-widget *::-webkit-scrollbar-thumb{border-radius:4px;background:var(--ap-scrollbar-thumb)}.aipanel-widget ::-webkit-scrollbar-thumb:hover,.aipanel-widget *::-webkit-scrollbar-thumb:hover{background:var(--ap-scrollbar-thumb-hover)}.aipanel-widget ::-webkit-scrollbar-corner,.aipanel-widget *::-webkit-scrollbar-corner{background:transparent}.aipanel-chat{position:fixed;bottom:20px;width:700px;height:86vh;max-height:calc(100vh - 40px);background:var(--ap-bg-main);border-radius:16px;box-shadow:var(--ap-shadow-lg);overflow:hidden;opacity:0;visibility:hidden;transform:translate3d(var(---chatAnimationOrigin\.x),var(---chatAnimationOrigin\.y),0) scale(.95);transition:all .3s ease;display:flex;flex-direction:column;z-index:99999}.aipanel-chat.open{opacity:1;visibility:visible;transform:translateZ(0) scale(1)}.aipanel-chat.no-transition,.aipanel-chat.no-transition.open{transition:none!important}.aipanel-chat.minimized{width:320px;height:320px}.aipanel-chat.minimized .aipanel-iframe-container{margin-top:-146px}.aipanel-chat-content{display:flex;flex:1;overflow:hidden}.aipanel-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 #3b82f666,0 0 0 2px #3b82f633;animation:slideDown .3s ease;z-index:10000000;display:flex;align-items:center;gap:10px}.aipanel-notification:before{content:"\1f4a1";font-size:16px}.aipanel-dialog-overlay{position:fixed;inset:0;background:var(--ap-dialog-overlay);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:9999999;animation:fadeIn .2s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.aipanel-dialog{width:min(380px,100%);background:var(--ap-dialog-bg);border-radius:24px;padding:24px 24px 20px;box-shadow:var(--ap-shadow-xl);animation:scaleIn .2s ease}@keyframes scaleIn{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}.aipanel-dialog-content{margin-bottom:20px}.aipanel-dialog-message{font-size:14px;line-height:22px;font-weight:400;color:var(--ap-text-primary)}.aipanel-dialog-actions{display:flex;gap:8px;justify-content:flex-end}.aipanel-dialog-btn{height:36px;padding:0 20px;border-radius:999px;border:1px solid transparent;font-size:14px;line-height:22px;font-weight:500;cursor:pointer;transition:all .2s}.aipanel-dialog-btn.cancel{background:transparent;border-color:var(--ap-border-primary);color:var(--ap-text-secondary)}.aipanel-dialog-btn.cancel:hover{background:var(--ap-hover-bg);color:var(--ap-text-primary)}.aipanel-dialog-btn.confirm{background:var(--ap-danger);color:#fff}.aipanel-dialog-btn.confirm:hover{background:var(--ap-danger-hover)}@keyframes slideDown{0%{transform:translate(-50%) translateY(-100%);opacity:0}to{transform:translate(-50%) translateY(0);opacity:1}}.aipanel-page-notification{position:fixed;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 #3b82f666,0 0 0 2px #3b82f633;animation:slideDown .3s ease;z-index:2147483647;display:flex;align-items:center;gap:10px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.aipanel-page-notification:before{content:"\1f4a1";font-size:16px}.aipanel-element-highlight{position:fixed;pointer-events:none;z-index:999998;border-radius:4px}#vue-inspector-container{display:none!important}.aipanel-element-tooltip{position:fixed;background:var(--ap-tooltip-bg);color:#fff;padding:8px 12px;border-radius:6px;font-size:12px;z-index:9999998;box-shadow:var(--ap-shadow-md);max-width:300px;pointer-events:none;line-height:1}.aipanel-tooltip-tag{font-weight:500;margin-bottom:4px;word-break:break-all}.aipanel-tooltip-file{font-size:11px;color:var(--ap-text-placeholder);word-break:break-all}.aipanel-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){.aipanel-chat{width:calc(100vw - 40px);height:calc(100vh - 100px)}}body.has-aipanel-split{transition:padding .3s ease;min-width:auto}body.has-aipanel-split-right{padding-right:var(--aipanel-split-width, 500px)}body.has-aipanel-split-left{padding-left:var(--aipanel-split-width, 500px)}.aipanel-widget.extension-mode{position:relative;width:100%;height:100%;display:flex}.aipanel-widget.extension-mode .aipanel-select-mode-hint,.aipanel-widget.extension-mode .aipanel-dialog-overlay{position:absolute}
1
+ .aipanel-widget{--ap-bg-main: #ffffff;--ap-bg-secondary: #f9fafb;--ap-bg-tertiary: #ebeef2;--ap-overlay-bg: rgba(249, 250, 251, .92);--ap-text-primary: #0f1115;--ap-text-secondary: #61666b;--ap-text-tertiary: #81858c;--ap-text-placeholder: #adb2b8;--ap-border-faint: rgba(15, 17, 21, .04);--ap-border-primary: rgba(15, 17, 21, .1);--ap-border-secondary: rgba(15, 17, 21, .12);--ap-hover-bg: rgba(38, 49, 72, .06);--ap-elevated-fill: #ffffff;--ap-elevated-hover: #f1f3f5;--ap-press-bg: rgba(38, 49, 72, .1);--ap-primary: #0f1115;--ap-primary-hover: #43454a;--ap-on-primary: #ffffff;--ap-accent: #4176e6;--ap-accent-hover: #5686fe;--ap-accent-bg: rgba(65, 118, 230, .1);--ap-danger: #ec1313;--ap-danger-hover: #c40f0f;--ap-state-pending: #f59e0b;--ap-state-completed: #22c55e;--ap-state-ongoing: #5686fe;--ap-tooltip-bg: #1e1e1e;--ap-dialog-overlay: rgba(0, 0, 0, .24);--ap-dialog-bg: #ffffff;--ap-scrollbar-thumb: #e5e5e5;--ap-scrollbar-thumb-hover: #d4d4d4;--ap-thinking-glow: rgba(86, 134, 254, .3);--ap-thinking-glow-strong: rgba(86, 134, 254, .55);--ap-skeleton-bg: rgba(15, 17, 21, .06);--ap-skeleton-gradient: linear-gradient( 90deg, rgba(15, 17, 21, .04) 25%, rgba(15, 17, 21, .1) 50%, rgba(15, 17, 21, .04) 75% );--ap-shadow-sm: 0 1px 2px rgba(15, 17, 21, .04), 0 1px 3px rgba(15, 17, 21, .06);--ap-shadow-md: 0 2px 8px rgba(15, 17, 21, .06), 0 4px 16px rgba(15, 17, 21, .06);--ap-shadow-lg: 0 0 0 .5px rgba(15, 17, 21, .06), 0 4px 16px rgba(15, 17, 21, .08), 0 16px 48px rgba(15, 17, 21, .1);--ap-shadow-xl: 0 0 0 .5px rgba(15, 17, 21, .08), 0 8px 32px rgba(15, 17, 21, .12), 0 24px 72px rgba(15, 17, 21, .14);--ap-shadow-accent: 0 1px 2px rgba(65, 118, 230, .14), 0 0 0 1px rgba(65, 118, 230, .18);position:fixed;z-index:999999;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}.aipanel-widget.aipanel-theme-dark{--ap-bg-main: #151517;--ap-bg-secondary: #1b1b1c;--ap-bg-tertiary: #2c2c2e;--ap-overlay-bg: rgba(21, 21, 23, .92);--ap-text-primary: #f9fafb;--ap-text-secondary: #cfd3d6;--ap-text-tertiary: #adb2b8;--ap-text-placeholder: #81858c;--ap-border-faint: rgba(255, 255, 255, .06);--ap-border-primary: rgba(255, 255, 255, .12);--ap-border-secondary: rgba(255, 255, 255, .16);--ap-hover-bg: rgba(255, 255, 255, .08);--ap-elevated-fill: #43454a;--ap-elevated-hover: #353638;--ap-press-bg: rgba(255, 255, 255, .14);--ap-primary: #f9fafb;--ap-primary-hover: #ebeef2;--ap-on-primary: #0f1115;--ap-accent: #679efe;--ap-accent-hover: #5686fe;--ap-accent-bg: rgba(103, 158, 254, .16);--ap-danger: #f25a5a;--ap-danger-hover: #ff8383;--ap-state-pending: #f59e0b;--ap-state-completed: #22c55e;--ap-state-ongoing: #5686fe;--ap-tooltip-bg: #282828;--ap-dialog-overlay: rgba(0, 0, 0, .5);--ap-dialog-bg: #2c2c2e;--ap-scrollbar-thumb: #3c3c3d;--ap-scrollbar-thumb-hover: #545557;--ap-thinking-glow: rgba(103, 158, 254, .35);--ap-thinking-glow-strong: rgba(103, 158, 254, .6);--ap-skeleton-bg: rgba(255, 255, 255, .07);--ap-skeleton-gradient: linear-gradient( 90deg, rgba(255, 255, 255, .05) 25%, rgba(255, 255, 255, .12) 50%, rgba(255, 255, 255, .05) 75% );--ap-shadow-sm: 0 1px 2px rgba(0, 0, 0, .3), 0 1px 3px rgba(0, 0, 0, .24);--ap-shadow-md: 0 2px 8px rgba(0, 0, 0, .3), 0 4px 16px rgba(0, 0, 0, .2);--ap-shadow-lg: 0 0 0 .5px rgba(255, 255, 255, .06), 0 4px 16px rgba(0, 0, 0, .3), 0 16px 48px rgba(0, 0, 0, .25);--ap-shadow-xl: 0 0 0 .5px rgba(255, 255, 255, .08), 0 8px 32px rgba(0, 0, 0, .36), 0 24px 72px rgba(0, 0, 0, .3);--ap-shadow-accent: 0 1px 2px rgba(103, 158, 254, .2), 0 0 0 1px rgba(103, 158, 254, .25)}@supports not selector(::-webkit-scrollbar){.aipanel-widget,.aipanel-widget *{scrollbar-width:thin;scrollbar-color:var(--ap-scrollbar-thumb) transparent}}.aipanel-widget ::-webkit-scrollbar,.aipanel-widget *::-webkit-scrollbar{width:8px;height:8px}.aipanel-widget ::-webkit-scrollbar-track,.aipanel-widget *::-webkit-scrollbar-track{background:transparent}.aipanel-widget ::-webkit-scrollbar-thumb,.aipanel-widget *::-webkit-scrollbar-thumb{border-radius:4px;background:var(--ap-scrollbar-thumb)}.aipanel-widget ::-webkit-scrollbar-thumb:hover,.aipanel-widget *::-webkit-scrollbar-thumb:hover{background:var(--ap-scrollbar-thumb-hover)}.aipanel-widget ::-webkit-scrollbar-corner,.aipanel-widget *::-webkit-scrollbar-corner{background:transparent}.aipanel-chat{position:fixed;bottom:20px;width:700px;height:86vh;max-height:calc(100vh - 40px);background:var(--ap-bg-main);border-radius:16px;box-shadow:var(--ap-shadow-lg);overflow:hidden;opacity:0;visibility:hidden;transform:translate3d(var(---chatAnimationOrigin\.x),var(---chatAnimationOrigin\.y),0) scale(.95);transition:all .3s ease;display:flex;flex-direction:column;z-index:99999}.aipanel-chat.open{opacity:1;visibility:visible;transform:translateZ(0) scale(1)}.aipanel-chat.no-transition,.aipanel-chat.no-transition.open{transition:none!important}.aipanel-chat.minimized{width:320px;height:320px}.aipanel-chat.minimized .aipanel-iframe-container{margin-top:-146px}.aipanel-chat-content{display:flex;flex:1;overflow:hidden}.aipanel-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 #3b82f666,0 0 0 2px #3b82f633;animation:slideDown .3s ease;z-index:10000000;display:flex;align-items:center;gap:10px}.aipanel-notification:before{content:"\1f4a1";font-size:16px}.aipanel-dialog-overlay{position:fixed;inset:0;background:var(--ap-dialog-overlay);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);display:flex;align-items:center;justify-content:center;z-index:9999999;animation:fadeIn .2s ease}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.aipanel-dialog{width:min(380px,100%);background:var(--ap-dialog-bg);border-radius:24px;padding:24px 24px 20px;box-shadow:var(--ap-shadow-xl);animation:scaleIn .2s ease}@keyframes scaleIn{0%{transform:scale(.9);opacity:0}to{transform:scale(1);opacity:1}}.aipanel-dialog-content{margin-bottom:20px}.aipanel-dialog-message{font-size:14px;line-height:22px;font-weight:400;color:var(--ap-text-primary)}.aipanel-dialog-actions{display:flex;gap:8px;justify-content:flex-end}.aipanel-dialog-btn{height:36px;padding:0 20px;border-radius:999px;border:1px solid transparent;font-size:14px;line-height:22px;font-weight:500;cursor:pointer;transition:all .2s}.aipanel-dialog-btn.cancel{background:transparent;border-color:var(--ap-border-primary);color:var(--ap-text-secondary)}.aipanel-dialog-btn.cancel:hover{background:var(--ap-hover-bg);color:var(--ap-text-primary)}.aipanel-dialog-btn.confirm{background:var(--ap-danger);color:#fff}.aipanel-dialog-btn.confirm:hover{background:var(--ap-danger-hover)}@keyframes slideDown{0%{transform:translate(-50%) translateY(-100%);opacity:0}to{transform:translate(-50%) translateY(0);opacity:1}}.aipanel-page-notification{position:fixed;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 #3b82f666,0 0 0 2px #3b82f633;animation:slideDown .3s ease;z-index:2147483647;display:flex;align-items:center;gap:10px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.aipanel-page-notification:before{content:"\1f4a1";font-size:16px}.aipanel-element-highlight{position:fixed;pointer-events:none;z-index:999998;border-radius:4px}.aipanel-element-highlight.breathing{animation:aipanel-highlight-breath 2s ease-in-out 2}@keyframes aipanel-highlight-breath{0%,to{opacity:.25;transform:scale(1)}50%{opacity:1;transform:scale(1.01)}}#vue-inspector-container{display:none!important}.aipanel-element-tooltip{position:fixed;background:var(--ap-tooltip-bg);color:#fff;padding:8px 12px;border-radius:6px;font-size:12px;z-index:9999998;box-shadow:var(--ap-shadow-md);max-width:300px;pointer-events:none;line-height:1}.aipanel-tooltip-tag{font-weight:500;margin-bottom:4px;word-break:break-all}.aipanel-tooltip-file{font-size:11px;color:var(--ap-text-placeholder);word-break:break-all}@media(max-width:768px){.aipanel-chat{width:calc(100vw - 40px);height:calc(100vh - 100px)}}body.has-aipanel-split{transition:padding .3s ease;min-width:auto}body.has-aipanel-split-right{padding-right:var(--aipanel-split-width, 500px)}body.has-aipanel-split-left{padding-left:var(--aipanel-split-width, 500px)}.aipanel-widget.extension-mode{position:relative;width:100%;height:100%;display:flex}.aipanel-widget.extension-mode .aipanel-select-mode-hint,.aipanel-widget.extension-mode .aipanel-dialog-overlay{position:absolute}
@@ -82,7 +82,7 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
82
82
  providerSidebar: { type: Boolean, required: false, default: false },
83
83
  sidebarCollapseControl: { type: String, required: false, default: "host" }
84
84
  },
85
- emits: ["update:open", "update:selectMode", "update:sessionListCollapsed", "update:currentSessionId", "update:selectedElements", "update:theme", "update:thinking", "update:splitPanelWidth", "toggle", "close", "toggle-session-list", "toggle-select-mode", "toggle-theme", "create-session", "select-session", "delete-session", "click-selected-node", "remove-selected-node", "clear-selected-nodes", "empty-action", "frame-loaded", "thinking-change", "split-panel-width-change"],
85
+ emits: ["update:open", "update:selectMode", "update:sessionListCollapsed", "update:currentSessionId", "update:selectedElements", "update:theme", "update:thinking", "update:splitPanelWidth", "toggle", "close", "toggle-session-list", "toggle-select-mode", "toggle-theme", "create-session", "select-session", "delete-session", "click-selected-node", "locate-node", "remove-selected-node", "clear-selected-nodes", "empty-action", "frame-loaded", "thinking-change", "split-panel-width-change"],
86
86
  setup(__props, { expose: __expose, emit: __emit }) {
87
87
  (0, import_vue.useCssVars)((_ctx) => ({
88
88
  "-chatAnimationOrigin.x": chatAnimationOrigin.value.x,
@@ -246,12 +246,32 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
246
246
  onDeleteSession: (session) => emit("delete-session", session),
247
247
  showConfirmDialog
248
248
  });
249
+ const {
250
+ highlightVisible,
251
+ highlightBreathing,
252
+ highlightStyle,
253
+ tooltipVisible,
254
+ tooltipStyle,
255
+ tooltipContent,
256
+ flashElement
257
+ } = (0, import_use_inspector.useInspector)({
258
+ selectMode: (0, import_vue2.toRef)(props, "selectMode"),
259
+ onAddSelectedNode: (element) => {
260
+ emit("click-selected-node", element);
261
+ },
262
+ onExitSelectMode: () => {
263
+ emit("update:selectMode", false);
264
+ emit("toggle-select-mode", false);
265
+ }
266
+ });
249
267
  const {
250
268
  bubbleVisible,
251
269
  hasSelectedElements,
252
270
  selectedElementItems,
271
+ consumePendingLocate,
253
272
  handleClearSelectedNodes,
254
273
  handleClickSelectedNode,
274
+ handleLocateSelectedElement,
255
275
  handleRemoveSelectedNode,
256
276
  handleToggleSelectMode
257
277
  } = (0, import_use_selection.useSelection)({
@@ -271,17 +291,11 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
271
291
  emit("clear-selected-nodes");
272
292
  emit("update:selectedElements", []);
273
293
  },
274
- showConfirmDialog
275
- });
276
- const { highlightVisible, highlightStyle, tooltipVisible, tooltipStyle, tooltipContent } = (0, import_use_inspector.useInspector)({
277
- selectMode: (0, import_vue2.toRef)(props, "selectMode"),
278
- onAddSelectedNode: (element) => {
279
- emit("click-selected-node", element);
280
- },
281
- onExitSelectMode: () => {
282
- emit("update:selectMode", false);
283
- emit("toggle-select-mode", false);
284
- }
294
+ showConfirmDialog,
295
+ // 点已选节点时复用选择模式的高亮框闪烁;扩展模式下挂件在侧栏,不操作页面
296
+ flashHighlight: flashElement,
297
+ locateInPage: () => !isExtensionMode.value,
298
+ notify: (message) => showNotification(message)
285
299
  });
286
300
  const bubbleOffset = (0, import_vue2.ref)(void 0);
287
301
  const {
@@ -416,12 +430,21 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
416
430
  }
417
431
  }
418
432
  }
433
+ if (event.data?.type === import_core.WIDGET_MSG.LOCATE_NODE && event.data.element) {
434
+ const element = event.data.element;
435
+ if (localDisplayMode.value === "extension") {
436
+ emit("locate-node", element);
437
+ } else {
438
+ handleLocateSelectedElement(element);
439
+ }
440
+ }
419
441
  };
420
442
  (0, import_vue2.onMounted)(() => {
421
443
  if (typeof window !== "undefined") {
422
444
  window.addEventListener("resize", handleWindowResize);
423
445
  window.addEventListener("message", handleIframeMessage);
424
446
  }
447
+ void consumePendingLocate();
425
448
  });
426
449
  (0, import_vue2.onUnmounted)(() => {
427
450
  if (typeof window !== "undefined") {
@@ -610,7 +633,7 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
610
633
  return dialogResolve;
611
634
  }, set dialogResolve(v) {
612
635
  dialogResolve = v;
613
- }, showConfirmDialog, handleDialogConfirm, handleDialogCancel, frameRef, triggerRef, sendMessageToIframe, localSessionListCollapsed, localDisplayMode, localSplitPosition, minimized, promptDockVisible, reviewPanelVisible, isRestoring, iframeLoaded, iframeReady, splitPanelWidth, syncStateToIframe, handleFrameLoaded, handleToggleDisplayMode, buttonActive, containerClasses, iframeSource, sessionListTitle, resolvedTheme, handleClose, handleEmptyAction, handleToggle, handleToggleSessionList, handleToggleTheme, sessionItems, handleCreateSession, handleDeleteSession, handleSelectSession, bubbleVisible, hasSelectedElements, selectedElementItems, handleClearSelectedNodes, handleClickSelectedNode, handleRemoveSelectedNode, handleToggleSelectMode, highlightVisible, highlightStyle, tooltipVisible, tooltipStyle, tooltipContent, bubbleOffset, effectiveMode, isSplitMode, isExtensionMode, panelWidth, splitConfig, splitPosition, handleResize, handleSplitToggle, handleTogglePosition, handleToggleMinimize, handleTogglePromptDock, handleToggleReviewPanel, handleRefresh, windowWidth, windowHeight, handleWindowResize, handleIframeMessage, bubbleQuadrant, isBubbleOnRightSide, chatPositionStyle, handleBubbleOffsetChange, handleResizeStart, handleResizeEnd, chatAnimationOrigin, isDragging, get wasOpenBeforeDrag() {
636
+ }, showConfirmDialog, handleDialogConfirm, handleDialogCancel, frameRef, triggerRef, sendMessageToIframe, localSessionListCollapsed, localDisplayMode, localSplitPosition, minimized, promptDockVisible, reviewPanelVisible, isRestoring, iframeLoaded, iframeReady, splitPanelWidth, syncStateToIframe, handleFrameLoaded, handleToggleDisplayMode, buttonActive, containerClasses, iframeSource, sessionListTitle, resolvedTheme, handleClose, handleEmptyAction, handleToggle, handleToggleSessionList, handleToggleTheme, sessionItems, handleCreateSession, handleDeleteSession, handleSelectSession, highlightVisible, highlightBreathing, highlightStyle, tooltipVisible, tooltipStyle, tooltipContent, flashElement, bubbleVisible, hasSelectedElements, selectedElementItems, consumePendingLocate, handleClearSelectedNodes, handleClickSelectedNode, handleLocateSelectedElement, handleRemoveSelectedNode, handleToggleSelectMode, bubbleOffset, effectiveMode, isSplitMode, isExtensionMode, panelWidth, splitConfig, splitPosition, handleResize, handleSplitToggle, handleTogglePosition, handleToggleMinimize, handleTogglePromptDock, handleToggleReviewPanel, handleRefresh, windowWidth, windowHeight, handleWindowResize, handleIframeMessage, bubbleQuadrant, isBubbleOnRightSide, chatPositionStyle, handleBubbleOffsetChange, handleResizeStart, handleResizeEnd, chatAnimationOrigin, isDragging, get wasOpenBeforeDrag() {
614
637
  return wasOpenBeforeDrag;
615
638
  }, set wasOpenBeforeDrag(v) {
616
639
  wasOpenBeforeDrag = v;
@@ -761,12 +784,12 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
761
784
  (0, import_vue3.withDirectives)((0, import_vue3.createElementVNode)(
762
785
  "div",
763
786
  {
764
- class: "aipanel-element-highlight",
787
+ class: (0, import_vue3.normalizeClass)(["aipanel-element-highlight", { breathing: $setup.highlightBreathing }]),
765
788
  style: (0, import_vue3.normalizeStyle)($setup.highlightStyle)
766
789
  },
767
790
  null,
768
- 4
769
- /* STYLE */
791
+ 6
792
+ /* CLASS, STYLE */
770
793
  ), [
771
794
  [import_vue3.vShow, $setup.highlightVisible]
772
795
  ]),
@@ -1,4 +1,5 @@
1
1
  import type { AIPanelWidgetProps } from "./types";
2
+ import { type AIPanelSelectedElement } from "@aipanel/core";
2
3
  declare var __VLS_13: {}, __VLS_29: {}, __VLS_32: {}, __VLS_35: {}, __VLS_38: {}, __VLS_41: {}, __VLS_44: {}, __VLS_47: {}, __VLS_50: {};
3
4
  type __VLS_Slots = {} & {
4
5
  'button-icon'?: (props: typeof __VLS_13) => any;
@@ -57,7 +58,7 @@ declare const __VLS_base: import("vue").DefineComponent<AIPanelWidgetProps, {
57
58
  hotkeyLabel: string;
58
59
  splitPanelWidth: number;
59
60
  currentSessionId: string | null;
60
- selectedElements: import("@aipanel/core").AIPanelSelectedElement[];
61
+ selectedElements: AIPanelSelectedElement[];
61
62
  splitMode: import("@aipanel/core").SplitModeOptions;
62
63
  hideBubble: boolean;
63
64
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
package/lib/index.cjs CHANGED
@@ -26,7 +26,7 @@ module.exports = __toCommonJS(lib_exports);
26
26
  var import_AI_panel_widget = require("./AI-panel-widget/index.cjs");
27
27
  __reExport(lib_exports, require("./AI-panel-widget/index.cjs"), module.exports);
28
28
  __reExport(lib_exports, require("./setup.cjs"), module.exports);
29
- const version = "1.3.7";
29
+ const version = "1.3.9";
30
30
  function install(app, options) {
31
31
  const components = [
32
32
  import_AI_panel_widget.AIPanelWidget
package/lib/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { App } from 'vue';
2
- declare const version = "1.3.7";
2
+ declare const version = "1.3.9";
3
3
  declare function install(app: App<any>, options?: any): void;
4
4
  export { install, version, };
5
5
  export * from './AI-panel-widget';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aipanel/ui",
3
- "version": "1.3.7",
3
+ "version": "1.3.9",
4
4
  "description": "Reusable AIPanel widget components built with Pagoda CLI",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
@@ -30,7 +30,7 @@
30
30
  "vue": "^3.5.0"
31
31
  },
32
32
  "dependencies": {
33
- "@aipanel/core": "1.3.7",
33
+ "@aipanel/core": "1.3.9",
34
34
  "css-selector-generator": "^3.9.2"
35
35
  },
36
36
  "scripts": {