@promakeai/inspector 1.0.0 → 1.0.3
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/README.md +111 -0
- package/dist/App.d.ts.map +1 -0
- package/dist/__tests__/App.test.d.ts.map +1 -0
- package/dist/components/Badge.d.ts.map +1 -0
- package/dist/components/ControlBox/ContentArea.d.ts.map +1 -0
- package/dist/components/ControlBox/PromptInput.d.ts.map +1 -0
- package/dist/components/ControlBox/index.d.ts.map +1 -0
- package/dist/components/ImageEditor/UploadBox.d.ts.map +1 -0
- package/dist/components/ImageEditor/index.d.ts.map +1 -0
- package/dist/components/Overlay.d.ts.map +1 -0
- package/dist/components/StyleEditor/BorderSection.d.ts.map +1 -0
- package/dist/components/StyleEditor/ColorPicker.d.ts.map +1 -0
- package/dist/components/StyleEditor/DisplaySection.d.ts.map +1 -0
- package/dist/components/StyleEditor/ImageSection.d.ts.map +1 -0
- package/dist/components/StyleEditor/LayoutSection.d.ts.map +1 -0
- package/dist/components/StyleEditor/NumberInput.d.ts.map +1 -0
- package/dist/components/StyleEditor/SliderInput.d.ts.map +1 -0
- package/dist/components/StyleEditor/SpacingSection.d.ts.map +1 -0
- package/dist/components/StyleEditor/TextSection.d.ts.map +1 -0
- package/dist/components/StyleEditor/index.d.ts.map +1 -0
- package/dist/components/TextEditor/index.d.ts.map +1 -0
- package/dist/components/ui/CustomCollapsible.d.ts.map +1 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/color-picker.d.ts.map +1 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/popover.d.ts.map +1 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/slider.d.ts.map +1 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/core/highlighter.d.ts.map +1 -0
- package/dist/hooks/useMessageBridge.d.ts.map +1 -0
- package/dist/hooks/useStylePreview.d.ts.map +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/store/useInspectorStore.d.ts.map +1 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/utils/colorUtils.d.ts.map +1 -0
- package/dist/utils/elementNames.d.ts.map +1 -0
- package/dist/utils/elementUtils.d.ts.map +1 -0
- package/dist/utils/errorTracker.d.ts.map +1 -0
- package/dist/utils/inputStyles.d.ts.map +1 -0
- package/dist/utils/styleUtils.d.ts.map +1 -0
- package/dist/utils/tailwindMapper.d.ts.map +1 -0
- package/dist/utils/urlTracker.d.ts.map +1 -0
- package/package.json +15 -10
- package/dist/packages/inspector/src/App.d.ts.map +0 -1
- package/dist/packages/inspector/src/__tests__/App.test.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/Badge.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ControlBox/ContentArea.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ControlBox/PromptInput.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ControlBox/index.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ImageEditor/UploadBox.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ImageEditor/index.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/Overlay.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/BorderSection.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/ColorPicker.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/DisplaySection.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/ImageSection.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/LayoutSection.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/NumberInput.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/SliderInput.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/SpacingSection.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/TextSection.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/StyleEditor/index.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/TextEditor/index.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ui/CustomCollapsible.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ui/button.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ui/color-picker.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ui/input.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ui/popover.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ui/select.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ui/slider.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ui/textarea.d.ts.map +0 -1
- package/dist/packages/inspector/src/components/ui/tooltip.d.ts.map +0 -1
- package/dist/packages/inspector/src/core/highlighter.d.ts.map +0 -1
- package/dist/packages/inspector/src/hooks/useMessageBridge.d.ts.map +0 -1
- package/dist/packages/inspector/src/hooks/useStylePreview.d.ts.map +0 -1
- package/dist/packages/inspector/src/index.d.ts.map +0 -1
- package/dist/packages/inspector/src/lib/utils.d.ts.map +0 -1
- package/dist/packages/inspector/src/plugin.d.ts.map +0 -1
- package/dist/packages/inspector/src/store/useInspectorStore.d.ts.map +0 -1
- package/dist/packages/inspector/src/styles.d.ts.map +0 -1
- package/dist/packages/inspector/src/utils/colorUtils.d.ts.map +0 -1
- package/dist/packages/inspector/src/utils/elementNames.d.ts.map +0 -1
- package/dist/packages/inspector/src/utils/elementUtils.d.ts.map +0 -1
- package/dist/packages/inspector/src/utils/errorTracker.d.ts.map +0 -1
- package/dist/packages/inspector/src/utils/inputStyles.d.ts.map +0 -1
- package/dist/packages/inspector/src/utils/styleUtils.d.ts.map +0 -1
- package/dist/packages/inspector/src/utils/tailwindMapper.d.ts.map +0 -1
- package/dist/packages/inspector/src/utils/urlTracker.d.ts.map +0 -1
- package/dist/packages/inspector/tsconfig.tsbuildinfo +0 -1
- package/src/App.tsx +0 -912
- package/src/__tests__/App.test.tsx +0 -373
- package/src/assets/fonts/Satoshi-Variable.woff +0 -0
- package/src/assets/fonts/Satoshi-Variable.woff2 +0 -0
- package/src/components/Badge.tsx +0 -118
- package/src/components/ControlBox/ContentArea.tsx +0 -13
- package/src/components/ControlBox/PromptInput.module.css +0 -66
- package/src/components/ControlBox/PromptInput.tsx +0 -104
- package/src/components/ControlBox/index.module.css +0 -81
- package/src/components/ControlBox/index.tsx +0 -409
- package/src/components/ImageEditor/UploadBox.module.css +0 -69
- package/src/components/ImageEditor/UploadBox.tsx +0 -113
- package/src/components/ImageEditor/index.module.css +0 -11
- package/src/components/ImageEditor/index.tsx +0 -84
- package/src/components/Overlay.tsx +0 -157
- package/src/components/StyleEditor/BorderSection.tsx +0 -147
- package/src/components/StyleEditor/ColorPicker.tsx +0 -182
- package/src/components/StyleEditor/DisplaySection.tsx +0 -349
- package/src/components/StyleEditor/ImageSection.tsx +0 -105
- package/src/components/StyleEditor/LayoutSection.tsx +0 -63
- package/src/components/StyleEditor/NumberInput.tsx +0 -138
- package/src/components/StyleEditor/SliderInput.tsx +0 -121
- package/src/components/StyleEditor/SpacingSection.tsx +0 -365
- package/src/components/StyleEditor/TextSection.tsx +0 -381
- package/src/components/StyleEditor/index.module.css +0 -133
- package/src/components/StyleEditor/index.tsx +0 -612
- package/src/components/StyleEditor/shared.module.css +0 -193
- package/src/components/TextEditor/index.module.css +0 -31
- package/src/components/TextEditor/index.tsx +0 -166
- package/src/components/ui/CustomCollapsible.tsx +0 -159
- package/src/components/ui/button.module.css +0 -141
- package/src/components/ui/button.tsx +0 -73
- package/src/components/ui/color-picker.module.css +0 -112
- package/src/components/ui/color-picker.tsx +0 -146
- package/src/components/ui/input.module.css +0 -49
- package/src/components/ui/input.tsx +0 -34
- package/src/components/ui/popover.module.css +0 -42
- package/src/components/ui/popover.tsx +0 -59
- package/src/components/ui/select.module.css +0 -160
- package/src/components/ui/select.tsx +0 -216
- package/src/components/ui/slider.module.css +0 -75
- package/src/components/ui/slider.tsx +0 -60
- package/src/components/ui/textarea.module.css +0 -30
- package/src/components/ui/textarea.tsx +0 -23
- package/src/components/ui/tooltip.module.css +0 -11
- package/src/components/ui/tooltip.tsx +0 -37
- package/src/core/highlighter.ts +0 -197
- package/src/hooks/useMessageBridge.ts +0 -49
- package/src/hooks/useStylePreview.ts +0 -332
- package/src/index.ts +0 -20
- package/src/lib/utils.ts +0 -5
- package/src/plugin.ts +0 -11
- package/src/store/useInspectorStore.ts +0 -235
- package/src/styles/fonts.css +0 -15
- package/src/styles/global.css +0 -138
- package/src/styles/variables.css +0 -151
- package/src/styles.ts +0 -5
- package/src/utils/colorUtils.ts +0 -133
- package/src/utils/elementNames.ts +0 -103
- package/src/utils/elementUtils.ts +0 -90
- package/src/utils/errorTracker.ts +0 -186
- package/src/utils/inputStyles.ts +0 -30
- package/src/utils/styleUtils.ts +0 -226
- package/src/utils/tailwindMapper.ts +0 -554
- package/src/utils/urlTracker.ts +0 -75
- package/src/vite-env.d.ts +0 -7
- /package/dist/{packages/inspector/src/App.d.ts → App.d.ts} +0 -0
- /package/dist/{packages/inspector/src/__tests__ → __tests__}/App.test.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/Badge.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ControlBox/ContentArea.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ControlBox/PromptInput.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ControlBox/index.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ImageEditor/UploadBox.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ImageEditor/index.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/Overlay.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/BorderSection.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/ColorPicker.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/DisplaySection.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/ImageSection.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/LayoutSection.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/NumberInput.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/SliderInput.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/SpacingSection.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/TextSection.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/StyleEditor/index.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/TextEditor/index.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ui/CustomCollapsible.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ui/button.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ui/color-picker.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ui/input.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ui/popover.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ui/select.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ui/slider.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ui/textarea.d.ts +0 -0
- /package/dist/{packages/inspector/src/components → components}/ui/tooltip.d.ts +0 -0
- /package/dist/{packages/inspector/src/core → core}/highlighter.d.ts +0 -0
- /package/dist/{packages/inspector/src/hooks → hooks}/useMessageBridge.d.ts +0 -0
- /package/dist/{packages/inspector/src/hooks → hooks}/useStylePreview.d.ts +0 -0
- /package/dist/{packages/inspector/src/index.d.ts → index.d.ts} +0 -0
- /package/dist/{packages/inspector/src/lib → lib}/utils.d.ts +0 -0
- /package/dist/{packages/inspector/src/plugin.d.ts → plugin.d.ts} +0 -0
- /package/dist/{packages/inspector/src/store → store}/useInspectorStore.d.ts +0 -0
- /package/dist/{packages/inspector/src/styles.d.ts → styles.d.ts} +0 -0
- /package/dist/{packages/inspector/src/utils → utils}/colorUtils.d.ts +0 -0
- /package/dist/{packages/inspector/src/utils → utils}/elementNames.d.ts +0 -0
- /package/dist/{packages/inspector/src/utils → utils}/elementUtils.d.ts +0 -0
- /package/dist/{packages/inspector/src/utils → utils}/errorTracker.d.ts +0 -0
- /package/dist/{packages/inspector/src/utils → utils}/inputStyles.d.ts +0 -0
- /package/dist/{packages/inspector/src/utils → utils}/styleUtils.d.ts +0 -0
- /package/dist/{packages/inspector/src/utils → utils}/tailwindMapper.d.ts +0 -0
- /package/dist/{packages/inspector/src/utils → utils}/urlTracker.d.ts +0 -0
package/src/App.tsx
DELETED
|
@@ -1,912 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Inspector Canvas - Main App Component
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { useState, useEffect, useMemo, useRef } from "react";
|
|
6
|
-
import { useMessageBridge } from "./hooks/useMessageBridge";
|
|
7
|
-
import { ErrorTracker } from "./utils/errorTracker";
|
|
8
|
-
import { UrlTracker } from "./utils/urlTracker";
|
|
9
|
-
import { Overlay } from "./components/Overlay";
|
|
10
|
-
import { ControlBox } from "./components/ControlBox";
|
|
11
|
-
import { Badge } from "./components/Badge";
|
|
12
|
-
import { useInspectorStore } from "./store/useInspectorStore";
|
|
13
|
-
import { ElementHighlighter } from "./core/highlighter";
|
|
14
|
-
import {
|
|
15
|
-
ComponentInfo,
|
|
16
|
-
SelectedElementData,
|
|
17
|
-
ElementReference,
|
|
18
|
-
} from "@promakeai/inspector-types";
|
|
19
|
-
|
|
20
|
-
const idAttribute = "data-dev-id";
|
|
21
|
-
|
|
22
|
-
const normalizeId = (id: string) => {
|
|
23
|
-
return id.replace(/\\/g, "/");
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const deNormalizeId = (id: string) => {
|
|
27
|
-
// Her / karakterini \\\\ ile değiştir (CSS selector için double escape)
|
|
28
|
-
return id.replace(/\//g, "\\\\\\\\");
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const isElementInViewport = (el: Element) => {
|
|
32
|
-
const rect = el.getBoundingClientRect();
|
|
33
|
-
return (
|
|
34
|
-
rect.top >= 0 &&
|
|
35
|
-
rect.left >= 0 &&
|
|
36
|
-
rect.bottom <=
|
|
37
|
-
(window.innerHeight || document.documentElement.clientHeight) &&
|
|
38
|
-
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
|
39
|
-
);
|
|
40
|
-
};
|
|
41
|
-
const findElementById = (id: string | ElementReference) => {
|
|
42
|
-
const idString = typeof id === "string" ? id : id.id;
|
|
43
|
-
const denormalizedId = idString.replace(/\//g, "\\");
|
|
44
|
-
const escapedId = CSS.escape(denormalizedId);
|
|
45
|
-
|
|
46
|
-
console.log({
|
|
47
|
-
id: idString,
|
|
48
|
-
denormalizedId,
|
|
49
|
-
escapedId,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Try exact match first
|
|
53
|
-
let element =
|
|
54
|
-
document.querySelector(`[${idAttribute}="${escapedId}"]`) ||
|
|
55
|
-
document.querySelector(`[${idAttribute}="${CSS.escape(idString)}"]`) ||
|
|
56
|
-
document.querySelector(
|
|
57
|
-
`[${idAttribute}="${CSS.escape(normalizeId(idString))}"]`
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
// If not found, try to find by partial match (for components)
|
|
61
|
-
if (!element) {
|
|
62
|
-
const allElements = document.querySelectorAll(`[${idAttribute}]`);
|
|
63
|
-
for (const el of allElements) {
|
|
64
|
-
const devId = el.getAttribute(idAttribute);
|
|
65
|
-
if (devId && devId.includes(idString)) {
|
|
66
|
-
element = el;
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// If object with selector provided, try selector as fallback
|
|
73
|
-
if (!element && typeof id === "object" && id.selector) {
|
|
74
|
-
element = document.querySelector(id.selector);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return element;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
function generateSelector(element: HTMLElement): string {
|
|
81
|
-
if (element.id) {
|
|
82
|
-
return "#" + element.id;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
let selector = element.tagName.toLowerCase();
|
|
86
|
-
|
|
87
|
-
if (element.className && typeof element.className === "string") {
|
|
88
|
-
const classes = element.className
|
|
89
|
-
.trim()
|
|
90
|
-
.split(/\s+/)
|
|
91
|
-
.filter((c) => c);
|
|
92
|
-
if (classes.length > 0) {
|
|
93
|
-
selector += "." + classes.join(".");
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return selector;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function getComponentInfo(element: HTMLElement): ComponentInfo | null {
|
|
101
|
-
const componentElement = element.hasAttribute(idAttribute)
|
|
102
|
-
? element
|
|
103
|
-
: element.closest(`[${idAttribute}]`);
|
|
104
|
-
|
|
105
|
-
const dataDevId = componentElement?.getAttribute(idAttribute);
|
|
106
|
-
// Get all attributes from vite-plugin-component-debugger
|
|
107
|
-
const dataDevName = componentElement?.getAttribute("data-dev-name");
|
|
108
|
-
const dataDevPath = componentElement?.getAttribute("data-dev-path");
|
|
109
|
-
const dataDevComponent = componentElement?.getAttribute("data-dev-component");
|
|
110
|
-
|
|
111
|
-
// Normalize paths: replace Windows backslashes with forward slashes
|
|
112
|
-
const normalizedPath = dataDevPath ? normalizeId(dataDevPath) : undefined;
|
|
113
|
-
const normalizedId = dataDevId ? normalizeId(dataDevId) : undefined;
|
|
114
|
-
|
|
115
|
-
const parts = dataDevId?.split(":");
|
|
116
|
-
|
|
117
|
-
const lineNumber = parts?.[1] ? parseInt(parts[1], 10) : 0;
|
|
118
|
-
const columnNumber = parts?.[2] ? parseInt(parts[2], 10) : 0;
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
id: normalizedId,
|
|
122
|
-
name: dataDevName || undefined,
|
|
123
|
-
path: normalizedPath || undefined,
|
|
124
|
-
fileName: normalizedPath || "production build",
|
|
125
|
-
lineNumber: lineNumber,
|
|
126
|
-
columnNumber: columnNumber,
|
|
127
|
-
component: dataDevComponent || dataDevName || "Unknown",
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function getElementReference(element: HTMLElement): ElementReference {
|
|
132
|
-
const component = getComponentInfo(element);
|
|
133
|
-
return {
|
|
134
|
-
id: component?.id || "",
|
|
135
|
-
tagName: element.tagName,
|
|
136
|
-
className: element.className,
|
|
137
|
-
selector: generateSelector(element),
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function collectParents(element: HTMLElement): ElementReference[] {
|
|
142
|
-
const parents: ElementReference[] = [];
|
|
143
|
-
let current = element.parentElement;
|
|
144
|
-
let count = 0;
|
|
145
|
-
|
|
146
|
-
while (current && count < 3) {
|
|
147
|
-
// Skip inspector's own elements
|
|
148
|
-
if (!current.closest("[data-inspector-ignore]")) {
|
|
149
|
-
parents.push(getElementReference(current));
|
|
150
|
-
count++;
|
|
151
|
-
}
|
|
152
|
-
current = current.parentElement;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return parents;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function collectChildren(element: HTMLElement): ElementReference[] {
|
|
159
|
-
const children: ElementReference[] = [];
|
|
160
|
-
const childElements = Array.from(element.children) as HTMLElement[];
|
|
161
|
-
|
|
162
|
-
for (let i = 0; i < Math.min(3, childElements.length); i++) {
|
|
163
|
-
children.push(getElementReference(childElements[i]));
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return children;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function getElementsAtPoint(x: number, y: number): HTMLElement[] {
|
|
170
|
-
const elements: HTMLElement[] = [];
|
|
171
|
-
let currentElement = document.elementFromPoint(x, y) as HTMLElement;
|
|
172
|
-
|
|
173
|
-
if (!currentElement) return elements;
|
|
174
|
-
|
|
175
|
-
// Skip inspector's own elements
|
|
176
|
-
if (currentElement.closest("[data-inspector-ignore]")) {
|
|
177
|
-
return elements;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Skip SVG elements - find the closest HTML parent
|
|
181
|
-
if (currentElement instanceof SVGElement) {
|
|
182
|
-
let parent = currentElement.parentElement;
|
|
183
|
-
while (parent && parent instanceof SVGElement) {
|
|
184
|
-
parent = parent.parentElement;
|
|
185
|
-
}
|
|
186
|
-
if (parent) {
|
|
187
|
-
currentElement = parent as HTMLElement;
|
|
188
|
-
} else {
|
|
189
|
-
return elements;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Start with the clicked element
|
|
194
|
-
elements.push(currentElement);
|
|
195
|
-
|
|
196
|
-
// Collect all meaningful direct children (not just at click point)
|
|
197
|
-
const collectMeaningfulChildren = (parent: HTMLElement, depth: number) => {
|
|
198
|
-
if (depth > 2) return; // Remove element count limit
|
|
199
|
-
|
|
200
|
-
const children = Array.from(parent.children);
|
|
201
|
-
|
|
202
|
-
console.log(`🔍 Checking children at depth ${depth}:`, {
|
|
203
|
-
parent: parent.tagName,
|
|
204
|
-
childrenCount: children.length,
|
|
205
|
-
currentStackLength: elements.length,
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// Collect ALL meaningful children, prioritizing those with data-dev-id
|
|
209
|
-
const meaningfulChildren: HTMLElement[] = [];
|
|
210
|
-
|
|
211
|
-
for (const child of children) {
|
|
212
|
-
// Skip SVG elements and non-HTML elements
|
|
213
|
-
if (!(child instanceof HTMLElement)) continue;
|
|
214
|
-
|
|
215
|
-
// Skip inspector's own elements
|
|
216
|
-
if (child.closest("[data-inspector-ignore]")) continue;
|
|
217
|
-
|
|
218
|
-
const rect = child.getBoundingClientRect();
|
|
219
|
-
const hasDevId = child.hasAttribute("data-dev-id");
|
|
220
|
-
const hasDimensions = rect.width > 0 && rect.height > 0;
|
|
221
|
-
const hasChildren = child.children.length > 0;
|
|
222
|
-
const hasText = child.textContent && child.textContent.trim().length > 0;
|
|
223
|
-
const isInteractive = [
|
|
224
|
-
"BUTTON",
|
|
225
|
-
"A",
|
|
226
|
-
"INPUT",
|
|
227
|
-
"IMG",
|
|
228
|
-
"VIDEO",
|
|
229
|
-
"SELECT",
|
|
230
|
-
"TEXTAREA",
|
|
231
|
-
].includes(child.tagName);
|
|
232
|
-
|
|
233
|
-
const isMeaningful =
|
|
234
|
-
hasDevId ||
|
|
235
|
-
(hasDimensions && (hasChildren || hasText || isInteractive));
|
|
236
|
-
|
|
237
|
-
console.log(` 📦 Child ${child.tagName}:`, {
|
|
238
|
-
isMeaningful,
|
|
239
|
-
hasDevId,
|
|
240
|
-
hasDimensions,
|
|
241
|
-
hasChildren,
|
|
242
|
-
hasText,
|
|
243
|
-
isInteractive,
|
|
244
|
-
rect: { width: rect.width, height: rect.height },
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
if (isMeaningful) {
|
|
248
|
-
meaningfulChildren.push(child as HTMLElement);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
console.log(` ✅ Found ${meaningfulChildren.length} meaningful children`);
|
|
253
|
-
|
|
254
|
-
// Add ALL meaningful children (prioritize data-dev-id first)
|
|
255
|
-
const childrenWithDevId = meaningfulChildren.filter((c) =>
|
|
256
|
-
c.hasAttribute("data-dev-id")
|
|
257
|
-
);
|
|
258
|
-
const childrenWithoutDevId = meaningfulChildren.filter(
|
|
259
|
-
(c) => !c.hasAttribute("data-dev-id")
|
|
260
|
-
);
|
|
261
|
-
const sortedChildren = [...childrenWithDevId, ...childrenWithoutDevId];
|
|
262
|
-
|
|
263
|
-
for (const child of sortedChildren) {
|
|
264
|
-
console.log(` ➕ Adding to stack:`, child.tagName, child);
|
|
265
|
-
elements.push(child);
|
|
266
|
-
// Recursively check EACH child's children (to go deeper for all branches)
|
|
267
|
-
collectMeaningfulChildren(child, depth + 1);
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
collectMeaningfulChildren(currentElement, 1);
|
|
272
|
-
|
|
273
|
-
return elements;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
function getElementData(element: HTMLElement): SelectedElementData {
|
|
277
|
-
const isTextNode = element.textContent && element.children.length === 0;
|
|
278
|
-
const isImageNode = element.tagName === "IMG";
|
|
279
|
-
|
|
280
|
-
const component = getComponentInfo(element);
|
|
281
|
-
|
|
282
|
-
return {
|
|
283
|
-
id: component?.id || "",
|
|
284
|
-
tagName: element.tagName,
|
|
285
|
-
className: element.className,
|
|
286
|
-
component: component,
|
|
287
|
-
position: {
|
|
288
|
-
top: element.getBoundingClientRect().top,
|
|
289
|
-
left: element.getBoundingClientRect().left,
|
|
290
|
-
width: element.getBoundingClientRect().width,
|
|
291
|
-
height: element.getBoundingClientRect().height,
|
|
292
|
-
},
|
|
293
|
-
isTextNode: isTextNode ? true : false,
|
|
294
|
-
textContent: isTextNode ? element.textContent?.trim() : "",
|
|
295
|
-
isImageNode,
|
|
296
|
-
imageUrl: isImageNode ? (element as HTMLImageElement).src : "",
|
|
297
|
-
selector: generateSelector(element),
|
|
298
|
-
currentRoute: window.location.pathname,
|
|
299
|
-
parents: collectParents(element),
|
|
300
|
-
children: collectChildren(element),
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
export function App() {
|
|
304
|
-
const { setTheme, setLabels, labels } = useInspectorStore();
|
|
305
|
-
const [inspectMode, setInspectMode] = useState(false);
|
|
306
|
-
const highlighter = useRef<ElementHighlighter | null>(null);
|
|
307
|
-
useEffect(() => {
|
|
308
|
-
highlighter.current = new ElementHighlighter();
|
|
309
|
-
}, []);
|
|
310
|
-
const [isPaused, setIsPaused] = useState(false);
|
|
311
|
-
const [hoveredElement, setHoveredElement] = useState<HTMLElement | null>(
|
|
312
|
-
null
|
|
313
|
-
);
|
|
314
|
-
const [selectedElement, setSelectedElement] = useState<HTMLElement | null>(
|
|
315
|
-
null
|
|
316
|
-
);
|
|
317
|
-
const [selectedElementData, setSelectedElementData] =
|
|
318
|
-
useState<SelectedElementData | null>(null);
|
|
319
|
-
const [activeTab, setActiveTab] = useState<"text" | "image" | "style" | null>(
|
|
320
|
-
null
|
|
321
|
-
);
|
|
322
|
-
const [showTextEditor, setShowTextEditor] = useState(false);
|
|
323
|
-
const [showImageEditor, setShowImageEditor] = useState(false);
|
|
324
|
-
const [showStyleEditor, setShowStyleEditor] = useState(false);
|
|
325
|
-
const [badgeVisible, setBadgeVisible] = useState(false);
|
|
326
|
-
const [showChildBorders, setShowChildBorders] = useState(true);
|
|
327
|
-
const [elementStack, setElementStack] = useState<HTMLElement[]>([]);
|
|
328
|
-
|
|
329
|
-
const { sendToParent, listenToParent } = useMessageBridge();
|
|
330
|
-
|
|
331
|
-
// Refs for trackers
|
|
332
|
-
const errorTrackerRef = useRef<ErrorTracker | null>(null);
|
|
333
|
-
const urlTrackerRef = useRef<UrlTracker | null>(null);
|
|
334
|
-
|
|
335
|
-
// Determine which tabs to show
|
|
336
|
-
const availableTabs = useMemo(() => {
|
|
337
|
-
const tabs: ("text" | "image" | "style")[] = [];
|
|
338
|
-
if (showTextEditor) tabs.push("text");
|
|
339
|
-
if (showImageEditor) tabs.push("image");
|
|
340
|
-
if (showStyleEditor) tabs.push("style");
|
|
341
|
-
return tabs;
|
|
342
|
-
}, [showTextEditor, showImageEditor, showStyleEditor]);
|
|
343
|
-
|
|
344
|
-
// Auto-select first available tab
|
|
345
|
-
useEffect(() => {
|
|
346
|
-
if (availableTabs.length > 0 && !activeTab) {
|
|
347
|
-
setActiveTab(availableTabs[0]);
|
|
348
|
-
}
|
|
349
|
-
}, [availableTabs, activeTab]);
|
|
350
|
-
|
|
351
|
-
// Initialize error and URL tracking
|
|
352
|
-
useEffect(() => {
|
|
353
|
-
// Error tracker
|
|
354
|
-
errorTrackerRef.current = new ErrorTracker((errorData) => {
|
|
355
|
-
sendToParent("INSPECTOR_ERROR", errorData);
|
|
356
|
-
});
|
|
357
|
-
errorTrackerRef.current.start();
|
|
358
|
-
|
|
359
|
-
// URL tracker
|
|
360
|
-
urlTrackerRef.current = new UrlTracker((urlData) => {
|
|
361
|
-
sendToParent("URL_CHANGED", urlData);
|
|
362
|
-
});
|
|
363
|
-
urlTrackerRef.current.start();
|
|
364
|
-
|
|
365
|
-
return () => {
|
|
366
|
-
errorTrackerRef.current?.stop();
|
|
367
|
-
};
|
|
368
|
-
}, [sendToParent]);
|
|
369
|
-
|
|
370
|
-
// Listen for messages from parent
|
|
371
|
-
useEffect(() => {
|
|
372
|
-
return listenToParent((message) => {
|
|
373
|
-
switch (message.type) {
|
|
374
|
-
case "TOGGLE_INSPECTOR":
|
|
375
|
-
setInspectMode(message.active);
|
|
376
|
-
if (message.labels) {
|
|
377
|
-
setLabels(message.labels);
|
|
378
|
-
}
|
|
379
|
-
if (message.theme) {
|
|
380
|
-
setTheme(message.theme);
|
|
381
|
-
}
|
|
382
|
-
break;
|
|
383
|
-
|
|
384
|
-
case "SHOW_CONTENT_INPUT":
|
|
385
|
-
setShowTextEditor(message.show);
|
|
386
|
-
break;
|
|
387
|
-
|
|
388
|
-
case "SHOW_IMAGE_INPUT":
|
|
389
|
-
setShowImageEditor(message.show);
|
|
390
|
-
break;
|
|
391
|
-
|
|
392
|
-
case "SHOW_STYLE_EDITOR":
|
|
393
|
-
setShowStyleEditor(message.show);
|
|
394
|
-
break;
|
|
395
|
-
|
|
396
|
-
case "SET_BADGE_VISIBLE":
|
|
397
|
-
setBadgeVisible(message.visible);
|
|
398
|
-
if (message.badgeText) {
|
|
399
|
-
setLabels({ badgeText: message.badgeText });
|
|
400
|
-
}
|
|
401
|
-
break;
|
|
402
|
-
|
|
403
|
-
case "HIGHLIGHT_ELEMENT":
|
|
404
|
-
handleHighlightElement(message.identifier, message.options);
|
|
405
|
-
break;
|
|
406
|
-
|
|
407
|
-
case "GET_ELEMENT_BY_ID":
|
|
408
|
-
handleGetElementById(message.inspectorId);
|
|
409
|
-
break;
|
|
410
|
-
|
|
411
|
-
case "SET_SHOW_CHILD_BORDERS":
|
|
412
|
-
setShowChildBorders(message.show);
|
|
413
|
-
break;
|
|
414
|
-
}
|
|
415
|
-
});
|
|
416
|
-
}, [listenToParent]);
|
|
417
|
-
|
|
418
|
-
// Mouse move handler for hover
|
|
419
|
-
useEffect(() => {
|
|
420
|
-
if (!inspectMode || isPaused) return;
|
|
421
|
-
|
|
422
|
-
const handleMouseMove = (e: MouseEvent) => {
|
|
423
|
-
const target = e.target as HTMLElement;
|
|
424
|
-
|
|
425
|
-
// Ignore inspector's own elements
|
|
426
|
-
if (target.closest("[data-inspector-ignore]")) {
|
|
427
|
-
setHoveredElement(null);
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
setHoveredElement(target);
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
document.addEventListener("mousemove", handleMouseMove, true);
|
|
435
|
-
return () =>
|
|
436
|
-
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
437
|
-
}, [inspectMode, isPaused]);
|
|
438
|
-
|
|
439
|
-
// Click handler for element selection
|
|
440
|
-
useEffect(() => {
|
|
441
|
-
if (!inspectMode) return;
|
|
442
|
-
|
|
443
|
-
const handleClick = (e: MouseEvent) => {
|
|
444
|
-
let target = e.target as HTMLElement;
|
|
445
|
-
|
|
446
|
-
// Ignore inspector's own elements
|
|
447
|
-
if (target.closest && target.closest("[data-inspector-ignore]")) {
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// If target is SVG, find the closest HTML parent
|
|
452
|
-
if (target instanceof SVGElement) {
|
|
453
|
-
let parent = target.parentElement;
|
|
454
|
-
while (parent && parent instanceof SVGElement) {
|
|
455
|
-
parent = parent.parentElement;
|
|
456
|
-
}
|
|
457
|
-
if (parent) {
|
|
458
|
-
target = parent as HTMLElement;
|
|
459
|
-
} else {
|
|
460
|
-
return; // No HTML parent found
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// If already paused, unpause
|
|
465
|
-
if (isPaused) {
|
|
466
|
-
e.preventDefault();
|
|
467
|
-
e.stopPropagation();
|
|
468
|
-
unpauseInspection();
|
|
469
|
-
return;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
e.preventDefault();
|
|
473
|
-
e.stopPropagation();
|
|
474
|
-
|
|
475
|
-
// Get element data and pause inspection
|
|
476
|
-
const elementData = getElementData(target);
|
|
477
|
-
|
|
478
|
-
// Collect z-index stack
|
|
479
|
-
const stack = getElementsAtPoint(e.clientX, e.clientY);
|
|
480
|
-
console.log("Element stack:", stack.length, stack);
|
|
481
|
-
setElementStack(stack);
|
|
482
|
-
|
|
483
|
-
setSelectedElement(target);
|
|
484
|
-
setSelectedElementData(elementData);
|
|
485
|
-
pauseInspection();
|
|
486
|
-
|
|
487
|
-
// Send to parent
|
|
488
|
-
sendToParent("INSPECTOR_ELEMENT_SELECTED", elementData);
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
document.addEventListener("click", handleClick, true);
|
|
492
|
-
return () => document.removeEventListener("click", handleClick, true);
|
|
493
|
-
}, [inspectMode, isPaused, sendToParent]);
|
|
494
|
-
|
|
495
|
-
// Cursor style
|
|
496
|
-
useEffect(() => {
|
|
497
|
-
if (inspectMode && !isPaused) {
|
|
498
|
-
document.body.style.cursor = "crosshair";
|
|
499
|
-
} else {
|
|
500
|
-
document.body.style.cursor = "";
|
|
501
|
-
}
|
|
502
|
-
}, [inspectMode, isPaused]);
|
|
503
|
-
|
|
504
|
-
function pauseInspection() {
|
|
505
|
-
setIsPaused(true);
|
|
506
|
-
document.body.style.overflow = "hidden";
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
async function unpauseInspection() {
|
|
510
|
-
setIsPaused(false);
|
|
511
|
-
setSelectedElement(null);
|
|
512
|
-
setSelectedElementData(null);
|
|
513
|
-
setActiveTab(null);
|
|
514
|
-
setElementStack([]);
|
|
515
|
-
document.body.style.overflow = "";
|
|
516
|
-
|
|
517
|
-
// Clean up window variables
|
|
518
|
-
(window as any).__styleEditorHasChanges = false;
|
|
519
|
-
(window as any).__styleEditorSave = null;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
function handleElementStackSelect(element: HTMLElement) {
|
|
523
|
-
console.log("🔄 Element stack select:", element);
|
|
524
|
-
const elementData = getElementData(element);
|
|
525
|
-
console.log("📦 New element data:", elementData);
|
|
526
|
-
setSelectedElement(element);
|
|
527
|
-
setSelectedElementData(elementData);
|
|
528
|
-
|
|
529
|
-
// Send to parent
|
|
530
|
-
sendToParent("INSPECTOR_ELEMENT_SELECTED", elementData);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
function handleHighlightElement(identifier: string | any, options?: any) {
|
|
534
|
-
// Check if we need to navigate to a different route first
|
|
535
|
-
const targetRoute =
|
|
536
|
-
typeof identifier === "object"
|
|
537
|
-
? identifier.targetRoute
|
|
538
|
-
: options?.targetRoute;
|
|
539
|
-
|
|
540
|
-
if (targetRoute && targetRoute !== window.location.pathname) {
|
|
541
|
-
console.log(`Navigating to route: ${targetRoute}`);
|
|
542
|
-
window.history.pushState({}, "", targetRoute);
|
|
543
|
-
|
|
544
|
-
// Dispatch popstate event to trigger React Router
|
|
545
|
-
window.dispatchEvent(new PopStateEvent("popstate"));
|
|
546
|
-
|
|
547
|
-
// Wait for route change and DOM update
|
|
548
|
-
setTimeout(() => {
|
|
549
|
-
handleHighlightElement(identifier, options);
|
|
550
|
-
}, 300);
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
let element: Element | null = null;
|
|
555
|
-
|
|
556
|
-
// If identifier is an object with element data
|
|
557
|
-
if (typeof identifier === "object" && identifier !== null) {
|
|
558
|
-
// Try by inspector ID first
|
|
559
|
-
if (identifier.id) {
|
|
560
|
-
element = findElementById(identifier.id);
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// If not found or element is invisible, try by selector with smart matching
|
|
564
|
-
if (
|
|
565
|
-
(!element || element.getBoundingClientRect().width === 0) &&
|
|
566
|
-
identifier.selector
|
|
567
|
-
) {
|
|
568
|
-
// Try with provided selector first - find ALL matching elements
|
|
569
|
-
const candidates = document.querySelectorAll(identifier.selector);
|
|
570
|
-
|
|
571
|
-
if (candidates.length === 1) {
|
|
572
|
-
// Only one match, use it
|
|
573
|
-
element = candidates[0];
|
|
574
|
-
} else if (candidates.length > 1) {
|
|
575
|
-
// Multiple matches - filter by text content or position
|
|
576
|
-
for (const candidate of candidates) {
|
|
577
|
-
const rect = candidate.getBoundingClientRect();
|
|
578
|
-
|
|
579
|
-
// Skip invisible elements
|
|
580
|
-
if (rect.width === 0 || rect.height === 0) continue;
|
|
581
|
-
|
|
582
|
-
// Match by text content if available
|
|
583
|
-
if (
|
|
584
|
-
identifier.textContent &&
|
|
585
|
-
candidate.textContent?.trim() === identifier.textContent.trim()
|
|
586
|
-
) {
|
|
587
|
-
element = candidate;
|
|
588
|
-
break;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// Match by approximate position if available
|
|
592
|
-
if (identifier.position) {
|
|
593
|
-
const posMatch =
|
|
594
|
-
Math.abs(rect.top - identifier.position.top) < 5 &&
|
|
595
|
-
Math.abs(rect.left - identifier.position.left) < 5;
|
|
596
|
-
if (posMatch) {
|
|
597
|
-
element = candidate;
|
|
598
|
-
break;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// If still no match, use first visible element
|
|
604
|
-
if (!element) {
|
|
605
|
-
for (const candidate of candidates) {
|
|
606
|
-
const rect = candidate.getBoundingClientRect();
|
|
607
|
-
if (rect.width > 0 && rect.height > 0) {
|
|
608
|
-
element = candidate;
|
|
609
|
-
break;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// Fallback to class name if selector fails
|
|
616
|
-
if (!element && identifier.className) {
|
|
617
|
-
const classes = identifier.className.split(" ").filter(Boolean);
|
|
618
|
-
if (classes.length > 0) {
|
|
619
|
-
const elements = document.getElementsByClassName(classes[0]);
|
|
620
|
-
for (let i = 0; i < elements.length; i++) {
|
|
621
|
-
const rect = elements[i].getBoundingClientRect();
|
|
622
|
-
if (rect.width > 0 && rect.height > 0) {
|
|
623
|
-
element = elements[i];
|
|
624
|
-
break;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
} else if (typeof identifier === "string") {
|
|
631
|
-
// Fallback: identifier is a string (ID or selector)
|
|
632
|
-
// Try 1: Find by inspector ID
|
|
633
|
-
element = findElementById(identifier);
|
|
634
|
-
|
|
635
|
-
// Try 2: If not found, try as CSS selector
|
|
636
|
-
if (!element) {
|
|
637
|
-
try {
|
|
638
|
-
element = document.querySelector(identifier);
|
|
639
|
-
} catch (e) {
|
|
640
|
-
// Invalid selector, continue to next fallback
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// Try 3: If still not found, try finding by class name
|
|
645
|
-
if (!element && identifier.includes(".")) {
|
|
646
|
-
const className = identifier.split(".").filter(Boolean).join(" ");
|
|
647
|
-
const elements = document.getElementsByClassName(className);
|
|
648
|
-
if (elements.length > 0) {
|
|
649
|
-
element = elements[0];
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
console.log("🔍 Highlight Debug:", {
|
|
655
|
-
element,
|
|
656
|
-
identifier,
|
|
657
|
-
elementRect: element?.getBoundingClientRect(),
|
|
658
|
-
elementInViewport: element ? isElementInViewport(element) : false,
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
if (!element) {
|
|
662
|
-
console.warn("❌ Element not found for highlighting:", identifier);
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
// Check if element is visible, try parents if not
|
|
667
|
-
const rect = element.getBoundingClientRect();
|
|
668
|
-
if (rect.width === 0 || rect.height === 0) {
|
|
669
|
-
console.log("⚠️ Element is invisible, trying parents...");
|
|
670
|
-
|
|
671
|
-
// Try to find visible parent
|
|
672
|
-
if (typeof identifier === "object" && identifier.parents) {
|
|
673
|
-
for (const parent of identifier.parents) {
|
|
674
|
-
let parentElement = null;
|
|
675
|
-
|
|
676
|
-
// Try by ID first
|
|
677
|
-
if (parent.id) {
|
|
678
|
-
parentElement = findElementById(parent.id);
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// Try by selector
|
|
682
|
-
if (!parentElement && parent.selector) {
|
|
683
|
-
parentElement = document.querySelector(parent.selector);
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
if (parentElement) {
|
|
687
|
-
const parentRect = parentElement.getBoundingClientRect();
|
|
688
|
-
if (parentRect.width > 0 && parentRect.height > 0) {
|
|
689
|
-
console.log("✅ Found visible parent:", parent.tagName);
|
|
690
|
-
element = parentElement;
|
|
691
|
-
break;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
// Highlight element
|
|
699
|
-
if (highlighter.current && element instanceof HTMLElement) {
|
|
700
|
-
highlighter.current?.highlight(element, {
|
|
701
|
-
color: options?.color || "#4417db",
|
|
702
|
-
duration: options?.duration || 2000,
|
|
703
|
-
});
|
|
704
|
-
|
|
705
|
-
// Scroll into view
|
|
706
|
-
if (options?.scrollIntoView !== false) {
|
|
707
|
-
element.scrollIntoView({
|
|
708
|
-
behavior: "smooth",
|
|
709
|
-
block: "nearest",
|
|
710
|
-
inline: "nearest",
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
function handleGetElementById(inspectorId: string) {
|
|
717
|
-
const element = findElementById(inspectorId);
|
|
718
|
-
|
|
719
|
-
if (element && element instanceof HTMLElement) {
|
|
720
|
-
const elementData = getElementData(element);
|
|
721
|
-
sendToParent("ELEMENT_INFO_RESPONSE", elementData);
|
|
722
|
-
} else {
|
|
723
|
-
sendToParent("ELEMENT_INFO_RESPONSE", {
|
|
724
|
-
error: "Element not found",
|
|
725
|
-
inspectorId,
|
|
726
|
-
});
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
// Block scroll and pointer events when inspector is active
|
|
731
|
-
useEffect(() => {
|
|
732
|
-
if (isPaused) {
|
|
733
|
-
// Track if user is dragging
|
|
734
|
-
let isDragging = false;
|
|
735
|
-
|
|
736
|
-
const handlePointerDown = () => {
|
|
737
|
-
isDragging = true;
|
|
738
|
-
};
|
|
739
|
-
|
|
740
|
-
const handlePointerUp = () => {
|
|
741
|
-
isDragging = false;
|
|
742
|
-
};
|
|
743
|
-
|
|
744
|
-
// Listen to pointer events on inspector root to track dragging
|
|
745
|
-
const inspectorRoot = document.getElementById("inspector-canvas-root");
|
|
746
|
-
if (inspectorRoot) {
|
|
747
|
-
inspectorRoot.addEventListener("pointerdown", handlePointerDown);
|
|
748
|
-
inspectorRoot.addEventListener("pointerup", handlePointerUp);
|
|
749
|
-
document.addEventListener("pointerup", handlePointerUp); // Global pointer up
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
// Prevent scroll on body
|
|
753
|
-
const preventScroll = (e: WheelEvent | TouchEvent) => {
|
|
754
|
-
// Allow scroll inside inspector components
|
|
755
|
-
const target = e.target as HTMLElement;
|
|
756
|
-
if (target.closest("#inspector-canvas-root")) {
|
|
757
|
-
return;
|
|
758
|
-
}
|
|
759
|
-
e.preventDefault();
|
|
760
|
-
e.stopPropagation();
|
|
761
|
-
};
|
|
762
|
-
|
|
763
|
-
// Prevent all pointer events on body
|
|
764
|
-
const preventPointer = (e: PointerEvent | MouseEvent) => {
|
|
765
|
-
const target = e.target as HTMLElement;
|
|
766
|
-
|
|
767
|
-
// Allow events inside inspector
|
|
768
|
-
if (target.closest("#inspector-canvas-root")) {
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// Don't prevent if user is dragging
|
|
773
|
-
if (isDragging) {
|
|
774
|
-
return;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
// Don't prevent if mouse is leaving viewport
|
|
778
|
-
if (e.type === "mouseleave" || e.type === "mouseout") {
|
|
779
|
-
return;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
e.preventDefault();
|
|
783
|
-
e.stopPropagation();
|
|
784
|
-
};
|
|
785
|
-
|
|
786
|
-
// Add event listeners with capture phase to catch all events
|
|
787
|
-
document.addEventListener("wheel", preventScroll, {
|
|
788
|
-
passive: false,
|
|
789
|
-
capture: true,
|
|
790
|
-
});
|
|
791
|
-
document.addEventListener("touchmove", preventScroll, {
|
|
792
|
-
passive: false,
|
|
793
|
-
capture: true,
|
|
794
|
-
});
|
|
795
|
-
document.addEventListener("pointerdown", preventPointer, {
|
|
796
|
-
capture: true,
|
|
797
|
-
});
|
|
798
|
-
document.addEventListener("pointerup", preventPointer, { capture: true });
|
|
799
|
-
document.addEventListener("pointermove", preventPointer, {
|
|
800
|
-
capture: true,
|
|
801
|
-
});
|
|
802
|
-
document.addEventListener("mousedown", preventPointer, { capture: true });
|
|
803
|
-
document.addEventListener("mouseup", preventPointer, { capture: true });
|
|
804
|
-
document.addEventListener("mousemove", preventPointer, { capture: true });
|
|
805
|
-
document.addEventListener("click", preventPointer, { capture: true });
|
|
806
|
-
|
|
807
|
-
// Prevent keyboard events
|
|
808
|
-
const preventKeyboard = (e: KeyboardEvent) => {
|
|
809
|
-
const target = e.target as HTMLElement;
|
|
810
|
-
if (target.closest("#inspector-canvas-root")) {
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
e.preventDefault();
|
|
814
|
-
e.stopPropagation();
|
|
815
|
-
};
|
|
816
|
-
document.addEventListener("keydown", preventKeyboard, { capture: true });
|
|
817
|
-
document.addEventListener("keyup", preventKeyboard, { capture: true });
|
|
818
|
-
|
|
819
|
-
return () => {
|
|
820
|
-
// Cleanup drag tracking
|
|
821
|
-
const inspectorRoot = document.getElementById("inspector-canvas-root");
|
|
822
|
-
if (inspectorRoot) {
|
|
823
|
-
inspectorRoot.removeEventListener("pointerdown", handlePointerDown);
|
|
824
|
-
inspectorRoot.removeEventListener("pointerup", handlePointerUp);
|
|
825
|
-
}
|
|
826
|
-
document.removeEventListener("pointerup", handlePointerUp);
|
|
827
|
-
|
|
828
|
-
document.removeEventListener("wheel", preventScroll, {
|
|
829
|
-
capture: true,
|
|
830
|
-
} as any);
|
|
831
|
-
document.removeEventListener("touchmove", preventScroll, {
|
|
832
|
-
capture: true,
|
|
833
|
-
} as any);
|
|
834
|
-
document.removeEventListener("pointerdown", preventPointer, {
|
|
835
|
-
capture: true,
|
|
836
|
-
});
|
|
837
|
-
document.removeEventListener("pointerup", preventPointer, {
|
|
838
|
-
capture: true,
|
|
839
|
-
});
|
|
840
|
-
document.removeEventListener("pointermove", preventPointer, {
|
|
841
|
-
capture: true,
|
|
842
|
-
});
|
|
843
|
-
document.removeEventListener("mousedown", preventPointer, {
|
|
844
|
-
capture: true,
|
|
845
|
-
});
|
|
846
|
-
document.removeEventListener("mouseup", preventPointer, {
|
|
847
|
-
capture: true,
|
|
848
|
-
});
|
|
849
|
-
document.removeEventListener("mousemove", preventPointer, {
|
|
850
|
-
capture: true,
|
|
851
|
-
});
|
|
852
|
-
document.removeEventListener("click", preventPointer, {
|
|
853
|
-
capture: true,
|
|
854
|
-
});
|
|
855
|
-
document.removeEventListener("keydown", preventKeyboard, {
|
|
856
|
-
capture: true,
|
|
857
|
-
});
|
|
858
|
-
document.removeEventListener("keyup", preventKeyboard, {
|
|
859
|
-
capture: true,
|
|
860
|
-
});
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
}, [isPaused]);
|
|
864
|
-
|
|
865
|
-
return (
|
|
866
|
-
<div
|
|
867
|
-
id="inspector-canvas-root"
|
|
868
|
-
data-inspector-ignore
|
|
869
|
-
className={isPaused ? "inspector-active" : ""}
|
|
870
|
-
>
|
|
871
|
-
{/* Backdrop to block all interactions (but not close inspector) */}
|
|
872
|
-
{isPaused && (
|
|
873
|
-
<div
|
|
874
|
-
className="inspector-backdrop"
|
|
875
|
-
onClick={(e) => {
|
|
876
|
-
// Prevent backdrop clicks from closing inspector
|
|
877
|
-
e.preventDefault();
|
|
878
|
-
e.stopPropagation();
|
|
879
|
-
}}
|
|
880
|
-
/>
|
|
881
|
-
)}
|
|
882
|
-
|
|
883
|
-
<Overlay
|
|
884
|
-
element={inspectMode && !isPaused ? hoveredElement : null}
|
|
885
|
-
selectedElement={isPaused ? selectedElement : null}
|
|
886
|
-
showChildBorders={showChildBorders}
|
|
887
|
-
/>
|
|
888
|
-
{isPaused && selectedElement && selectedElementData && (
|
|
889
|
-
<ControlBox
|
|
890
|
-
element={selectedElement}
|
|
891
|
-
elementData={selectedElementData}
|
|
892
|
-
activeTab={activeTab}
|
|
893
|
-
availableTabs={availableTabs}
|
|
894
|
-
onTabChange={setActiveTab}
|
|
895
|
-
onClose={unpauseInspection}
|
|
896
|
-
onPromptSubmit={(prompt) => {
|
|
897
|
-
sendToParent("INSPECTOR_PROMPT_SUBMITTED", {
|
|
898
|
-
prompt,
|
|
899
|
-
element: selectedElementData,
|
|
900
|
-
});
|
|
901
|
-
setInspectMode(false);
|
|
902
|
-
unpauseInspection();
|
|
903
|
-
}}
|
|
904
|
-
elementStack={elementStack}
|
|
905
|
-
onElementSelect={handleElementStackSelect}
|
|
906
|
-
labels={labels}
|
|
907
|
-
/>
|
|
908
|
-
)}
|
|
909
|
-
<Badge visible={badgeVisible} />
|
|
910
|
-
</div>
|
|
911
|
-
);
|
|
912
|
-
}
|