vite-plugin-ai-annotator 1.3.4 → 1.14.1
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.
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Shared constants for annotator components
|
|
3
3
|
*/
|
|
4
4
|
export declare const Z_INDEX: {
|
|
5
|
+
readonly INSPECTION_OVERLAY: 999995;
|
|
5
6
|
readonly HIGHLIGHT_OVERLAY: 999996;
|
|
6
7
|
readonly HOVER_OVERLAY: 999997;
|
|
7
8
|
readonly BADGE: 999998;
|
|
@@ -13,3 +14,17 @@ export declare const CONSOLE_LIMITS: {
|
|
|
13
14
|
readonly BUFFER_TRIM_TO: 500;
|
|
14
15
|
};
|
|
15
16
|
export declare const SCREENSHOT_TIMEOUT_MS = 10000;
|
|
17
|
+
export declare const SELECTION_COLORS: readonly ["#FF00FF", "#00FFFF", "#FFFF00"];
|
|
18
|
+
export declare const COLORS: {
|
|
19
|
+
readonly INSPECTION: "#A855F7";
|
|
20
|
+
readonly BADGE_TEXT: "#050505";
|
|
21
|
+
readonly BADGE_BG: "#050505";
|
|
22
|
+
};
|
|
23
|
+
export declare const FONTS: {
|
|
24
|
+
readonly MONO: "'JetBrains Mono', monospace";
|
|
25
|
+
readonly GOOGLE_FONTS_URL: "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap";
|
|
26
|
+
};
|
|
27
|
+
export declare const TEXT_SELECTION: {
|
|
28
|
+
readonly MAX_LENGTH: 10000;
|
|
29
|
+
readonly HIGHLIGHT_OPACITY: 0.3;
|
|
30
|
+
};
|
|
@@ -11,6 +11,7 @@ export interface InspectionManager {
|
|
|
11
11
|
export interface InspectionCallbacks {
|
|
12
12
|
onElementSelect?: (element: Element) => void;
|
|
13
13
|
onMultiSelect?: (elements: Element[]) => void;
|
|
14
|
+
onTextSelect?: (range: Range, commonAncestor: Element) => void;
|
|
14
15
|
shouldIgnoreElement?: (element: Element) => boolean;
|
|
15
16
|
isElementSelected?: (element: Element) => boolean;
|
|
16
17
|
onEscape?: () => void;
|
|
@@ -3,14 +3,30 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { ElementData } from '../rpc/define';
|
|
5
5
|
import type { ComponentInfo } from './detectors';
|
|
6
|
+
/**
|
|
7
|
+
* Metadata for a text selection annotation.
|
|
8
|
+
* Created when user selects text (not an element) for annotation.
|
|
9
|
+
*/
|
|
10
|
+
export interface TextSelectionInfo {
|
|
11
|
+
/** The actual text content that was selected by the user */
|
|
12
|
+
selectedText: string;
|
|
13
|
+
/** The nearest common ancestor element containing the entire selection */
|
|
14
|
+
containerElement: Element;
|
|
15
|
+
}
|
|
6
16
|
export interface SelectedElementInfo {
|
|
7
17
|
color: string;
|
|
8
18
|
index: number;
|
|
9
19
|
displayText: string;
|
|
20
|
+
textSelection?: TextSelectionInfo;
|
|
10
21
|
}
|
|
11
22
|
type ComponentFinder = (el: Element) => ComponentInfo | null;
|
|
23
|
+
export interface WrapTextRangeResult {
|
|
24
|
+
wrapper: Element;
|
|
25
|
+
textSelection: TextSelectionInfo;
|
|
26
|
+
}
|
|
12
27
|
export interface ElementSelectionManager {
|
|
13
|
-
selectElement(element: Element, componentFinder?: ComponentFinder): void;
|
|
28
|
+
selectElement(element: Element, componentFinder?: ComponentFinder, textSelection?: TextSelectionInfo): void;
|
|
29
|
+
wrapTextRange(range: Range, containerElement: Element): WrapTextRangeResult | null;
|
|
14
30
|
deselectElement(element: Element): void;
|
|
15
31
|
clearAllSelections(): void;
|
|
16
32
|
hasElement(element: Element): boolean;
|
|
@@ -40,6 +40,7 @@ export declare class AnnotatorToolbar extends LitElement {
|
|
|
40
40
|
private reportPageContext;
|
|
41
41
|
private getPageContext;
|
|
42
42
|
private getSelectedElements;
|
|
43
|
+
private enrichElementsWithComments;
|
|
43
44
|
private triggerSelection;
|
|
44
45
|
private captureScreenshot;
|
|
45
46
|
private clearSelection;
|
|
@@ -48,6 +49,7 @@ export declare class AnnotatorToolbar extends LitElement {
|
|
|
48
49
|
private getConsoleLogs;
|
|
49
50
|
private handleElementSelected;
|
|
50
51
|
private handleMultiSelect;
|
|
52
|
+
private handleTextSelected;
|
|
51
53
|
private removeSelectedElement;
|
|
52
54
|
private showCommentPopoverForElement;
|
|
53
55
|
private handlePopoverKeydown;
|
|
@@ -6388,6 +6388,7 @@
|
|
|
6388
6388
|
|
|
6389
6389
|
// src/annotator/constants.ts
|
|
6390
6390
|
var Z_INDEX = {
|
|
6391
|
+
INSPECTION_OVERLAY: 999995,
|
|
6391
6392
|
HIGHLIGHT_OVERLAY: 999996,
|
|
6392
6393
|
HOVER_OVERLAY: 999997,
|
|
6393
6394
|
BADGE: 999998,
|
|
@@ -6402,6 +6403,25 @@
|
|
|
6402
6403
|
// Keep last N entries after trim
|
|
6403
6404
|
};
|
|
6404
6405
|
var SCREENSHOT_TIMEOUT_MS = 1e4;
|
|
6406
|
+
var SELECTION_COLORS = ["#FF00FF", "#00FFFF", "#FFFF00"];
|
|
6407
|
+
var COLORS = {
|
|
6408
|
+
INSPECTION: "#A855F7",
|
|
6409
|
+
// Purple for inspection
|
|
6410
|
+
BADGE_TEXT: "#050505",
|
|
6411
|
+
// Black for badge text
|
|
6412
|
+
BADGE_BG: "#050505"
|
|
6413
|
+
// Black for badge background
|
|
6414
|
+
};
|
|
6415
|
+
var FONTS = {
|
|
6416
|
+
MONO: "'JetBrains Mono', monospace",
|
|
6417
|
+
GOOGLE_FONTS_URL: "https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap"
|
|
6418
|
+
};
|
|
6419
|
+
var TEXT_SELECTION = {
|
|
6420
|
+
MAX_LENGTH: 1e4,
|
|
6421
|
+
// Maximum characters allowed in a text selection
|
|
6422
|
+
HIGHLIGHT_OPACITY: 0.3
|
|
6423
|
+
// Background opacity for text highlight
|
|
6424
|
+
};
|
|
6405
6425
|
|
|
6406
6426
|
// src/annotator/selection.ts
|
|
6407
6427
|
function createElementSelectionManager() {
|
|
@@ -6410,8 +6430,23 @@
|
|
|
6410
6430
|
let colorIndex = 0;
|
|
6411
6431
|
let onEditClickCallback = null;
|
|
6412
6432
|
let keyframesStyleElement = null;
|
|
6413
|
-
|
|
6414
|
-
|
|
6433
|
+
function unwrapTextSelection(element) {
|
|
6434
|
+
const parent = element.parentNode;
|
|
6435
|
+
if (!parent) {
|
|
6436
|
+
console.warn("[AI Annotator] Cannot unwrap text selection: element has no parent");
|
|
6437
|
+
return;
|
|
6438
|
+
}
|
|
6439
|
+
while (element.firstChild) {
|
|
6440
|
+
parent.insertBefore(element.firstChild, element);
|
|
6441
|
+
}
|
|
6442
|
+
element.remove();
|
|
6443
|
+
}
|
|
6444
|
+
function getDisplayText(index, element, componentFinder, textSelection) {
|
|
6445
|
+
if (textSelection) {
|
|
6446
|
+
const preview = textSelection.selectedText.substring(0, 15);
|
|
6447
|
+
const ellipsis = textSelection.selectedText.length > 15 ? "..." : "";
|
|
6448
|
+
return `#${index} "${preview}${ellipsis}"`;
|
|
6449
|
+
}
|
|
6415
6450
|
const component = componentFinder?.(element);
|
|
6416
6451
|
if (component && component.componentLocation) {
|
|
6417
6452
|
const componentPath = component.componentLocation.split("@")[0];
|
|
@@ -6434,14 +6469,14 @@
|
|
|
6434
6469
|
}
|
|
6435
6470
|
}
|
|
6436
6471
|
function createSelectionGroup(element, color, displayText) {
|
|
6437
|
-
const textColor =
|
|
6472
|
+
const textColor = COLORS.BADGE_TEXT;
|
|
6438
6473
|
const glowColor = color.toLowerCase();
|
|
6439
6474
|
const badge = document.createElement("div");
|
|
6440
6475
|
badge.classList.add("annotator-badge");
|
|
6441
6476
|
const shadow = badge.attachShadow({ mode: "open" });
|
|
6442
6477
|
const style = document.createElement("style");
|
|
6443
6478
|
style.textContent = `
|
|
6444
|
-
@import url('
|
|
6479
|
+
@import url('${FONTS.GOOGLE_FONTS_URL}');
|
|
6445
6480
|
|
|
6446
6481
|
@keyframes badge-glow {
|
|
6447
6482
|
0%, 100% { box-shadow: 2px 2px 0px ${color}44, 0 0 8px ${glowColor}80; }
|
|
@@ -6452,7 +6487,7 @@
|
|
|
6452
6487
|
display: flex;
|
|
6453
6488
|
align-items: center;
|
|
6454
6489
|
border: 1px solid ${color};
|
|
6455
|
-
background:
|
|
6490
|
+
background: ${COLORS.BADGE_BG};
|
|
6456
6491
|
box-shadow: 1px 1px 0px ${color}44, 0 0 6px ${glowColor}60;
|
|
6457
6492
|
animation: badge-glow 2s ease-in-out infinite;
|
|
6458
6493
|
cursor: pointer;
|
|
@@ -6471,7 +6506,7 @@
|
|
|
6471
6506
|
justify-content: center;
|
|
6472
6507
|
font-size: 9px;
|
|
6473
6508
|
font-weight: 700;
|
|
6474
|
-
font-family:
|
|
6509
|
+
font-family: ${FONTS.MONO};
|
|
6475
6510
|
white-space: nowrap;
|
|
6476
6511
|
text-transform: uppercase;
|
|
6477
6512
|
}
|
|
@@ -6580,14 +6615,42 @@
|
|
|
6580
6615
|
return children;
|
|
6581
6616
|
}
|
|
6582
6617
|
return {
|
|
6583
|
-
selectElement(element, componentFinder) {
|
|
6584
|
-
const color =
|
|
6618
|
+
selectElement(element, componentFinder, textSelection) {
|
|
6619
|
+
const color = SELECTION_COLORS[colorIndex % SELECTION_COLORS.length];
|
|
6585
6620
|
const index = selectedElements.size + 1;
|
|
6586
6621
|
colorIndex++;
|
|
6587
|
-
const displayText = getDisplayText(index, element, componentFinder);
|
|
6622
|
+
const displayText = getDisplayText(index, element, componentFinder, textSelection);
|
|
6588
6623
|
const group = createSelectionGroup(element, color, displayText);
|
|
6589
6624
|
selectionGroups.set(element, group);
|
|
6590
|
-
selectedElements.set(element, { color, index, displayText });
|
|
6625
|
+
selectedElements.set(element, { color, index, displayText, textSelection });
|
|
6626
|
+
},
|
|
6627
|
+
wrapTextRange(range, containerElement) {
|
|
6628
|
+
const selectedText = range.toString().trim();
|
|
6629
|
+
if (!selectedText) return null;
|
|
6630
|
+
if (selectedText.length > TEXT_SELECTION.MAX_LENGTH) {
|
|
6631
|
+
console.warn(`[AI Annotator] Text selection exceeds maximum length of ${TEXT_SELECTION.MAX_LENGTH} characters`);
|
|
6632
|
+
return null;
|
|
6633
|
+
}
|
|
6634
|
+
const highlightColor = SELECTION_COLORS[colorIndex % SELECTION_COLORS.length];
|
|
6635
|
+
const wrapper = document.createElement("span");
|
|
6636
|
+
wrapper.className = "annotator-text-selection annotator-ignore";
|
|
6637
|
+
wrapper.style.cssText = `
|
|
6638
|
+
background: ${highlightColor}4D;
|
|
6639
|
+
border-radius: 2px;
|
|
6640
|
+
`;
|
|
6641
|
+
try {
|
|
6642
|
+
range.surroundContents(wrapper);
|
|
6643
|
+
} catch (error) {
|
|
6644
|
+
console.warn("[AI Annotator] Cannot wrap cross-element text selection. Please select text within a single paragraph.");
|
|
6645
|
+
return null;
|
|
6646
|
+
}
|
|
6647
|
+
return {
|
|
6648
|
+
wrapper,
|
|
6649
|
+
textSelection: {
|
|
6650
|
+
selectedText,
|
|
6651
|
+
containerElement
|
|
6652
|
+
}
|
|
6653
|
+
};
|
|
6591
6654
|
},
|
|
6592
6655
|
deselectElement(element) {
|
|
6593
6656
|
const elementData = selectedElements.get(element);
|
|
@@ -6599,15 +6662,22 @@
|
|
|
6599
6662
|
group.overlay.remove();
|
|
6600
6663
|
selectionGroups.delete(element);
|
|
6601
6664
|
}
|
|
6665
|
+
if (elementData.textSelection && element.classList.contains("annotator-text-selection")) {
|
|
6666
|
+
unwrapTextSelection(element);
|
|
6667
|
+
}
|
|
6602
6668
|
selectedElements.delete(element);
|
|
6603
6669
|
reindexElements();
|
|
6604
6670
|
}
|
|
6605
6671
|
},
|
|
6606
6672
|
clearAllSelections() {
|
|
6607
|
-
selectionGroups.forEach((group) => {
|
|
6673
|
+
selectionGroups.forEach((group, element) => {
|
|
6608
6674
|
group.cleanup();
|
|
6609
6675
|
group.badge.remove();
|
|
6610
6676
|
group.overlay.remove();
|
|
6677
|
+
const elementData = selectedElements.get(element);
|
|
6678
|
+
if (elementData?.textSelection && element.classList.contains("annotator-text-selection")) {
|
|
6679
|
+
unwrapTextSelection(element);
|
|
6680
|
+
}
|
|
6611
6681
|
});
|
|
6612
6682
|
selectionGroups.clear();
|
|
6613
6683
|
selectedElements.clear();
|
|
@@ -6646,13 +6716,14 @@
|
|
|
6646
6716
|
const data = selectedElements.get(element);
|
|
6647
6717
|
const children = findSelectedChildren(element);
|
|
6648
6718
|
const componentData = componentFinder?.(element);
|
|
6719
|
+
const targetElement = data.textSelection?.containerElement || element;
|
|
6649
6720
|
const elementInfo = {
|
|
6650
6721
|
index: data.index,
|
|
6651
|
-
tagName:
|
|
6652
|
-
xpath: XPathUtils.generateXPath(
|
|
6653
|
-
cssSelector: XPathUtils.generateEnhancedCSSSelector(
|
|
6722
|
+
tagName: targetElement.tagName,
|
|
6723
|
+
xpath: XPathUtils.generateXPath(targetElement),
|
|
6724
|
+
cssSelector: XPathUtils.generateEnhancedCSSSelector(targetElement),
|
|
6654
6725
|
textContent: element.textContent?.substring(0, 100) || "",
|
|
6655
|
-
attributes: Array.from(
|
|
6726
|
+
attributes: Array.from(targetElement.attributes).reduce((acc, attr) => {
|
|
6656
6727
|
if (attr.name !== "style") {
|
|
6657
6728
|
acc[attr.name] = attr.value;
|
|
6658
6729
|
}
|
|
@@ -6660,11 +6731,24 @@
|
|
|
6660
6731
|
}, {}),
|
|
6661
6732
|
children: []
|
|
6662
6733
|
};
|
|
6734
|
+
if (data.textSelection && data.textSelection.containerElement.isConnected) {
|
|
6735
|
+
elementInfo.textSelection = {
|
|
6736
|
+
selectedText: data.textSelection.selectedText,
|
|
6737
|
+
containerXPath: XPathUtils.generateXPath(data.textSelection.containerElement),
|
|
6738
|
+
containerCssSelector: XPathUtils.generateEnhancedCSSSelector(data.textSelection.containerElement)
|
|
6739
|
+
};
|
|
6740
|
+
} else if (data.textSelection) {
|
|
6741
|
+
elementInfo.textSelection = {
|
|
6742
|
+
selectedText: data.textSelection.selectedText,
|
|
6743
|
+
containerXPath: "",
|
|
6744
|
+
containerCssSelector: ""
|
|
6745
|
+
};
|
|
6746
|
+
}
|
|
6663
6747
|
if (imagePaths && imagePaths.has(element)) {
|
|
6664
6748
|
elementInfo.imagePath = imagePaths.get(element);
|
|
6665
6749
|
}
|
|
6666
6750
|
try {
|
|
6667
|
-
const htmlElement =
|
|
6751
|
+
const htmlElement = targetElement;
|
|
6668
6752
|
const computedStyle = window.getComputedStyle(htmlElement);
|
|
6669
6753
|
elementInfo.computedStyles = {
|
|
6670
6754
|
width: htmlElement.offsetWidth,
|
|
@@ -6699,38 +6783,43 @@
|
|
|
6699
6783
|
var DRAG_THRESHOLD = 5;
|
|
6700
6784
|
var INITIAL_DRAG_STATE = { isDragging: false, startX: 0, startY: 0, currentX: 0, currentY: 0 };
|
|
6701
6785
|
function createInspectionManager(callbacks = {}) {
|
|
6702
|
-
const { onElementSelect, onMultiSelect, shouldIgnoreElement, isElementSelected, onEscape, onCopy } = callbacks;
|
|
6786
|
+
const { onElementSelect, onMultiSelect, onTextSelect, shouldIgnoreElement, isElementSelected, onEscape, onCopy } = callbacks;
|
|
6703
6787
|
let isInspecting = false;
|
|
6704
6788
|
let currentHoveredElement = null;
|
|
6705
6789
|
let hoverOverlay = null;
|
|
6706
6790
|
let hoverKeyframesStyleElement = null;
|
|
6707
|
-
let inspectionStyleElement = null;
|
|
6708
6791
|
let selectionOverlay = null;
|
|
6792
|
+
let glassPane = null;
|
|
6709
6793
|
let dragState = { ...INITIAL_DRAG_STATE };
|
|
6710
6794
|
let mouseDownTime = 0;
|
|
6711
|
-
function
|
|
6712
|
-
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
cursor: default !important;
|
|
6726
|
-
}
|
|
6795
|
+
function createGlassPane() {
|
|
6796
|
+
const pane = document.createElement("div");
|
|
6797
|
+
pane.id = "annotator-glass-pane";
|
|
6798
|
+
pane.className = "annotator-ignore";
|
|
6799
|
+
pane.style.cssText = `
|
|
6800
|
+
position: fixed;
|
|
6801
|
+
top: 0;
|
|
6802
|
+
left: 0;
|
|
6803
|
+
width: 100vw;
|
|
6804
|
+
height: 100vh;
|
|
6805
|
+
background: transparent;
|
|
6806
|
+
cursor: crosshair;
|
|
6807
|
+
z-index: ${Z_INDEX.INSPECTION_OVERLAY};
|
|
6808
|
+
pointer-events: auto;
|
|
6727
6809
|
`;
|
|
6728
|
-
|
|
6810
|
+
pane.addEventListener("mousedown", handleMouseDown, true);
|
|
6811
|
+
pane.addEventListener("mousemove", handleMouseMove, true);
|
|
6812
|
+
pane.addEventListener("mouseup", handleMouseUp, true);
|
|
6813
|
+
pane.addEventListener("click", preventClick, true);
|
|
6814
|
+
pane.addEventListener("dblclick", preventMouseEvents, true);
|
|
6815
|
+
pane.addEventListener("contextmenu", preventMouseEvents, true);
|
|
6816
|
+
document.body.appendChild(pane);
|
|
6817
|
+
return pane;
|
|
6729
6818
|
}
|
|
6730
|
-
function
|
|
6731
|
-
if (
|
|
6732
|
-
|
|
6733
|
-
|
|
6819
|
+
function removeGlassPane() {
|
|
6820
|
+
if (glassPane) {
|
|
6821
|
+
glassPane.remove();
|
|
6822
|
+
glassPane = null;
|
|
6734
6823
|
}
|
|
6735
6824
|
}
|
|
6736
6825
|
function removeHoverHighlight() {
|
|
@@ -6752,7 +6841,7 @@
|
|
|
6752
6841
|
`;
|
|
6753
6842
|
document.head.appendChild(hoverKeyframesStyleElement);
|
|
6754
6843
|
}
|
|
6755
|
-
const color =
|
|
6844
|
+
const color = COLORS.INSPECTION;
|
|
6756
6845
|
const overlay = document.createElement("div");
|
|
6757
6846
|
overlay.className = "annotator-hover-overlay";
|
|
6758
6847
|
const rect = element.getBoundingClientRect();
|
|
@@ -6785,15 +6874,13 @@
|
|
|
6785
6874
|
hoverOverlay.style.height = `${rect.height}px`;
|
|
6786
6875
|
}
|
|
6787
6876
|
function getElementAtPoint(x2, y3) {
|
|
6788
|
-
if (
|
|
6789
|
-
|
|
6790
|
-
|
|
6877
|
+
if (!glassPane) return null;
|
|
6878
|
+
const originalPointerEvents = glassPane.style.pointerEvents;
|
|
6879
|
+
glassPane.style.pointerEvents = "none";
|
|
6791
6880
|
try {
|
|
6792
6881
|
return document.elementFromPoint(x2, y3);
|
|
6793
6882
|
} finally {
|
|
6794
|
-
|
|
6795
|
-
inspectionStyleElement.disabled = false;
|
|
6796
|
-
}
|
|
6883
|
+
glassPane.style.pointerEvents = originalPointerEvents;
|
|
6797
6884
|
}
|
|
6798
6885
|
}
|
|
6799
6886
|
function createSelectionOverlay() {
|
|
@@ -6801,7 +6888,7 @@
|
|
|
6801
6888
|
overlay.className = "annotator-ignore";
|
|
6802
6889
|
overlay.style.cssText = `
|
|
6803
6890
|
position: fixed;
|
|
6804
|
-
border: 2px dashed
|
|
6891
|
+
border: 2px dashed ${COLORS.INSPECTION};
|
|
6805
6892
|
background: rgba(168, 85, 247, 0.1);
|
|
6806
6893
|
pointer-events: none;
|
|
6807
6894
|
z-index: ${Z_INDEX.HOVER_OVERLAY};
|
|
@@ -6839,26 +6926,28 @@
|
|
|
6839
6926
|
return inner.left >= outer.left && inner.right <= outer.right && inner.top >= outer.top && inner.bottom <= outer.bottom;
|
|
6840
6927
|
}
|
|
6841
6928
|
function findElementsFullyInRect(rect) {
|
|
6842
|
-
if (
|
|
6843
|
-
inspectionStyleElement.disabled = true;
|
|
6844
|
-
}
|
|
6929
|
+
if (glassPane) glassPane.style.display = "none";
|
|
6845
6930
|
try {
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
if (
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
elements.push(element);
|
|
6931
|
+
let traverse2 = function(node) {
|
|
6932
|
+
if (shouldIgnoreElement?.(node)) return;
|
|
6933
|
+
if (node.tagName === "SCRIPT" || node.tagName === "STYLE" || node.tagName === "NOSCRIPT") return;
|
|
6934
|
+
const elementRect = node.getBoundingClientRect();
|
|
6935
|
+
if (elementRect.width > 0 && elementRect.height > 0) {
|
|
6936
|
+
if (isFullyContained(elementRect, rect)) {
|
|
6937
|
+
elements.push(node);
|
|
6938
|
+
}
|
|
6855
6939
|
}
|
|
6856
|
-
|
|
6940
|
+
const children = node.children;
|
|
6941
|
+
for (let i5 = 0; i5 < children.length; i5++) {
|
|
6942
|
+
traverse2(children[i5]);
|
|
6943
|
+
}
|
|
6944
|
+
};
|
|
6945
|
+
var traverse = traverse2;
|
|
6946
|
+
const elements = [];
|
|
6947
|
+
traverse2(document.body);
|
|
6857
6948
|
return elements;
|
|
6858
6949
|
} finally {
|
|
6859
|
-
if (
|
|
6860
|
-
inspectionStyleElement.disabled = false;
|
|
6861
|
-
}
|
|
6950
|
+
if (glassPane) glassPane.style.display = "block";
|
|
6862
6951
|
}
|
|
6863
6952
|
}
|
|
6864
6953
|
function filterLeafElements(elements) {
|
|
@@ -6868,7 +6957,7 @@
|
|
|
6868
6957
|
}
|
|
6869
6958
|
function handleMouseDown(e5) {
|
|
6870
6959
|
const clickedElement = e5.target;
|
|
6871
|
-
if (shouldIgnoreElement?.(clickedElement)) return;
|
|
6960
|
+
if (shouldIgnoreElement?.(clickedElement) && clickedElement !== glassPane) return;
|
|
6872
6961
|
mouseDownTime = Date.now();
|
|
6873
6962
|
dragState = {
|
|
6874
6963
|
isDragging: false,
|
|
@@ -6911,38 +7000,55 @@
|
|
|
6911
7000
|
hoverOverlay = createHoverOverlay(target);
|
|
6912
7001
|
currentHoveredElement = target;
|
|
6913
7002
|
}
|
|
7003
|
+
function detectTextSelection() {
|
|
7004
|
+
const selection = window.getSelection();
|
|
7005
|
+
if (!selection || selection.isCollapsed || selection.rangeCount === 0) return null;
|
|
7006
|
+
const selectedText = selection.toString().trim();
|
|
7007
|
+
if (selectedText.length === 0) return null;
|
|
7008
|
+
const range = selection.getRangeAt(0);
|
|
7009
|
+
const ancestor = range.commonAncestorContainer;
|
|
7010
|
+
const commonAncestor = ancestor.nodeType === Node.ELEMENT_NODE ? ancestor : ancestor.parentElement;
|
|
7011
|
+
if (!commonAncestor || shouldIgnoreElement?.(commonAncestor)) return null;
|
|
7012
|
+
return { range, commonAncestor };
|
|
7013
|
+
}
|
|
6914
7014
|
function handleMouseUp(e5) {
|
|
6915
7015
|
const wasDragging = dragState.isDragging;
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
7016
|
+
try {
|
|
7017
|
+
if (wasDragging) {
|
|
7018
|
+
removeSelectionOverlay();
|
|
7019
|
+
const selectionRect = getSelectionRect();
|
|
7020
|
+
if (selectionRect.width > 10 && selectionRect.height > 10) {
|
|
7021
|
+
const elementsInRect = findElementsFullyInRect(selectionRect);
|
|
7022
|
+
const leafElements = filterLeafElements(elementsInRect);
|
|
7023
|
+
if (leafElements.length > 0) {
|
|
7024
|
+
onMultiSelect?.(leafElements);
|
|
7025
|
+
}
|
|
7026
|
+
}
|
|
7027
|
+
} else if (mouseDownTime > 0) {
|
|
7028
|
+
const textSelection = detectTextSelection();
|
|
7029
|
+
if (textSelection) {
|
|
7030
|
+
const range = textSelection.range.cloneRange();
|
|
7031
|
+
const commonAncestor = textSelection.commonAncestor;
|
|
7032
|
+
window.getSelection()?.removeAllRanges();
|
|
7033
|
+
onTextSelect?.(range, commonAncestor);
|
|
7034
|
+
return;
|
|
7035
|
+
}
|
|
7036
|
+
const target = getElementAtPoint(e5.clientX, e5.clientY);
|
|
7037
|
+
if (target && !shouldIgnoreElement?.(target)) {
|
|
7038
|
+
onElementSelect?.(target);
|
|
6924
7039
|
}
|
|
6925
7040
|
}
|
|
6926
|
-
}
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
onElementSelect?.(target);
|
|
6930
|
-
}
|
|
7041
|
+
} finally {
|
|
7042
|
+
mouseDownTime = 0;
|
|
7043
|
+
dragState = { ...INITIAL_DRAG_STATE };
|
|
6931
7044
|
}
|
|
6932
|
-
mouseDownTime = 0;
|
|
6933
|
-
dragState = { ...INITIAL_DRAG_STATE };
|
|
6934
7045
|
}
|
|
6935
7046
|
function preventClick(e5) {
|
|
6936
|
-
const target = e5.target;
|
|
6937
|
-
if (shouldIgnoreElement?.(target)) return;
|
|
6938
7047
|
e5.preventDefault();
|
|
6939
7048
|
e5.stopPropagation();
|
|
6940
7049
|
e5.stopImmediatePropagation();
|
|
6941
7050
|
}
|
|
6942
7051
|
function preventMouseEvents(e5) {
|
|
6943
|
-
const target = e5.target;
|
|
6944
|
-
if (shouldIgnoreElement?.(target)) return;
|
|
6945
|
-
if (dragState.isDragging) return;
|
|
6946
7052
|
e5.preventDefault();
|
|
6947
7053
|
e5.stopPropagation();
|
|
6948
7054
|
e5.stopImmediatePropagation();
|
|
@@ -6967,16 +7073,11 @@
|
|
|
6967
7073
|
removeSelectionOverlay();
|
|
6968
7074
|
}
|
|
6969
7075
|
function cleanup() {
|
|
6970
|
-
|
|
6971
|
-
document.removeEventListener("mousedown", handleMouseDown, true);
|
|
6972
|
-
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
6973
|
-
document.removeEventListener("mouseup", handleMouseUp, true);
|
|
6974
|
-
document.removeEventListener("click", preventClick, true);
|
|
6975
|
-
document.removeEventListener("dblclick", preventMouseEvents, true);
|
|
6976
|
-
document.removeEventListener("contextmenu", preventMouseEvents, true);
|
|
7076
|
+
removeGlassPane();
|
|
6977
7077
|
document.removeEventListener("keydown", handleKeyDown);
|
|
6978
7078
|
removeHoverHighlight();
|
|
6979
7079
|
resetDragState();
|
|
7080
|
+
window.getSelection()?.removeAllRanges();
|
|
6980
7081
|
}
|
|
6981
7082
|
function cleanupKeyframesStyle() {
|
|
6982
7083
|
if (hoverKeyframesStyleElement) {
|
|
@@ -6988,13 +7089,7 @@
|
|
|
6988
7089
|
enterInspectionMode() {
|
|
6989
7090
|
if (isInspecting) return;
|
|
6990
7091
|
isInspecting = true;
|
|
6991
|
-
|
|
6992
|
-
document.addEventListener("mousedown", handleMouseDown, true);
|
|
6993
|
-
document.addEventListener("mousemove", handleMouseMove, true);
|
|
6994
|
-
document.addEventListener("mouseup", handleMouseUp, true);
|
|
6995
|
-
document.addEventListener("click", preventClick, true);
|
|
6996
|
-
document.addEventListener("dblclick", preventMouseEvents, true);
|
|
6997
|
-
document.addEventListener("contextmenu", preventMouseEvents, true);
|
|
7092
|
+
glassPane = createGlassPane();
|
|
6998
7093
|
document.addEventListener("keydown", handleKeyDown);
|
|
6999
7094
|
},
|
|
7000
7095
|
exitInspectionMode() {
|
|
@@ -7589,6 +7684,7 @@
|
|
|
7589
7684
|
this.inspectionManager = createInspectionManager({
|
|
7590
7685
|
onElementSelect: (element) => this.handleElementSelected(element),
|
|
7591
7686
|
onMultiSelect: (elements) => this.handleMultiSelect(elements),
|
|
7687
|
+
onTextSelect: (range, commonAncestor) => this.handleTextSelected(range, commonAncestor),
|
|
7592
7688
|
shouldIgnoreElement: (element) => this.shouldIgnoreElement(element),
|
|
7593
7689
|
isElementSelected: (element) => this.selectionManager?.hasElement(element) || false,
|
|
7594
7690
|
onEscape: () => this.exitInspectingMode(),
|
|
@@ -7695,24 +7791,24 @@
|
|
|
7695
7791
|
const elements = this.selectionManager.buildHierarchicalStructure(
|
|
7696
7792
|
(el) => findNearestComponent(el, this.verbose)
|
|
7697
7793
|
);
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7794
|
+
this.enrichElementsWithComments(elements, this.selectionManager.getSelectedElements());
|
|
7795
|
+
return elements;
|
|
7796
|
+
}
|
|
7797
|
+
enrichElementsWithComments(items, selectedElements) {
|
|
7798
|
+
for (const item of items) {
|
|
7799
|
+
for (const [element, info] of selectedElements) {
|
|
7800
|
+
if (info.index === item.index) {
|
|
7801
|
+
const comment = this.elementComments.get(element);
|
|
7802
|
+
if (comment) {
|
|
7803
|
+
item.comment = comment;
|
|
7707
7804
|
}
|
|
7708
|
-
|
|
7709
|
-
if (item.children.length > 0) {
|
|
7710
|
-
addComments(item.children, selectedElements);
|
|
7805
|
+
break;
|
|
7711
7806
|
}
|
|
7712
7807
|
}
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
7808
|
+
if (item.children.length > 0) {
|
|
7809
|
+
this.enrichElementsWithComments(item.children, selectedElements);
|
|
7810
|
+
}
|
|
7811
|
+
}
|
|
7716
7812
|
}
|
|
7717
7813
|
triggerSelection(mode, selector, selectorType) {
|
|
7718
7814
|
try {
|
|
@@ -7878,6 +7974,29 @@
|
|
|
7878
7974
|
}
|
|
7879
7975
|
this.emitSelectionChanged();
|
|
7880
7976
|
}
|
|
7977
|
+
handleTextSelected(range, commonAncestor) {
|
|
7978
|
+
if (!this.selectionManager) return;
|
|
7979
|
+
const result = this.selectionManager.wrapTextRange(range, commonAncestor);
|
|
7980
|
+
if (!result) {
|
|
7981
|
+
this.showToast("Select text within one element");
|
|
7982
|
+
return;
|
|
7983
|
+
}
|
|
7984
|
+
try {
|
|
7985
|
+
this.selectionManager.selectElement(
|
|
7986
|
+
result.wrapper,
|
|
7987
|
+
(el) => findNearestComponent(el, this.verbose),
|
|
7988
|
+
result.textSelection
|
|
7989
|
+
);
|
|
7990
|
+
this.showCommentPopoverForElement(result.wrapper);
|
|
7991
|
+
this.selectionCount = this.selectionManager.getSelectedCount();
|
|
7992
|
+
this.emitSelectionChanged();
|
|
7993
|
+
} catch (error) {
|
|
7994
|
+
result.wrapper.remove();
|
|
7995
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7996
|
+
this.log("Text selection error:", message);
|
|
7997
|
+
this.showToast("Selection error");
|
|
7998
|
+
}
|
|
7999
|
+
}
|
|
7881
8000
|
removeSelectedElement() {
|
|
7882
8001
|
if (!this.commentPopover.element || !this.selectionManager) return;
|
|
7883
8002
|
const element = this.commentPopover.element;
|
package/dist/rpc/define.d.ts
CHANGED
|
@@ -10,6 +10,26 @@ export interface PageContext {
|
|
|
10
10
|
selectionCount: number;
|
|
11
11
|
isInspecting: boolean;
|
|
12
12
|
}
|
|
13
|
+
export interface ElementTextSelection {
|
|
14
|
+
selectedText: string;
|
|
15
|
+
containerXPath: string;
|
|
16
|
+
containerCssSelector: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ElementComputedStyles {
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
fontSize: string;
|
|
22
|
+
fontFamily: string;
|
|
23
|
+
color?: string;
|
|
24
|
+
backgroundColor?: string;
|
|
25
|
+
display?: string;
|
|
26
|
+
position?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ElementComponentData {
|
|
29
|
+
componentLocation: string;
|
|
30
|
+
componentName?: string;
|
|
31
|
+
framework?: 'vue' | 'react' | 'angular' | 'svelte' | 'vanilla';
|
|
32
|
+
}
|
|
13
33
|
export interface ElementData {
|
|
14
34
|
index: number;
|
|
15
35
|
tagName: string;
|
|
@@ -19,21 +39,9 @@ export interface ElementData {
|
|
|
19
39
|
attributes: Record<string, string>;
|
|
20
40
|
imagePath?: string;
|
|
21
41
|
comment?: string;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
fontSize: string;
|
|
26
|
-
fontFamily: string;
|
|
27
|
-
color?: string;
|
|
28
|
-
backgroundColor?: string;
|
|
29
|
-
display?: string;
|
|
30
|
-
position?: string;
|
|
31
|
-
};
|
|
32
|
-
componentData?: {
|
|
33
|
-
componentLocation: string;
|
|
34
|
-
componentName?: string;
|
|
35
|
-
framework?: 'vue' | 'react' | 'angular' | 'svelte' | 'vanilla';
|
|
36
|
-
};
|
|
42
|
+
textSelection?: ElementTextSelection;
|
|
43
|
+
computedStyles?: ElementComputedStyles;
|
|
44
|
+
componentData?: ElementComponentData;
|
|
37
45
|
children: ElementData[];
|
|
38
46
|
}
|
|
39
47
|
export interface ScreenshotResult {
|
package/package.json
CHANGED