@vite-plugin-opencode-assistant/components 1.0.33 → 1.0.34

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.
package/es/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import OpenCodeWidget from './open-code-widget';
2
2
  import type { App } from 'vue';
3
- declare const version = "1.0.33";
3
+ declare const version = "1.0.34";
4
4
  declare function install(app: App<any>, options?: any): void;
5
5
  export { install, version, OpenCodeWidget };
6
6
  export default install;
package/es/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import OpenCodeWidget from "./open-code-widget";
2
- const version = "1.0.33";
2
+ const version = "1.0.34";
3
3
  function install(app, options) {
4
4
  const components = [
5
5
  OpenCodeWidget
@@ -1,6 +1,17 @@
1
1
  import { ref, watch, onMounted, onUnmounted } from "vue";
2
2
  import { truncate } from "@vite-plugin-opencode-assistant/shared";
3
3
  import getCssSelector from "css-selector-generator";
4
+ const IGNORE_SELECTORS = [
5
+ "#vue-inspector-container",
6
+ ".opencode-widget",
7
+ ".opencode-element-highlight",
8
+ ".opencode-element-tooltip",
9
+ ".opencode-select-mode-hint",
10
+ ".floating-bubble"
11
+ ];
12
+ const IGNORE_ATTRIBUTE = "data-v-inspector-ignore";
13
+ const KEY_PROPS_DATA = "__v_inspector";
14
+ const KEY_DATA = "data-v-inspector";
4
15
  function throttle(fn, delay) {
5
16
  let lastCall = 0;
6
17
  let rafId = null;
@@ -66,74 +77,27 @@ function isStateClass(className) {
66
77
  }
67
78
  return false;
68
79
  }
69
- function filterStateClasses(classes) {
70
- return classes.filter((cls) => !isStateClass(cls));
71
- }
72
80
  function getElementDescription(element) {
73
- try {
74
- const selector = getCssSelector(element, {
75
- selectors: ["id", "class", "tag", "nthchild"],
76
- combineWithinSelector: true,
77
- combineBetweenSelectors: true,
78
- maxCombinations: 100,
79
- maxCandidates: 100,
80
- blacklist: [
81
- (selectorValue) => {
82
- const idMatch = selectorValue.match(/^#(.+)$/);
83
- if (idMatch) {
84
- return isDynamicId(idMatch[1]);
85
- }
86
- const classMatch = selectorValue.match(/^\.([a-zA-Z_-][\w-]*)$/);
87
- if (classMatch) {
88
- return isStateClass(classMatch[1]);
89
- }
90
- return false;
81
+ return getCssSelector(element, {
82
+ selectors: ["id", "class", "tag", "nthchild"],
83
+ combineWithinSelector: true,
84
+ combineBetweenSelectors: true,
85
+ maxCombinations: 100,
86
+ maxCandidates: 100,
87
+ blacklist: [
88
+ (selectorValue) => {
89
+ const idMatch = selectorValue.match(/^#(.+)$/);
90
+ if (idMatch) {
91
+ return isDynamicId(idMatch[1]);
91
92
  }
92
- ]
93
- });
94
- return selector;
95
- } catch (e) {
96
- const tag = element.tagName.toLowerCase();
97
- const parts = [tag];
98
- const id = element.id;
99
- if (id && !isDynamicId(id)) parts.push(`#${id}`);
100
- const className = element.className;
101
- if (typeof className === "string") {
102
- const classes = filterStateClasses(className.trim().split(/\s+/).filter(Boolean)).slice(0, 2);
103
- if (classes.length > 0) parts.push(`.${classes.join(".")}`);
104
- } else {
105
- const svgClass = className.baseVal;
106
- if (svgClass) {
107
- const classes = filterStateClasses(svgClass.trim().split(/\s+/).filter(Boolean)).slice(
108
- 0,
109
- 2
110
- );
111
- if (classes.length > 0) parts.push(`.${classes.join(".")}`);
93
+ const classMatch = selectorValue.match(/^\.([a-zA-Z_-][\w-]*)$/);
94
+ if (classMatch) {
95
+ return isStateClass(classMatch[1]);
96
+ }
97
+ return false;
112
98
  }
113
- }
114
- const name = element.getAttribute("name");
115
- if (name) parts.push(`[name="${name}"]`);
116
- const placeholder = element.getAttribute("placeholder");
117
- if (placeholder) parts.push(`[placeholder="${placeholder.substring(0, 20)}"]`);
118
- const src = element.getAttribute("src");
119
- if (src) parts.push(`[src]`);
120
- const href = element.getAttribute("href");
121
- if (href && href !== "#") parts.push(`[href]`);
122
- return parts.join("");
123
- }
124
- }
125
- function getFileInfoFromAttributes(element) {
126
- const file = element.getAttribute("data-v-inspector-file");
127
- if (file) {
128
- const line = element.getAttribute("data-v-inspector-line");
129
- const column = element.getAttribute("data-v-inspector-column");
130
- return {
131
- file,
132
- line: line ? parseInt(line, 10) : null,
133
- column: column ? parseInt(column, 10) : null
134
- };
135
- }
136
- return null;
99
+ ]
100
+ });
137
101
  }
138
102
  function getFileInfoFromVueInstance(element) {
139
103
  var _a, _b, _c, _d;
@@ -161,61 +125,83 @@ function getFileInfoFromVueInstance(element) {
161
125
  }
162
126
  return null;
163
127
  }
164
- function findFileInfo(element, inspector) {
128
+ function shouldIgnoreElement(el) {
129
+ if (el.hasAttribute(IGNORE_ATTRIBUTE)) return true;
130
+ for (const selector of IGNORE_SELECTORS) {
131
+ if (el.closest(selector)) return true;
132
+ }
133
+ return false;
134
+ }
135
+ function getDataFromElement(el) {
165
136
  var _a, _b;
137
+ const vnodeData = (_b = (_a = el.__vnode) == null ? void 0 : _a.props) == null ? void 0 : _b[KEY_PROPS_DATA];
138
+ if (vnodeData) return vnodeData;
139
+ const attr = el.getAttribute(KEY_DATA);
140
+ return attr != null ? attr : void 0;
141
+ }
142
+ function findInspectorFileInfo(element) {
166
143
  let current = element;
167
- let fallbackFileInfo = null;
168
144
  while (current) {
169
- const attrInfo = getFileInfoFromAttributes(current);
170
- if (attrInfo && attrInfo.line !== null) {
171
- return attrInfo;
145
+ const data = getDataFromElement(current);
146
+ if (data) {
147
+ const splitRE = /(.+):([\d]+):([\d]+)$/;
148
+ const match = data.match(splitRE);
149
+ if (match) {
150
+ return {
151
+ file: match[1],
152
+ line: parseInt(match[2], 10),
153
+ column: parseInt(match[3], 10)
154
+ };
155
+ }
172
156
  }
173
- if (attrInfo && !fallbackFileInfo) {
174
- fallbackFileInfo = attrInfo;
157
+ current = current.parentElement;
158
+ }
159
+ return null;
160
+ }
161
+ function mergeFileInfo(inspectorFileInfo, vueFileInfo) {
162
+ if (!(inspectorFileInfo == null ? void 0 : inspectorFileInfo.file) && !(vueFileInfo == null ? void 0 : vueFileInfo.file)) {
163
+ return { file: null, line: null, column: null };
164
+ }
165
+ const isNodeModules = (path) => path.includes("node_modules");
166
+ if ((inspectorFileInfo == null ? void 0 : inspectorFileInfo.file) && (vueFileInfo == null ? void 0 : vueFileInfo.file)) {
167
+ if (!isNodeModules(inspectorFileInfo.file)) {
168
+ return inspectorFileInfo;
169
+ } else if (!isNodeModules(vueFileInfo.file)) {
170
+ return vueFileInfo;
171
+ } else {
172
+ return inspectorFileInfo;
175
173
  }
176
- const fakeEvent = {
177
- clientX: 0,
178
- clientY: 0,
179
- target: current,
180
- currentTarget: current
181
- };
182
- const { params } = inspector.getTargetNode(fakeEvent);
183
- if (params && params.file) {
184
- const info = {
174
+ } else if (inspectorFileInfo == null ? void 0 : inspectorFileInfo.file) {
175
+ return inspectorFileInfo;
176
+ } else {
177
+ return vueFileInfo;
178
+ }
179
+ }
180
+ function getTargetElement(e) {
181
+ if (!e.target || !(e.target instanceof Element)) return null;
182
+ const el = e.target;
183
+ if (shouldIgnoreElement(el)) return null;
184
+ return el;
185
+ }
186
+ function getFileInfo(e, element) {
187
+ var _a, _b;
188
+ const inspector = window.__VUE_INSPECTOR__;
189
+ let inspectorFileInfo = null;
190
+ if (inspector) {
191
+ const { targetNode, params } = inspector.getTargetNode(e);
192
+ if (targetNode && params && params.file) {
193
+ inspectorFileInfo = {
185
194
  file: params.file,
186
195
  line: (_a = params.line) != null ? _a : null,
187
196
  column: (_b = params.column) != null ? _b : null
188
197
  };
189
- if (info.line !== null) {
190
- return info;
191
- }
192
- if (!fallbackFileInfo) {
193
- fallbackFileInfo = info;
194
- }
195
198
  }
196
- const vueInfo = getFileInfoFromVueInstance(current);
197
- if (vueInfo && !fallbackFileInfo) {
198
- fallbackFileInfo = vueInfo;
199
- }
200
- current = current.parentElement;
201
199
  }
202
- return fallbackFileInfo || { file: null, line: null, column: null };
203
- }
204
- function getPreciseElementAtPoint(x, y, boundary) {
205
- const elements = document.elementsFromPoint(x, y);
206
- for (const el of elements) {
207
- if (el.closest("#vue-inspector-container")) continue;
208
- if (el.closest(".opencode-widget")) continue;
209
- if (el.hasAttribute("data-v-inspector-ignore")) continue;
210
- if (boundary) {
211
- if (boundary.contains(el) || el === boundary) {
212
- return el;
213
- }
214
- } else {
215
- return el;
216
- }
200
+ if (element && !inspectorFileInfo) {
201
+ inspectorFileInfo = findInspectorFileInfo(element);
217
202
  }
218
- return null;
203
+ const vueFileInfo = element ? getFileInfoFromVueInstance(element) : null;
204
+ return mergeFileInfo(inspectorFileInfo, vueFileInfo);
219
205
  }
220
206
  function useInspector(options) {
221
207
  const highlightVisible = ref(false);
@@ -230,84 +216,50 @@ function useInspector(options) {
230
216
  const tooltipContent = ref({ description: "", fileInfo: "" });
231
217
  const INSPECTOR_CHECK_INTERVAL = 500;
232
218
  let inspectorCheckTimer = null;
233
- let currentHighlightElement = null;
234
- let currentFileInfo = { file: null, line: null, column: null };
235
219
  let currentPrimary = "#3b82f6";
236
220
  let currentPrimaryBg = "rgba(59, 130, 246, 0.1)";
237
- let currentDescription = "";
238
- let currentFileInfoText = "";
221
+ function setPointerEventsNone(elements) {
222
+ elements.forEach((el) => {
223
+ if (el) el.style.pointerEvents = "none";
224
+ });
225
+ }
226
+ function setPointerEventsAuto(elements) {
227
+ elements.forEach((el) => {
228
+ if (el) el.style.pointerEvents = "";
229
+ });
230
+ }
239
231
  function handleMouseMoveCore(e) {
240
- var _a, _b;
241
232
  if (!options.selectMode.value) return;
242
- const inspector = window.__VUE_INSPECTOR__;
243
233
  const highlight = document.querySelector(".opencode-element-highlight");
244
234
  const tooltip = document.querySelector(".opencode-element-tooltip");
245
- if (highlight) highlight.style.pointerEvents = "none";
246
- if (tooltip) tooltip.style.pointerEvents = "none";
247
- let elementToHighlight = null;
248
- let targetNode;
249
- let fileInfo = { file: null, line: null, column: null };
250
- try {
251
- if (inspector) {
252
- const result = inspector.getTargetNode(e);
253
- targetNode = result.targetNode;
254
- const params = result.params;
255
- if (targetNode) {
256
- const preciseElement = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode);
257
- elementToHighlight = preciseElement || targetNode;
258
- if (params && params.file) {
259
- fileInfo = {
260
- file: params.file,
261
- line: (_a = params.line) != null ? _a : null,
262
- column: (_b = params.column) != null ? _b : null
263
- };
264
- } else {
265
- fileInfo = findFileInfo(targetNode, inspector);
266
- }
267
- }
268
- }
269
- if (!elementToHighlight) {
270
- elementToHighlight = getPreciseElementAtPoint(e.clientX, e.clientY, null);
271
- }
272
- if (elementToHighlight && !fileInfo.file) {
273
- fileInfo = getFileInfoFromVueInstance(elementToHighlight) || fileInfo;
274
- }
275
- } finally {
276
- if (highlight) highlight.style.pointerEvents = "";
277
- if (tooltip) tooltip.style.pointerEvents = "";
278
- }
235
+ const selectHint = document.querySelector(".opencode-select-mode-hint");
236
+ const floatingBubble = document.querySelector(".floating-bubble");
237
+ const uiElements = [highlight, tooltip, selectHint, floatingBubble];
238
+ setPointerEventsNone(uiElements);
239
+ const elementToHighlight = getTargetElement(e);
240
+ const fileInfo = getFileInfo(e, elementToHighlight);
241
+ setPointerEventsAuto(uiElements);
279
242
  if (elementToHighlight) {
280
- const elementChanged = currentHighlightElement !== elementToHighlight;
281
- if (elementChanged) {
282
- currentHighlightElement = elementToHighlight;
283
- currentFileInfo = fileInfo;
284
- const widget = document.querySelector(".opencode-widget");
285
- if (widget) {
286
- const style = getComputedStyle(widget);
287
- currentPrimary = style.getPropertyValue("--oc-primary").trim() || currentPrimary;
288
- currentPrimaryBg = style.getPropertyValue("--oc-primary-bg").trim() || currentPrimaryBg;
289
- }
290
- currentDescription = getElementDescription(elementToHighlight);
291
- } else if (!currentFileInfo.file && fileInfo.file) {
292
- currentFileInfo = fileInfo;
243
+ const widget = document.querySelector(".opencode-widget");
244
+ if (widget) {
245
+ const style = getComputedStyle(widget);
246
+ currentPrimary = style.getPropertyValue("--oc-primary").trim() || currentPrimary;
247
+ currentPrimaryBg = style.getPropertyValue("--oc-primary-bg").trim() || currentPrimaryBg;
293
248
  }
294
- const fileName = currentFileInfo.file ? currentFileInfo.file.split("/").pop() : "";
249
+ const description = getElementDescription(elementToHighlight);
250
+ const fileName = fileInfo.file ? fileInfo.file.split("/").pop() : "";
295
251
  let lineInfo = "";
296
- if (currentFileInfo.line) {
297
- lineInfo = `:${currentFileInfo.line}`;
298
- if (currentFileInfo.column) {
299
- lineInfo += `:${currentFileInfo.column}`;
252
+ if (fileInfo.line) {
253
+ lineInfo = `:${fileInfo.line}`;
254
+ if (fileInfo.column) {
255
+ lineInfo += `:${fileInfo.column}`;
300
256
  }
301
257
  }
302
- const newFileInfoText = fileName ? `${fileName}${lineInfo}` : "";
303
- const fileInfoChanged = currentFileInfoText !== newFileInfoText;
304
- if (elementChanged || fileInfoChanged) {
305
- currentFileInfoText = newFileInfoText;
306
- tooltipContent.value = {
307
- description: currentDescription,
308
- fileInfo: currentFileInfoText
309
- };
310
- }
258
+ const fileInfoText = fileName ? `${fileName}${lineInfo}` : "";
259
+ tooltipContent.value = {
260
+ description,
261
+ fileInfo: fileInfoText
262
+ };
311
263
  const rect = elementToHighlight.getBoundingClientRect();
312
264
  const newTop = `${rect.top}px`;
313
265
  const newLeft = `${rect.left}px`;
@@ -325,13 +277,20 @@ function useInspector(options) {
325
277
  }
326
278
  const tooltipHeight = 50;
327
279
  const tooltipWidth = 200;
280
+ const margin = 10;
328
281
  let tooltipTop = rect.top - tooltipHeight - 8;
329
282
  let tooltipLeft = rect.left;
330
- if (tooltipTop < 10) {
283
+ if (tooltipTop < margin) {
331
284
  tooltipTop = rect.bottom + 8;
332
285
  }
333
- if (tooltipLeft + tooltipWidth > window.innerWidth - 10) {
334
- tooltipLeft = window.innerWidth - tooltipWidth - 10;
286
+ if (tooltipTop + tooltipHeight > window.innerHeight - margin) {
287
+ tooltipTop = Math.max(margin, rect.top - tooltipHeight - 8);
288
+ }
289
+ if (tooltipLeft < margin) {
290
+ tooltipLeft = margin;
291
+ }
292
+ if (tooltipLeft + tooltipWidth > window.innerWidth - margin) {
293
+ tooltipLeft = window.innerWidth - tooltipWidth - margin;
335
294
  }
336
295
  const newTooltipTop = `${tooltipTop}px`;
337
296
  const newTooltipLeft = `${tooltipLeft}px`;
@@ -341,23 +300,11 @@ function useInspector(options) {
341
300
  left: newTooltipLeft
342
301
  };
343
302
  }
344
- if (!highlightVisible.value) {
345
- highlightVisible.value = true;
346
- }
347
- if (!tooltipVisible.value) {
348
- tooltipVisible.value = true;
349
- }
303
+ highlightVisible.value = true;
304
+ tooltipVisible.value = true;
350
305
  } else {
351
- currentHighlightElement = null;
352
- currentDescription = "";
353
- currentFileInfoText = "";
354
- currentFileInfo = { file: null, line: null, column: null };
355
- if (highlightVisible.value) {
356
- highlightVisible.value = false;
357
- }
358
- if (tooltipVisible.value) {
359
- tooltipVisible.value = false;
360
- }
306
+ highlightVisible.value = false;
307
+ tooltipVisible.value = false;
361
308
  }
362
309
  }
363
310
  const handleMouseMove = throttle(handleMouseMoveCore, 16);
@@ -366,32 +313,11 @@ function useInspector(options) {
366
313
  if (!inspector || inspector.__opencode_hooked) return;
367
314
  const originalHandleClick = inspector.handleClick.bind(inspector);
368
315
  inspector.handleClick = function(e) {
369
- var _a, _b;
370
316
  if (options.selectMode.value) {
371
317
  e.preventDefault();
372
318
  e.stopPropagation();
373
- let elementToSelect = null;
374
- let fileInfo = { file: null, line: null, column: null };
375
- const { targetNode, params } = inspector.getTargetNode(e);
376
- if (targetNode) {
377
- const preciseElement = getPreciseElementAtPoint(e.clientX, e.clientY, targetNode);
378
- elementToSelect = preciseElement || targetNode;
379
- if (params && params.file) {
380
- fileInfo = {
381
- file: params.file,
382
- line: (_a = params.line) != null ? _a : null,
383
- column: (_b = params.column) != null ? _b : null
384
- };
385
- } else if (elementToSelect) {
386
- fileInfo = findFileInfo(elementToSelect, inspector);
387
- }
388
- }
389
- if (!elementToSelect) {
390
- elementToSelect = getPreciseElementAtPoint(e.clientX, e.clientY, null);
391
- }
392
- if (elementToSelect && !fileInfo.file) {
393
- fileInfo = getFileInfoFromVueInstance(elementToSelect) || fileInfo;
394
- }
319
+ const elementToSelect = getTargetElement(e);
320
+ const fileInfo = getFileInfo(e, elementToSelect);
395
321
  if (elementToSelect) {
396
322
  const innerText = getDirectText(elementToSelect);
397
323
  const description = getElementDescription(elementToSelect);
@@ -431,10 +357,6 @@ function useInspector(options) {
431
357
  }
432
358
  document.removeEventListener("mousemove", handleMouseMove);
433
359
  document.removeEventListener("keydown", handleKeydown, true);
434
- currentHighlightElement = null;
435
- currentDescription = "";
436
- currentFileInfoText = "";
437
- currentFileInfo = { file: null, line: null, column: null };
438
360
  highlightVisible.value = false;
439
361
  tooltipVisible.value = false;
440
362
  }