@aipanel/ui 1.2.19 → 1.2.20

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.
@@ -1,24 +1,5 @@
1
1
  import { type Ref } from "vue";
2
2
  import type { AIPanelSelectedElement } from "../src/types";
3
- interface VueInspector {
4
- getTargetNode: (e: MouseEvent) => {
5
- targetNode: Element | null;
6
- params: {
7
- file?: string;
8
- line?: number;
9
- column?: number;
10
- } | null;
11
- };
12
- handleClick: (e: MouseEvent) => void;
13
- enable: () => void;
14
- disable: () => void;
15
- __aipanel_hooked?: boolean;
16
- }
17
- declare global {
18
- interface Window {
19
- __VUE_INSPECTOR__?: VueInspector;
20
- }
21
- }
22
3
  interface UseInspectorOptions {
23
4
  selectMode: Ref<boolean>;
24
5
  onAddSelectedNode: (element: AIPanelSelectedElement) => void;
@@ -1,17 +1,24 @@
1
1
  import { ref, watch, onMounted, onUnmounted, nextTick } from "vue";
2
- import { INSPECTOR_CHECK_INTERVAL, truncate } from "@aipanel/core";
2
+ import {
3
+ INSPECTOR_CHECK_INTERVAL,
4
+ listInspectorAdapters,
5
+ resolveInspectorAdapter,
6
+ truncate
7
+ } from "@aipanel/core";
3
8
  import getCssSelector from "css-selector-generator";
4
- const IGNORE_SELECTORS = [
5
- "#vue-inspector-container",
6
- ".aipanel-widget",
9
+ const WIDGET_ROOT_SELECTOR = ".aipanel-widget";
10
+ const WIDGET_IGNORE_SELECTORS = [
11
+ WIDGET_ROOT_SELECTOR,
7
12
  ".aipanel-element-highlight",
8
13
  ".aipanel-element-tooltip",
9
14
  ".aipanel-select-mode-hint",
10
15
  ".floating-bubble"
11
16
  ];
12
- const IGNORE_ATTRIBUTE = "data-v-inspector-ignore";
13
- const KEY_PROPS_DATA = "__v_inspector";
14
- const KEY_DATA = "data-v-inspector";
17
+ const IGNORE_SELECTORS = [
18
+ ...WIDGET_IGNORE_SELECTORS,
19
+ ...listInspectorAdapters().flatMap((adapter) => adapter.ignoreSelectors)
20
+ ];
21
+ const IGNORE_ATTRIBUTES = listInspectorAdapters().flatMap((adapter) => adapter.ignoreAttributes);
15
22
  function getDirectText(element) {
16
23
  const el = element;
17
24
  const text = el.innerText || element.textContent || "";
@@ -77,114 +84,27 @@ function getElementDescription(element) {
77
84
  ]
78
85
  });
79
86
  }
80
- function getFileInfoFromVueInstance(element) {
81
- const vue3Instance = element.__vueParentComponent;
82
- if (vue3Instance) {
83
- let current = vue3Instance;
84
- while (current) {
85
- const file = current.type?.__file || current.vnode?.type?.__file;
86
- if (file) {
87
- return { file, line: null, column: null };
88
- }
89
- current = current.parent;
90
- }
91
- }
92
- const vue2Instance = element.__vue__;
93
- if (vue2Instance) {
94
- let current = vue2Instance;
95
- while (current) {
96
- const file = current.$options?.__file;
97
- if (file) {
98
- return { file, line: null, column: null };
99
- }
100
- current = current.$parent;
101
- }
102
- }
103
- return null;
104
- }
105
87
  function shouldIgnoreElement(el) {
106
- if (el.hasAttribute(IGNORE_ATTRIBUTE)) return true;
88
+ if (IGNORE_ATTRIBUTES.some((attribute) => el.hasAttribute(attribute))) return true;
107
89
  for (const selector of IGNORE_SELECTORS) {
108
90
  if (el.closest(selector)) return true;
109
91
  }
110
92
  return false;
111
93
  }
112
- function getDataFromElement(el) {
113
- const vnodeData = el.__vnode?.props?.[KEY_PROPS_DATA];
114
- if (vnodeData) return vnodeData;
115
- const ctxVNode = el.__vnode?.ctx?.vnode;
116
- if (ctxVNode?.el === el) {
117
- const ctxData = ctxVNode.props?.[KEY_PROPS_DATA];
118
- if (ctxData) return ctxData;
119
- }
120
- const vueInstance = el.__vueParentComponent;
121
- let currentParent = vueInstance?.parent;
122
- while (currentParent) {
123
- if (currentParent.vnode?.el === el) {
124
- const parentData = currentParent.vnode.props?.[KEY_PROPS_DATA];
125
- if (parentData) return parentData;
126
- }
127
- currentParent = currentParent.parent;
128
- }
129
- const attr = el.getAttribute(KEY_DATA);
130
- return attr ?? void 0;
131
- }
132
- function findInspectorFileInfo(element) {
133
- let current = element;
134
- while (current) {
135
- if (shouldIgnoreElement(current)) {
136
- current = current.parentElement;
137
- continue;
138
- }
139
- const data = getDataFromElement(current);
140
- if (data) {
141
- const splitRE = /(.+):([\d]+):([\d]+)$/;
142
- const match = data.match(splitRE);
143
- if (match) {
144
- return {
145
- file: match[1],
146
- line: parseInt(match[2], 10),
147
- column: parseInt(match[3], 10)
148
- };
149
- }
150
- }
151
- current = current.parentElement;
94
+ function resolveElementSourceLocation(element) {
95
+ if (!element) return null;
96
+ for (const adapter of listInspectorAdapters()) {
97
+ const location = adapter.resolveSourceLocation(element);
98
+ if (location?.file) return location;
152
99
  }
153
100
  return null;
154
101
  }
155
- function mergeFileInfo(inspectorFileInfo, vueFileInfo) {
156
- if (!inspectorFileInfo?.file && !vueFileInfo?.file) {
157
- return { file: null, line: null, column: null };
158
- }
159
- const isNodeModules = (path) => path.includes("node_modules");
160
- if (inspectorFileInfo?.file && vueFileInfo?.file) {
161
- if (!isNodeModules(inspectorFileInfo.file)) {
162
- return inspectorFileInfo;
163
- } else if (!isNodeModules(vueFileInfo.file)) {
164
- return vueFileInfo;
165
- } else {
166
- return inspectorFileInfo;
167
- }
168
- } else if (inspectorFileInfo?.file) {
169
- return inspectorFileInfo;
170
- } else {
171
- return vueFileInfo;
172
- }
173
- }
174
102
  function getTargetElement(e) {
175
103
  if (!e.target || !(e.target instanceof Element)) return null;
176
104
  const el = e.target;
177
105
  if (shouldIgnoreElement(el)) return null;
178
106
  return el;
179
107
  }
180
- function getFileInfo(e, element) {
181
- let inspectorFileInfo = null;
182
- if (element) {
183
- inspectorFileInfo = findInspectorFileInfo(element);
184
- }
185
- const vueFileInfo = element ? getFileInfoFromVueInstance(element) : null;
186
- return mergeFileInfo(inspectorFileInfo, vueFileInfo);
187
- }
188
108
  function useInspector(options) {
189
109
  const highlightVisible = ref(false);
190
110
  const highlightStyle = ref({
@@ -218,7 +138,7 @@ function useInspector(options) {
218
138
  const uiElements = [highlight, tooltip, selectHint, floatingBubble];
219
139
  setPointerEventsNone(uiElements);
220
140
  const elementToHighlight = getTargetElement(e);
221
- const fileInfo = getFileInfo(e, elementToHighlight);
141
+ const fileInfo = resolveElementSourceLocation(elementToHighlight);
222
142
  setPointerEventsAuto(uiElements);
223
143
  if (elementToHighlight) {
224
144
  const widget = document.querySelector(".aipanel-widget");
@@ -228,9 +148,9 @@ function useInspector(options) {
228
148
  currentPrimaryBg = style.getPropertyValue("--ap-accent-bg").trim() || currentPrimaryBg;
229
149
  }
230
150
  const description = getElementDescription(elementToHighlight);
231
- const fileName = fileInfo.file ? fileInfo.file.split("/").pop() : "";
151
+ const fileName = fileInfo?.file ? fileInfo.file.split("/").pop() : "";
232
152
  let lineInfo = "";
233
- if (fileInfo.line) {
153
+ if (fileInfo?.line) {
234
154
  lineInfo = `:${fileInfo.line}`;
235
155
  if (fileInfo.column) {
236
156
  lineInfo += `:${fileInfo.column}`;
@@ -339,37 +259,30 @@ function useInspector(options) {
339
259
  }
340
260
  }
341
261
  const handleMouseMove = handleMouseMoveCore;
342
- function setupInspectorHook() {
343
- const inspector = window.__VUE_INSPECTOR__;
344
- if (!inspector || inspector.__aipanel_hooked) return;
345
- const originalHandleClick = inspector.handleClick.bind(inspector);
346
- inspector.handleClick = function(e) {
347
- if (options.selectMode.value) {
348
- const targetEl = e.target instanceof Element ? e.target : null;
349
- if (targetEl && targetEl.closest(".aipanel-widget")) {
350
- return originalHandleClick.call(inspector, e);
351
- }
352
- e.preventDefault();
353
- e.stopPropagation();
354
- const elementToSelect = getTargetElement(e);
355
- const fileInfo = getFileInfo(e, elementToSelect);
356
- if (elementToSelect) {
357
- const innerText = getDirectText(elementToSelect);
358
- const description = getElementDescription(elementToSelect);
359
- const elementInfo = {
360
- filePath: fileInfo.file,
361
- line: fileInfo.line,
362
- column: fileInfo.column,
363
- innerText: truncate(innerText, 200),
364
- description
365
- };
366
- options.onAddSelectedNode(elementInfo);
367
- }
368
- return;
369
- }
370
- return originalHandleClick.call(inspector, e);
371
- };
372
- inspector.__aipanel_hooked = true;
262
+ function handleElementClick(element) {
263
+ if (!options.selectMode.value) return false;
264
+ if (element?.closest(WIDGET_ROOT_SELECTOR)) return false;
265
+ const elementToSelect = element && !shouldIgnoreElement(element) ? element : null;
266
+ if (elementToSelect) {
267
+ const fileInfo = resolveElementSourceLocation(elementToSelect);
268
+ const innerText = getDirectText(elementToSelect);
269
+ const description = getElementDescription(elementToSelect);
270
+ const elementInfo = {
271
+ filePath: fileInfo?.file ?? null,
272
+ line: fileInfo?.line ?? null,
273
+ column: fileInfo?.column ?? null,
274
+ innerText: truncate(innerText, 200),
275
+ description
276
+ };
277
+ options.onAddSelectedNode(elementInfo);
278
+ }
279
+ return true;
280
+ }
281
+ function hookInspector() {
282
+ const adapter = resolveInspectorAdapter();
283
+ if (!adapter) return false;
284
+ adapter.onElementClick(handleElementClick);
285
+ return true;
373
286
  }
374
287
  function handleKeydown(e) {
375
288
  if (e.key === "Escape" && options.selectMode.value) {
@@ -379,17 +292,11 @@ function useInspector(options) {
379
292
  }
380
293
  }
381
294
  watch(options.selectMode, (newVal) => {
382
- const inspector = window.__VUE_INSPECTOR__;
295
+ resolveInspectorAdapter()?.setEnabled(newVal);
383
296
  if (newVal) {
384
- if (inspector) {
385
- inspector.enable();
386
- }
387
297
  document.addEventListener("mousemove", handleMouseMove);
388
298
  document.addEventListener("keydown", handleKeydown, true);
389
299
  } else {
390
- if (inspector) {
391
- inspector.disable();
392
- }
393
300
  document.removeEventListener("mousemove", handleMouseMove);
394
301
  document.removeEventListener("keydown", handleKeydown, true);
395
302
  highlightVisible.value = false;
@@ -397,19 +304,14 @@ function useInspector(options) {
397
304
  }
398
305
  });
399
306
  onMounted(() => {
400
- if (window.__VUE_INSPECTOR__) {
401
- setupInspectorHook();
402
- } else {
403
- inspectorCheckTimer = window.setInterval(() => {
404
- if (window.__VUE_INSPECTOR__) {
405
- setupInspectorHook();
406
- if (inspectorCheckTimer) {
407
- window.clearInterval(inspectorCheckTimer);
408
- inspectorCheckTimer = null;
409
- }
410
- }
411
- }, INSPECTOR_CHECK_INTERVAL);
412
- }
307
+ if (hookInspector()) return;
308
+ inspectorCheckTimer = window.setInterval(() => {
309
+ if (!hookInspector()) return;
310
+ if (inspectorCheckTimer) {
311
+ window.clearInterval(inspectorCheckTimer);
312
+ inspectorCheckTimer = null;
313
+ }
314
+ }, INSPECTOR_CHECK_INTERVAL);
413
315
  });
414
316
  onUnmounted(() => {
415
317
  if (inspectorCheckTimer) {
@@ -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;min-height:36px;padding:8px 10px;border-radius:8px;cursor:pointer;color:var(--ap-text-primary);transition:background-color .15s ease}.aipanel-widget.aipanel-theme-dark .aipanel-session-item{color:var(--ap-text-secondary)}.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:13px;font-weight:400;line-height:20px}.aipanel-session-meta{flex:none;margin-left:auto;font-size:12px;line-height:20px;color:var(--ap-text-placeholder);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:22px;height:22px;border:none;border-radius:6px;background:transparent;color:var(--ap-text-placeholder);font-size:16px;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;min-height:36px;box-sizing:border-box;padding:8px 10px;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;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}}
@@ -109,7 +109,7 @@ const _hoisted_8 = {
109
109
  class: "aipanel-session-state aipanel-session-state-completed",
110
110
  title: "\u5DF2\u5B8C\u6210"
111
111
  };
112
- const _hoisted_9 = { class: "aipanel-session-title-text" };
112
+ const _hoisted_9 = ["title"];
113
113
  const _hoisted_10 = {
114
114
  key: 3,
115
115
  class: "aipanel-session-meta"
@@ -257,13 +257,11 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
257
257
  /* STABLE_FRAGMENT */
258
258
  ))
259
259
  ], 8, _hoisted_6)) : $setup.isSessionCompleted(item.id) ? (_openBlock(), _createElementBlock("span", _hoisted_8)) : _createCommentVNode("v-if", true),
260
- _createElementVNode(
261
- "span",
262
- _hoisted_9,
263
- _toDisplayString(item.title),
264
- 1
265
- /* TEXT */
266
- ),
260
+ _createCommentVNode(" \u5355\u884C\u7701\u7565\uFF1B\u539F\u751F title \u60AC\u6D6E\u663E\u793A\u5B8C\u6574\u6807\u9898\uFF08\u5BF9\u9F50 DS \u884C HoverCard \u7684\u5B8C\u6574\u6807\u9898\u80FD\u529B\uFF09 "),
261
+ _createElementVNode("span", {
262
+ class: "aipanel-session-title-text",
263
+ title: item.title
264
+ }, _toDisplayString(item.title), 9, _hoisted_9),
267
265
  item.meta ? (_openBlock(), _createElementBlock(
268
266
  "span",
269
267
  _hoisted_10,
package/es/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { App } from 'vue';
2
- declare const version = "1.2.19";
2
+ declare const version = "1.2.20";
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.2.19";
2
+ const version = "1.2.20";
3
3
  function install(app, options) {
4
4
  const components = [
5
5
  AIPanelWidget
@@ -33,17 +33,19 @@ module.exports = __toCommonJS(use_inspector_exports);
33
33
  var import_vue = require("vue");
34
34
  var import_core = require("@aipanel/core");
35
35
  var import_css_selector_generator = __toESM(require("css-selector-generator"));
36
- const IGNORE_SELECTORS = [
37
- "#vue-inspector-container",
38
- ".aipanel-widget",
36
+ const WIDGET_ROOT_SELECTOR = ".aipanel-widget";
37
+ const WIDGET_IGNORE_SELECTORS = [
38
+ WIDGET_ROOT_SELECTOR,
39
39
  ".aipanel-element-highlight",
40
40
  ".aipanel-element-tooltip",
41
41
  ".aipanel-select-mode-hint",
42
42
  ".floating-bubble"
43
43
  ];
44
- const IGNORE_ATTRIBUTE = "data-v-inspector-ignore";
45
- const KEY_PROPS_DATA = "__v_inspector";
46
- const KEY_DATA = "data-v-inspector";
44
+ const IGNORE_SELECTORS = [
45
+ ...WIDGET_IGNORE_SELECTORS,
46
+ ...(0, import_core.listInspectorAdapters)().flatMap((adapter) => adapter.ignoreSelectors)
47
+ ];
48
+ const IGNORE_ATTRIBUTES = (0, import_core.listInspectorAdapters)().flatMap((adapter) => adapter.ignoreAttributes);
47
49
  function getDirectText(element) {
48
50
  const el = element;
49
51
  const text = el.innerText || element.textContent || "";
@@ -109,114 +111,27 @@ function getElementDescription(element) {
109
111
  ]
110
112
  });
111
113
  }
112
- function getFileInfoFromVueInstance(element) {
113
- const vue3Instance = element.__vueParentComponent;
114
- if (vue3Instance) {
115
- let current = vue3Instance;
116
- while (current) {
117
- const file = current.type?.__file || current.vnode?.type?.__file;
118
- if (file) {
119
- return { file, line: null, column: null };
120
- }
121
- current = current.parent;
122
- }
123
- }
124
- const vue2Instance = element.__vue__;
125
- if (vue2Instance) {
126
- let current = vue2Instance;
127
- while (current) {
128
- const file = current.$options?.__file;
129
- if (file) {
130
- return { file, line: null, column: null };
131
- }
132
- current = current.$parent;
133
- }
134
- }
135
- return null;
136
- }
137
114
  function shouldIgnoreElement(el) {
138
- if (el.hasAttribute(IGNORE_ATTRIBUTE)) return true;
115
+ if (IGNORE_ATTRIBUTES.some((attribute) => el.hasAttribute(attribute))) return true;
139
116
  for (const selector of IGNORE_SELECTORS) {
140
117
  if (el.closest(selector)) return true;
141
118
  }
142
119
  return false;
143
120
  }
144
- function getDataFromElement(el) {
145
- const vnodeData = el.__vnode?.props?.[KEY_PROPS_DATA];
146
- if (vnodeData) return vnodeData;
147
- const ctxVNode = el.__vnode?.ctx?.vnode;
148
- if (ctxVNode?.el === el) {
149
- const ctxData = ctxVNode.props?.[KEY_PROPS_DATA];
150
- if (ctxData) return ctxData;
151
- }
152
- const vueInstance = el.__vueParentComponent;
153
- let currentParent = vueInstance?.parent;
154
- while (currentParent) {
155
- if (currentParent.vnode?.el === el) {
156
- const parentData = currentParent.vnode.props?.[KEY_PROPS_DATA];
157
- if (parentData) return parentData;
158
- }
159
- currentParent = currentParent.parent;
160
- }
161
- const attr = el.getAttribute(KEY_DATA);
162
- return attr ?? void 0;
163
- }
164
- function findInspectorFileInfo(element) {
165
- let current = element;
166
- while (current) {
167
- if (shouldIgnoreElement(current)) {
168
- current = current.parentElement;
169
- continue;
170
- }
171
- const data = getDataFromElement(current);
172
- if (data) {
173
- const splitRE = /(.+):([\d]+):([\d]+)$/;
174
- const match = data.match(splitRE);
175
- if (match) {
176
- return {
177
- file: match[1],
178
- line: parseInt(match[2], 10),
179
- column: parseInt(match[3], 10)
180
- };
181
- }
182
- }
183
- current = current.parentElement;
121
+ function resolveElementSourceLocation(element) {
122
+ if (!element) return null;
123
+ for (const adapter of (0, import_core.listInspectorAdapters)()) {
124
+ const location = adapter.resolveSourceLocation(element);
125
+ if (location?.file) return location;
184
126
  }
185
127
  return null;
186
128
  }
187
- function mergeFileInfo(inspectorFileInfo, vueFileInfo) {
188
- if (!inspectorFileInfo?.file && !vueFileInfo?.file) {
189
- return { file: null, line: null, column: null };
190
- }
191
- const isNodeModules = (path) => path.includes("node_modules");
192
- if (inspectorFileInfo?.file && vueFileInfo?.file) {
193
- if (!isNodeModules(inspectorFileInfo.file)) {
194
- return inspectorFileInfo;
195
- } else if (!isNodeModules(vueFileInfo.file)) {
196
- return vueFileInfo;
197
- } else {
198
- return inspectorFileInfo;
199
- }
200
- } else if (inspectorFileInfo?.file) {
201
- return inspectorFileInfo;
202
- } else {
203
- return vueFileInfo;
204
- }
205
- }
206
129
  function getTargetElement(e) {
207
130
  if (!e.target || !(e.target instanceof Element)) return null;
208
131
  const el = e.target;
209
132
  if (shouldIgnoreElement(el)) return null;
210
133
  return el;
211
134
  }
212
- function getFileInfo(e, element) {
213
- let inspectorFileInfo = null;
214
- if (element) {
215
- inspectorFileInfo = findInspectorFileInfo(element);
216
- }
217
- const vueFileInfo = element ? getFileInfoFromVueInstance(element) : null;
218
- return mergeFileInfo(inspectorFileInfo, vueFileInfo);
219
- }
220
135
  function useInspector(options) {
221
136
  const highlightVisible = (0, import_vue.ref)(false);
222
137
  const highlightStyle = (0, import_vue.ref)({
@@ -250,7 +165,7 @@ function useInspector(options) {
250
165
  const uiElements = [highlight, tooltip, selectHint, floatingBubble];
251
166
  setPointerEventsNone(uiElements);
252
167
  const elementToHighlight = getTargetElement(e);
253
- const fileInfo = getFileInfo(e, elementToHighlight);
168
+ const fileInfo = resolveElementSourceLocation(elementToHighlight);
254
169
  setPointerEventsAuto(uiElements);
255
170
  if (elementToHighlight) {
256
171
  const widget = document.querySelector(".aipanel-widget");
@@ -260,9 +175,9 @@ function useInspector(options) {
260
175
  currentPrimaryBg = style.getPropertyValue("--ap-accent-bg").trim() || currentPrimaryBg;
261
176
  }
262
177
  const description = getElementDescription(elementToHighlight);
263
- const fileName = fileInfo.file ? fileInfo.file.split("/").pop() : "";
178
+ const fileName = fileInfo?.file ? fileInfo.file.split("/").pop() : "";
264
179
  let lineInfo = "";
265
- if (fileInfo.line) {
180
+ if (fileInfo?.line) {
266
181
  lineInfo = `:${fileInfo.line}`;
267
182
  if (fileInfo.column) {
268
183
  lineInfo += `:${fileInfo.column}`;
@@ -371,37 +286,30 @@ function useInspector(options) {
371
286
  }
372
287
  }
373
288
  const handleMouseMove = handleMouseMoveCore;
374
- function setupInspectorHook() {
375
- const inspector = window.__VUE_INSPECTOR__;
376
- if (!inspector || inspector.__aipanel_hooked) return;
377
- const originalHandleClick = inspector.handleClick.bind(inspector);
378
- inspector.handleClick = function(e) {
379
- if (options.selectMode.value) {
380
- const targetEl = e.target instanceof Element ? e.target : null;
381
- if (targetEl && targetEl.closest(".aipanel-widget")) {
382
- return originalHandleClick.call(inspector, e);
383
- }
384
- e.preventDefault();
385
- e.stopPropagation();
386
- const elementToSelect = getTargetElement(e);
387
- const fileInfo = getFileInfo(e, elementToSelect);
388
- if (elementToSelect) {
389
- const innerText = getDirectText(elementToSelect);
390
- const description = getElementDescription(elementToSelect);
391
- const elementInfo = {
392
- filePath: fileInfo.file,
393
- line: fileInfo.line,
394
- column: fileInfo.column,
395
- innerText: (0, import_core.truncate)(innerText, 200),
396
- description
397
- };
398
- options.onAddSelectedNode(elementInfo);
399
- }
400
- return;
401
- }
402
- return originalHandleClick.call(inspector, e);
403
- };
404
- inspector.__aipanel_hooked = true;
289
+ function handleElementClick(element) {
290
+ if (!options.selectMode.value) return false;
291
+ if (element?.closest(WIDGET_ROOT_SELECTOR)) return false;
292
+ const elementToSelect = element && !shouldIgnoreElement(element) ? element : null;
293
+ if (elementToSelect) {
294
+ const fileInfo = resolveElementSourceLocation(elementToSelect);
295
+ const innerText = getDirectText(elementToSelect);
296
+ const description = getElementDescription(elementToSelect);
297
+ const elementInfo = {
298
+ filePath: fileInfo?.file ?? null,
299
+ line: fileInfo?.line ?? null,
300
+ column: fileInfo?.column ?? null,
301
+ innerText: (0, import_core.truncate)(innerText, 200),
302
+ description
303
+ };
304
+ options.onAddSelectedNode(elementInfo);
305
+ }
306
+ return true;
307
+ }
308
+ function hookInspector() {
309
+ const adapter = (0, import_core.resolveInspectorAdapter)();
310
+ if (!adapter) return false;
311
+ adapter.onElementClick(handleElementClick);
312
+ return true;
405
313
  }
406
314
  function handleKeydown(e) {
407
315
  if (e.key === "Escape" && options.selectMode.value) {
@@ -411,17 +319,11 @@ function useInspector(options) {
411
319
  }
412
320
  }
413
321
  (0, import_vue.watch)(options.selectMode, (newVal) => {
414
- const inspector = window.__VUE_INSPECTOR__;
322
+ (0, import_core.resolveInspectorAdapter)()?.setEnabled(newVal);
415
323
  if (newVal) {
416
- if (inspector) {
417
- inspector.enable();
418
- }
419
324
  document.addEventListener("mousemove", handleMouseMove);
420
325
  document.addEventListener("keydown", handleKeydown, true);
421
326
  } else {
422
- if (inspector) {
423
- inspector.disable();
424
- }
425
327
  document.removeEventListener("mousemove", handleMouseMove);
426
328
  document.removeEventListener("keydown", handleKeydown, true);
427
329
  highlightVisible.value = false;
@@ -429,19 +331,14 @@ function useInspector(options) {
429
331
  }
430
332
  });
431
333
  (0, import_vue.onMounted)(() => {
432
- if (window.__VUE_INSPECTOR__) {
433
- setupInspectorHook();
434
- } else {
435
- inspectorCheckTimer = window.setInterval(() => {
436
- if (window.__VUE_INSPECTOR__) {
437
- setupInspectorHook();
438
- if (inspectorCheckTimer) {
439
- window.clearInterval(inspectorCheckTimer);
440
- inspectorCheckTimer = null;
441
- }
442
- }
443
- }, import_core.INSPECTOR_CHECK_INTERVAL);
444
- }
334
+ if (hookInspector()) return;
335
+ inspectorCheckTimer = window.setInterval(() => {
336
+ if (!hookInspector()) return;
337
+ if (inspectorCheckTimer) {
338
+ window.clearInterval(inspectorCheckTimer);
339
+ inspectorCheckTimer = null;
340
+ }
341
+ }, import_core.INSPECTOR_CHECK_INTERVAL);
445
342
  });
446
343
  (0, import_vue.onUnmounted)(() => {
447
344
  if (inspectorCheckTimer) {
@@ -1,24 +1,5 @@
1
1
  import { type Ref } from "vue";
2
2
  import type { AIPanelSelectedElement } from "../src/types";
3
- interface VueInspector {
4
- getTargetNode: (e: MouseEvent) => {
5
- targetNode: Element | null;
6
- params: {
7
- file?: string;
8
- line?: number;
9
- column?: number;
10
- } | null;
11
- };
12
- handleClick: (e: MouseEvent) => void;
13
- enable: () => void;
14
- disable: () => void;
15
- __aipanel_hooked?: boolean;
16
- }
17
- declare global {
18
- interface Window {
19
- __VUE_INSPECTOR__?: VueInspector;
20
- }
21
- }
22
3
  interface UseInspectorOptions {
23
4
  selectMode: Ref<boolean>;
24
5
  onAddSelectedNode: (element: AIPanelSelectedElement) => void;
@@ -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;min-height:36px;padding:8px 10px;border-radius:8px;cursor:pointer;color:var(--ap-text-primary);transition:background-color .15s ease}.aipanel-widget.aipanel-theme-dark .aipanel-session-item{color:var(--ap-text-secondary)}.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:13px;font-weight:400;line-height:20px}.aipanel-session-meta{flex:none;margin-left:auto;font-size:12px;line-height:20px;color:var(--ap-text-placeholder);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:22px;height:22px;border:none;border-radius:6px;background:transparent;color:var(--ap-text-placeholder);font-size:16px;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;min-height:36px;box-sizing:border-box;padding:8px 10px;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;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}}
@@ -131,7 +131,7 @@ const _hoisted_8 = {
131
131
  class: "aipanel-session-state aipanel-session-state-completed",
132
132
  title: "\u5DF2\u5B8C\u6210"
133
133
  };
134
- const _hoisted_9 = { class: "aipanel-session-title-text" };
134
+ const _hoisted_9 = ["title"];
135
135
  const _hoisted_10 = {
136
136
  key: 3,
137
137
  class: "aipanel-session-meta"
@@ -279,13 +279,11 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
279
279
  /* STABLE_FRAGMENT */
280
280
  ))
281
281
  ], 8, _hoisted_6)) : $setup.isSessionCompleted(item.id) ? ((0, import_vue3.openBlock)(), (0, import_vue3.createElementBlock)("span", _hoisted_8)) : (0, import_vue3.createCommentVNode)("v-if", true),
282
- (0, import_vue3.createElementVNode)(
283
- "span",
284
- _hoisted_9,
285
- (0, import_vue3.toDisplayString)(item.title),
286
- 1
287
- /* TEXT */
288
- ),
282
+ (0, import_vue3.createCommentVNode)(" \u5355\u884C\u7701\u7565\uFF1B\u539F\u751F title \u60AC\u6D6E\u663E\u793A\u5B8C\u6574\u6807\u9898\uFF08\u5BF9\u9F50 DS \u884C HoverCard \u7684\u5B8C\u6574\u6807\u9898\u80FD\u529B\uFF09 "),
283
+ (0, import_vue3.createElementVNode)("span", {
284
+ class: "aipanel-session-title-text",
285
+ title: item.title
286
+ }, (0, import_vue3.toDisplayString)(item.title), 9, _hoisted_9),
289
287
  item.meta ? ((0, import_vue3.openBlock)(), (0, import_vue3.createElementBlock)(
290
288
  "span",
291
289
  _hoisted_10,
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.2.19";
29
+ const version = "1.2.20";
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.2.19";
2
+ declare const version = "1.2.20";
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.2.19",
3
+ "version": "1.2.20",
4
4
  "description": "Reusable AIPanel widget components built with Pagoda CLI",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
@@ -31,10 +31,11 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "css-selector-generator": "^3.9.2",
34
- "@aipanel/core": "1.2.19"
34
+ "@aipanel/core": "1.2.20"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "pagoda-cli build",
38
- "test": "vitest run"
38
+ "test": "vitest run",
39
+ "test:coverage": "vitest run --coverage"
39
40
  }
40
41
  }