vite-plugin-ai-annotator 1.1.26 → 1.1.28

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,5 +1,6 @@
1
1
  /**
2
2
  * Inspection Manager for mouse inspection mode handling
3
+ * Supports both single-click selection and drag-to-select multiple elements
3
4
  */
4
5
  export interface InspectionManager {
5
6
  enterInspectionMode(): void;
@@ -9,6 +10,7 @@ export interface InspectionManager {
9
10
  }
10
11
  export interface InspectionCallbacks {
11
12
  onElementSelect?: (element: Element) => void;
13
+ onMultiSelect?: (elements: Element[]) => void;
12
14
  shouldIgnoreElement?: (element: Element) => boolean;
13
15
  isElementSelected?: (element: Element) => boolean;
14
16
  onEscape?: () => void;
@@ -44,6 +44,7 @@ export declare class AnnotatorToolbar extends LitElement {
44
44
  private injectJS;
45
45
  private getConsoleLogs;
46
46
  private handleElementSelected;
47
+ private handleMultiSelect;
47
48
  private removeSelectedElement;
48
49
  private showCommentPopoverForElement;
49
50
  private handlePopoverKeydown;
@@ -6706,11 +6706,15 @@
6706
6706
  }
6707
6707
 
6708
6708
  // src/annotator/inspection.ts
6709
+ var DRAG_THRESHOLD = 5;
6709
6710
  function createInspectionManager(callbacks = {}) {
6710
- const { onElementSelect, shouldIgnoreElement, isElementSelected, onEscape, onCopy } = callbacks;
6711
+ const { onElementSelect, onMultiSelect, shouldIgnoreElement, isElementSelected, onEscape, onCopy } = callbacks;
6711
6712
  let isInspecting = false;
6712
6713
  let currentHoveredElement = null;
6713
6714
  let inspectionStyleElement = null;
6715
+ let selectionOverlay = null;
6716
+ let dragState = { isDragging: false, startX: 0, startY: 0, currentX: 0, currentY: 0 };
6717
+ let mouseDownTime = 0;
6714
6718
  function addInspectionStyles() {
6715
6719
  inspectionStyleElement = document.createElement("style");
6716
6720
  inspectionStyleElement.id = "annotator-toolbar-styles";
@@ -6718,6 +6722,8 @@
6718
6722
  * {
6719
6723
  pointer-events: none !important;
6720
6724
  cursor: crosshair !important;
6725
+ user-select: none !important;
6726
+ -webkit-user-select: none !important;
6721
6727
  }
6722
6728
  annotator-toolbar, annotator-toolbar *,
6723
6729
  .annotator-badge, .annotator-badge *,
@@ -6754,7 +6760,100 @@
6754
6760
  }
6755
6761
  return element;
6756
6762
  }
6763
+ function createSelectionOverlay() {
6764
+ const overlay = document.createElement("div");
6765
+ overlay.className = "annotator-ignore";
6766
+ overlay.style.cssText = `
6767
+ position: fixed;
6768
+ border: 2px dashed #00FFFF;
6769
+ background: rgba(0, 255, 255, 0.1);
6770
+ pointer-events: none;
6771
+ z-index: 999999;
6772
+ box-shadow: 0 0 10px rgba(0, 255, 255, 0.3);
6773
+ `;
6774
+ document.body.appendChild(overlay);
6775
+ return overlay;
6776
+ }
6777
+ function updateSelectionOverlay() {
6778
+ if (!selectionOverlay) return;
6779
+ const left = Math.min(dragState.startX, dragState.currentX);
6780
+ const top = Math.min(dragState.startY, dragState.currentY);
6781
+ const width = Math.abs(dragState.currentX - dragState.startX);
6782
+ const height = Math.abs(dragState.currentY - dragState.startY);
6783
+ selectionOverlay.style.left = `${left}px`;
6784
+ selectionOverlay.style.top = `${top}px`;
6785
+ selectionOverlay.style.width = `${width}px`;
6786
+ selectionOverlay.style.height = `${height}px`;
6787
+ }
6788
+ function removeSelectionOverlay() {
6789
+ if (selectionOverlay) {
6790
+ selectionOverlay.remove();
6791
+ selectionOverlay = null;
6792
+ }
6793
+ }
6794
+ function getSelectionRect() {
6795
+ const left = Math.min(dragState.startX, dragState.currentX);
6796
+ const top = Math.min(dragState.startY, dragState.currentY);
6797
+ const width = Math.abs(dragState.currentX - dragState.startX);
6798
+ const height = Math.abs(dragState.currentY - dragState.startY);
6799
+ return new DOMRect(left, top, width, height);
6800
+ }
6801
+ function isFullyContained(inner, outer) {
6802
+ return inner.left >= outer.left && inner.right <= outer.right && inner.top >= outer.top && inner.bottom <= outer.bottom;
6803
+ }
6804
+ function findElementsFullyInRect(rect) {
6805
+ if (inspectionStyleElement) {
6806
+ inspectionStyleElement.disabled = true;
6807
+ }
6808
+ const elements = [];
6809
+ const allElements = document.body.querySelectorAll("*");
6810
+ for (const element of allElements) {
6811
+ if (shouldIgnoreElement?.(element)) continue;
6812
+ if (element.tagName === "SCRIPT" || element.tagName === "STYLE" || element.tagName === "NOSCRIPT") continue;
6813
+ const elementRect = element.getBoundingClientRect();
6814
+ if (elementRect.width === 0 || elementRect.height === 0) continue;
6815
+ if (isFullyContained(elementRect, rect)) {
6816
+ elements.push(element);
6817
+ }
6818
+ }
6819
+ if (inspectionStyleElement) {
6820
+ inspectionStyleElement.disabled = false;
6821
+ }
6822
+ return elements;
6823
+ }
6824
+ function filterLeafElements(elements) {
6825
+ return elements.filter((el) => {
6826
+ return !elements.some((other) => other !== el && el.contains(other));
6827
+ });
6828
+ }
6829
+ function handleMouseDown(e5) {
6830
+ const clickedElement = e5.target;
6831
+ if (shouldIgnoreElement?.(clickedElement)) return;
6832
+ mouseDownTime = Date.now();
6833
+ dragState = {
6834
+ isDragging: false,
6835
+ startX: e5.clientX,
6836
+ startY: e5.clientY,
6837
+ currentX: e5.clientX,
6838
+ currentY: e5.clientY
6839
+ };
6840
+ }
6757
6841
  function handleMouseMove(e5) {
6842
+ if (mouseDownTime > 0) {
6843
+ const dx = Math.abs(e5.clientX - dragState.startX);
6844
+ const dy = Math.abs(e5.clientY - dragState.startY);
6845
+ if (!dragState.isDragging && (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD)) {
6846
+ dragState.isDragging = true;
6847
+ removeHoverHighlight();
6848
+ selectionOverlay = createSelectionOverlay();
6849
+ }
6850
+ if (dragState.isDragging) {
6851
+ dragState.currentX = e5.clientX;
6852
+ dragState.currentY = e5.clientY;
6853
+ updateSelectionOverlay();
6854
+ return;
6855
+ }
6856
+ }
6758
6857
  const target = getElementAtPoint(e5.clientX, e5.clientY);
6759
6858
  if (!target || shouldIgnoreElement?.(target)) {
6760
6859
  removeHoverHighlight();
@@ -6766,19 +6865,38 @@
6766
6865
  target.style.outlineOffset = "2px";
6767
6866
  currentHoveredElement = target;
6768
6867
  }
6769
- function handleClick(e5) {
6770
- const clickedElement = e5.target;
6771
- if (shouldIgnoreElement?.(clickedElement)) return;
6868
+ function handleMouseUp(e5) {
6869
+ const wasDragging = dragState.isDragging;
6870
+ if (wasDragging) {
6871
+ removeSelectionOverlay();
6872
+ const selectionRect = getSelectionRect();
6873
+ if (selectionRect.width > 10 && selectionRect.height > 10) {
6874
+ const elementsInRect = findElementsFullyInRect(selectionRect);
6875
+ const leafElements = filterLeafElements(elementsInRect);
6876
+ if (leafElements.length > 0) {
6877
+ onMultiSelect?.(leafElements);
6878
+ }
6879
+ }
6880
+ } else if (mouseDownTime > 0) {
6881
+ const target = getElementAtPoint(e5.clientX, e5.clientY);
6882
+ if (target && !shouldIgnoreElement?.(target)) {
6883
+ onElementSelect?.(target);
6884
+ }
6885
+ }
6886
+ mouseDownTime = 0;
6887
+ dragState = { isDragging: false, startX: 0, startY: 0, currentX: 0, currentY: 0 };
6888
+ }
6889
+ function preventClick(e5) {
6890
+ const target = e5.target;
6891
+ if (shouldIgnoreElement?.(target)) return;
6772
6892
  e5.preventDefault();
6773
6893
  e5.stopPropagation();
6774
6894
  e5.stopImmediatePropagation();
6775
- const target = getElementAtPoint(e5.clientX, e5.clientY);
6776
- if (!target || shouldIgnoreElement?.(target)) return;
6777
- onElementSelect?.(target);
6778
6895
  }
6779
6896
  function preventMouseEvents(e5) {
6780
6897
  const target = e5.target;
6781
6898
  if (shouldIgnoreElement?.(target)) return;
6899
+ if (dragState.isDragging) return;
6782
6900
  e5.preventDefault();
6783
6901
  e5.stopPropagation();
6784
6902
  e5.stopImmediatePropagation();
@@ -6797,15 +6915,20 @@
6797
6915
  }
6798
6916
  }
6799
6917
  }
6918
+ function resetDragState() {
6919
+ mouseDownTime = 0;
6920
+ dragState = { isDragging: false, startX: 0, startY: 0, currentX: 0, currentY: 0 };
6921
+ removeSelectionOverlay();
6922
+ }
6800
6923
  return {
6801
6924
  enterInspectionMode() {
6802
6925
  if (isInspecting) return;
6803
6926
  isInspecting = true;
6804
6927
  addInspectionStyles();
6928
+ document.addEventListener("mousedown", handleMouseDown, true);
6805
6929
  document.addEventListener("mousemove", handleMouseMove, true);
6806
- document.addEventListener("click", handleClick, true);
6807
- document.addEventListener("mousedown", preventMouseEvents, true);
6808
- document.addEventListener("mouseup", preventMouseEvents, true);
6930
+ document.addEventListener("mouseup", handleMouseUp, true);
6931
+ document.addEventListener("click", preventClick, true);
6809
6932
  document.addEventListener("dblclick", preventMouseEvents, true);
6810
6933
  document.addEventListener("contextmenu", preventMouseEvents, true);
6811
6934
  document.addEventListener("keydown", handleKeyDown);
@@ -6814,14 +6937,15 @@
6814
6937
  if (!isInspecting) return;
6815
6938
  isInspecting = false;
6816
6939
  removeInspectionStyles();
6940
+ document.removeEventListener("mousedown", handleMouseDown, true);
6817
6941
  document.removeEventListener("mousemove", handleMouseMove, true);
6818
- document.removeEventListener("click", handleClick, true);
6819
- document.removeEventListener("mousedown", preventMouseEvents, true);
6820
- document.removeEventListener("mouseup", preventMouseEvents, true);
6942
+ document.removeEventListener("mouseup", handleMouseUp, true);
6943
+ document.removeEventListener("click", preventClick, true);
6821
6944
  document.removeEventListener("dblclick", preventMouseEvents, true);
6822
6945
  document.removeEventListener("contextmenu", preventMouseEvents, true);
6823
6946
  document.removeEventListener("keydown", handleKeyDown);
6824
6947
  removeHoverHighlight();
6948
+ resetDragState();
6825
6949
  },
6826
6950
  isInInspectionMode() {
6827
6951
  return isInspecting;
@@ -6830,14 +6954,15 @@
6830
6954
  if (isInspecting) {
6831
6955
  isInspecting = false;
6832
6956
  removeInspectionStyles();
6957
+ document.removeEventListener("mousedown", handleMouseDown, true);
6833
6958
  document.removeEventListener("mousemove", handleMouseMove, true);
6834
- document.removeEventListener("click", handleClick, true);
6835
- document.removeEventListener("mousedown", preventMouseEvents, true);
6836
- document.removeEventListener("mouseup", preventMouseEvents, true);
6959
+ document.removeEventListener("mouseup", handleMouseUp, true);
6960
+ document.removeEventListener("click", preventClick, true);
6837
6961
  document.removeEventListener("dblclick", preventMouseEvents, true);
6838
6962
  document.removeEventListener("contextmenu", preventMouseEvents, true);
6839
6963
  document.removeEventListener("keydown", handleKeyDown);
6840
6964
  removeHoverHighlight();
6965
+ resetDragState();
6841
6966
  }
6842
6967
  }
6843
6968
  };
@@ -7395,6 +7520,7 @@
7395
7520
  });
7396
7521
  this.inspectionManager = createInspectionManager({
7397
7522
  onElementSelect: (element) => this.handleElementSelected(element),
7523
+ onMultiSelect: (elements) => this.handleMultiSelect(elements),
7398
7524
  shouldIgnoreElement: (element) => this.shouldIgnoreElement(element),
7399
7525
  isElementSelected: (element) => this.selectionManager?.hasElement(element) || false,
7400
7526
  onEscape: () => this.exitInspectingMode(),
@@ -7563,12 +7689,12 @@
7563
7689
  if (type === "element" && selector) {
7564
7690
  const element = document.querySelector(selector);
7565
7691
  if (!element) {
7566
- console.error(`[AI Annotator] Element not found for selector: ${selector}`);
7692
+ this.log(`Element not found for selector: ${selector}`);
7567
7693
  return { success: false, error: `Element not found: ${selector}` };
7568
7694
  }
7569
7695
  targetElement = element;
7570
7696
  }
7571
- console.log(`[AI Annotator] Capturing screenshot of ${type === "element" ? selector : "viewport"}`);
7697
+ this.log(`Capturing screenshot of ${type === "element" ? selector : "viewport"}`);
7572
7698
  const blob = await toBlob(targetElement, {
7573
7699
  quality,
7574
7700
  type: "image/webp",
@@ -7576,10 +7702,10 @@
7576
7702
  skipFonts: true
7577
7703
  });
7578
7704
  if (!blob) {
7579
- console.error("[AI Annotator] toBlob returned null - screenshot capture failed");
7705
+ this.log("toBlob returned null - screenshot capture failed");
7580
7706
  return { success: false, error: "Failed to capture screenshot (toBlob returned null)" };
7581
7707
  }
7582
- console.log(`[AI Annotator] Screenshot captured, blob size: ${blob.size} bytes`);
7708
+ this.log(`Screenshot captured, blob size: ${blob.size} bytes`);
7583
7709
  const reader = new FileReader();
7584
7710
  const base64 = await new Promise((resolve, reject) => {
7585
7711
  reader.onload = () => {
@@ -7593,7 +7719,7 @@
7593
7719
  return { success: true, base64 };
7594
7720
  } catch (error) {
7595
7721
  const errorMessage = error instanceof Error ? error.message : String(error);
7596
- console.error(`[AI Annotator] Screenshot error: ${errorMessage}`, error);
7722
+ this.log(`Screenshot error: ${errorMessage}`, error);
7597
7723
  return {
7598
7724
  success: false,
7599
7725
  error: errorMessage
@@ -7658,6 +7784,26 @@
7658
7784
  });
7659
7785
  }
7660
7786
  }
7787
+ handleMultiSelect(elements) {
7788
+ if (!this.selectionManager) return;
7789
+ let newSelectCount = 0;
7790
+ for (const element of elements) {
7791
+ if (!this.selectionManager.hasElement(element)) {
7792
+ this.selectionManager.selectElement(element, (el) => findNearestComponent(el, this.verbose));
7793
+ newSelectCount++;
7794
+ }
7795
+ }
7796
+ this.selectionCount = this.selectionManager.getSelectedCount();
7797
+ if (newSelectCount > 0) {
7798
+ this.showToast(`Selected ${newSelectCount} element(s)`);
7799
+ }
7800
+ if (this.socket?.connected) {
7801
+ this.socket.emit("selectionChanged", {
7802
+ count: this.selectionCount,
7803
+ elements: this.getSelectedElements()
7804
+ });
7805
+ }
7806
+ }
7661
7807
  removeSelectedElement() {
7662
7808
  if (!this.commentPopover.element || !this.selectionManager) return;
7663
7809
  const element = this.commentPopover.element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-ai-annotator",
3
- "version": "1.1.26",
3
+ "version": "1.1.28",
4
4
  "description": "AI-powered element annotator for Vite - Pick elements and get instant AI code modifications",
5
5
  "type": "module",
6
6
  "main": "dist/vite-plugin.js",