@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.
Files changed (204) hide show
  1. package/README.md +111 -0
  2. package/dist/App.d.ts.map +1 -0
  3. package/dist/__tests__/App.test.d.ts.map +1 -0
  4. package/dist/components/Badge.d.ts.map +1 -0
  5. package/dist/components/ControlBox/ContentArea.d.ts.map +1 -0
  6. package/dist/components/ControlBox/PromptInput.d.ts.map +1 -0
  7. package/dist/components/ControlBox/index.d.ts.map +1 -0
  8. package/dist/components/ImageEditor/UploadBox.d.ts.map +1 -0
  9. package/dist/components/ImageEditor/index.d.ts.map +1 -0
  10. package/dist/components/Overlay.d.ts.map +1 -0
  11. package/dist/components/StyleEditor/BorderSection.d.ts.map +1 -0
  12. package/dist/components/StyleEditor/ColorPicker.d.ts.map +1 -0
  13. package/dist/components/StyleEditor/DisplaySection.d.ts.map +1 -0
  14. package/dist/components/StyleEditor/ImageSection.d.ts.map +1 -0
  15. package/dist/components/StyleEditor/LayoutSection.d.ts.map +1 -0
  16. package/dist/components/StyleEditor/NumberInput.d.ts.map +1 -0
  17. package/dist/components/StyleEditor/SliderInput.d.ts.map +1 -0
  18. package/dist/components/StyleEditor/SpacingSection.d.ts.map +1 -0
  19. package/dist/components/StyleEditor/TextSection.d.ts.map +1 -0
  20. package/dist/components/StyleEditor/index.d.ts.map +1 -0
  21. package/dist/components/TextEditor/index.d.ts.map +1 -0
  22. package/dist/components/ui/CustomCollapsible.d.ts.map +1 -0
  23. package/dist/components/ui/button.d.ts.map +1 -0
  24. package/dist/components/ui/color-picker.d.ts.map +1 -0
  25. package/dist/components/ui/input.d.ts.map +1 -0
  26. package/dist/components/ui/popover.d.ts.map +1 -0
  27. package/dist/components/ui/select.d.ts.map +1 -0
  28. package/dist/components/ui/slider.d.ts.map +1 -0
  29. package/dist/components/ui/textarea.d.ts.map +1 -0
  30. package/dist/components/ui/tooltip.d.ts.map +1 -0
  31. package/dist/core/highlighter.d.ts.map +1 -0
  32. package/dist/hooks/useMessageBridge.d.ts.map +1 -0
  33. package/dist/hooks/useStylePreview.d.ts.map +1 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/lib/utils.d.ts.map +1 -0
  36. package/dist/plugin.d.ts.map +1 -0
  37. package/dist/store/useInspectorStore.d.ts.map +1 -0
  38. package/dist/styles.d.ts.map +1 -0
  39. package/dist/utils/colorUtils.d.ts.map +1 -0
  40. package/dist/utils/elementNames.d.ts.map +1 -0
  41. package/dist/utils/elementUtils.d.ts.map +1 -0
  42. package/dist/utils/errorTracker.d.ts.map +1 -0
  43. package/dist/utils/inputStyles.d.ts.map +1 -0
  44. package/dist/utils/styleUtils.d.ts.map +1 -0
  45. package/dist/utils/tailwindMapper.d.ts.map +1 -0
  46. package/dist/utils/urlTracker.d.ts.map +1 -0
  47. package/package.json +15 -10
  48. package/dist/packages/inspector/src/App.d.ts.map +0 -1
  49. package/dist/packages/inspector/src/__tests__/App.test.d.ts.map +0 -1
  50. package/dist/packages/inspector/src/components/Badge.d.ts.map +0 -1
  51. package/dist/packages/inspector/src/components/ControlBox/ContentArea.d.ts.map +0 -1
  52. package/dist/packages/inspector/src/components/ControlBox/PromptInput.d.ts.map +0 -1
  53. package/dist/packages/inspector/src/components/ControlBox/index.d.ts.map +0 -1
  54. package/dist/packages/inspector/src/components/ImageEditor/UploadBox.d.ts.map +0 -1
  55. package/dist/packages/inspector/src/components/ImageEditor/index.d.ts.map +0 -1
  56. package/dist/packages/inspector/src/components/Overlay.d.ts.map +0 -1
  57. package/dist/packages/inspector/src/components/StyleEditor/BorderSection.d.ts.map +0 -1
  58. package/dist/packages/inspector/src/components/StyleEditor/ColorPicker.d.ts.map +0 -1
  59. package/dist/packages/inspector/src/components/StyleEditor/DisplaySection.d.ts.map +0 -1
  60. package/dist/packages/inspector/src/components/StyleEditor/ImageSection.d.ts.map +0 -1
  61. package/dist/packages/inspector/src/components/StyleEditor/LayoutSection.d.ts.map +0 -1
  62. package/dist/packages/inspector/src/components/StyleEditor/NumberInput.d.ts.map +0 -1
  63. package/dist/packages/inspector/src/components/StyleEditor/SliderInput.d.ts.map +0 -1
  64. package/dist/packages/inspector/src/components/StyleEditor/SpacingSection.d.ts.map +0 -1
  65. package/dist/packages/inspector/src/components/StyleEditor/TextSection.d.ts.map +0 -1
  66. package/dist/packages/inspector/src/components/StyleEditor/index.d.ts.map +0 -1
  67. package/dist/packages/inspector/src/components/TextEditor/index.d.ts.map +0 -1
  68. package/dist/packages/inspector/src/components/ui/CustomCollapsible.d.ts.map +0 -1
  69. package/dist/packages/inspector/src/components/ui/button.d.ts.map +0 -1
  70. package/dist/packages/inspector/src/components/ui/color-picker.d.ts.map +0 -1
  71. package/dist/packages/inspector/src/components/ui/input.d.ts.map +0 -1
  72. package/dist/packages/inspector/src/components/ui/popover.d.ts.map +0 -1
  73. package/dist/packages/inspector/src/components/ui/select.d.ts.map +0 -1
  74. package/dist/packages/inspector/src/components/ui/slider.d.ts.map +0 -1
  75. package/dist/packages/inspector/src/components/ui/textarea.d.ts.map +0 -1
  76. package/dist/packages/inspector/src/components/ui/tooltip.d.ts.map +0 -1
  77. package/dist/packages/inspector/src/core/highlighter.d.ts.map +0 -1
  78. package/dist/packages/inspector/src/hooks/useMessageBridge.d.ts.map +0 -1
  79. package/dist/packages/inspector/src/hooks/useStylePreview.d.ts.map +0 -1
  80. package/dist/packages/inspector/src/index.d.ts.map +0 -1
  81. package/dist/packages/inspector/src/lib/utils.d.ts.map +0 -1
  82. package/dist/packages/inspector/src/plugin.d.ts.map +0 -1
  83. package/dist/packages/inspector/src/store/useInspectorStore.d.ts.map +0 -1
  84. package/dist/packages/inspector/src/styles.d.ts.map +0 -1
  85. package/dist/packages/inspector/src/utils/colorUtils.d.ts.map +0 -1
  86. package/dist/packages/inspector/src/utils/elementNames.d.ts.map +0 -1
  87. package/dist/packages/inspector/src/utils/elementUtils.d.ts.map +0 -1
  88. package/dist/packages/inspector/src/utils/errorTracker.d.ts.map +0 -1
  89. package/dist/packages/inspector/src/utils/inputStyles.d.ts.map +0 -1
  90. package/dist/packages/inspector/src/utils/styleUtils.d.ts.map +0 -1
  91. package/dist/packages/inspector/src/utils/tailwindMapper.d.ts.map +0 -1
  92. package/dist/packages/inspector/src/utils/urlTracker.d.ts.map +0 -1
  93. package/dist/packages/inspector/tsconfig.tsbuildinfo +0 -1
  94. package/src/App.tsx +0 -912
  95. package/src/__tests__/App.test.tsx +0 -373
  96. package/src/assets/fonts/Satoshi-Variable.woff +0 -0
  97. package/src/assets/fonts/Satoshi-Variable.woff2 +0 -0
  98. package/src/components/Badge.tsx +0 -118
  99. package/src/components/ControlBox/ContentArea.tsx +0 -13
  100. package/src/components/ControlBox/PromptInput.module.css +0 -66
  101. package/src/components/ControlBox/PromptInput.tsx +0 -104
  102. package/src/components/ControlBox/index.module.css +0 -81
  103. package/src/components/ControlBox/index.tsx +0 -409
  104. package/src/components/ImageEditor/UploadBox.module.css +0 -69
  105. package/src/components/ImageEditor/UploadBox.tsx +0 -113
  106. package/src/components/ImageEditor/index.module.css +0 -11
  107. package/src/components/ImageEditor/index.tsx +0 -84
  108. package/src/components/Overlay.tsx +0 -157
  109. package/src/components/StyleEditor/BorderSection.tsx +0 -147
  110. package/src/components/StyleEditor/ColorPicker.tsx +0 -182
  111. package/src/components/StyleEditor/DisplaySection.tsx +0 -349
  112. package/src/components/StyleEditor/ImageSection.tsx +0 -105
  113. package/src/components/StyleEditor/LayoutSection.tsx +0 -63
  114. package/src/components/StyleEditor/NumberInput.tsx +0 -138
  115. package/src/components/StyleEditor/SliderInput.tsx +0 -121
  116. package/src/components/StyleEditor/SpacingSection.tsx +0 -365
  117. package/src/components/StyleEditor/TextSection.tsx +0 -381
  118. package/src/components/StyleEditor/index.module.css +0 -133
  119. package/src/components/StyleEditor/index.tsx +0 -612
  120. package/src/components/StyleEditor/shared.module.css +0 -193
  121. package/src/components/TextEditor/index.module.css +0 -31
  122. package/src/components/TextEditor/index.tsx +0 -166
  123. package/src/components/ui/CustomCollapsible.tsx +0 -159
  124. package/src/components/ui/button.module.css +0 -141
  125. package/src/components/ui/button.tsx +0 -73
  126. package/src/components/ui/color-picker.module.css +0 -112
  127. package/src/components/ui/color-picker.tsx +0 -146
  128. package/src/components/ui/input.module.css +0 -49
  129. package/src/components/ui/input.tsx +0 -34
  130. package/src/components/ui/popover.module.css +0 -42
  131. package/src/components/ui/popover.tsx +0 -59
  132. package/src/components/ui/select.module.css +0 -160
  133. package/src/components/ui/select.tsx +0 -216
  134. package/src/components/ui/slider.module.css +0 -75
  135. package/src/components/ui/slider.tsx +0 -60
  136. package/src/components/ui/textarea.module.css +0 -30
  137. package/src/components/ui/textarea.tsx +0 -23
  138. package/src/components/ui/tooltip.module.css +0 -11
  139. package/src/components/ui/tooltip.tsx +0 -37
  140. package/src/core/highlighter.ts +0 -197
  141. package/src/hooks/useMessageBridge.ts +0 -49
  142. package/src/hooks/useStylePreview.ts +0 -332
  143. package/src/index.ts +0 -20
  144. package/src/lib/utils.ts +0 -5
  145. package/src/plugin.ts +0 -11
  146. package/src/store/useInspectorStore.ts +0 -235
  147. package/src/styles/fonts.css +0 -15
  148. package/src/styles/global.css +0 -138
  149. package/src/styles/variables.css +0 -151
  150. package/src/styles.ts +0 -5
  151. package/src/utils/colorUtils.ts +0 -133
  152. package/src/utils/elementNames.ts +0 -103
  153. package/src/utils/elementUtils.ts +0 -90
  154. package/src/utils/errorTracker.ts +0 -186
  155. package/src/utils/inputStyles.ts +0 -30
  156. package/src/utils/styleUtils.ts +0 -226
  157. package/src/utils/tailwindMapper.ts +0 -554
  158. package/src/utils/urlTracker.ts +0 -75
  159. package/src/vite-env.d.ts +0 -7
  160. /package/dist/{packages/inspector/src/App.d.ts → App.d.ts} +0 -0
  161. /package/dist/{packages/inspector/src/__tests__ → __tests__}/App.test.d.ts +0 -0
  162. /package/dist/{packages/inspector/src/components → components}/Badge.d.ts +0 -0
  163. /package/dist/{packages/inspector/src/components → components}/ControlBox/ContentArea.d.ts +0 -0
  164. /package/dist/{packages/inspector/src/components → components}/ControlBox/PromptInput.d.ts +0 -0
  165. /package/dist/{packages/inspector/src/components → components}/ControlBox/index.d.ts +0 -0
  166. /package/dist/{packages/inspector/src/components → components}/ImageEditor/UploadBox.d.ts +0 -0
  167. /package/dist/{packages/inspector/src/components → components}/ImageEditor/index.d.ts +0 -0
  168. /package/dist/{packages/inspector/src/components → components}/Overlay.d.ts +0 -0
  169. /package/dist/{packages/inspector/src/components → components}/StyleEditor/BorderSection.d.ts +0 -0
  170. /package/dist/{packages/inspector/src/components → components}/StyleEditor/ColorPicker.d.ts +0 -0
  171. /package/dist/{packages/inspector/src/components → components}/StyleEditor/DisplaySection.d.ts +0 -0
  172. /package/dist/{packages/inspector/src/components → components}/StyleEditor/ImageSection.d.ts +0 -0
  173. /package/dist/{packages/inspector/src/components → components}/StyleEditor/LayoutSection.d.ts +0 -0
  174. /package/dist/{packages/inspector/src/components → components}/StyleEditor/NumberInput.d.ts +0 -0
  175. /package/dist/{packages/inspector/src/components → components}/StyleEditor/SliderInput.d.ts +0 -0
  176. /package/dist/{packages/inspector/src/components → components}/StyleEditor/SpacingSection.d.ts +0 -0
  177. /package/dist/{packages/inspector/src/components → components}/StyleEditor/TextSection.d.ts +0 -0
  178. /package/dist/{packages/inspector/src/components → components}/StyleEditor/index.d.ts +0 -0
  179. /package/dist/{packages/inspector/src/components → components}/TextEditor/index.d.ts +0 -0
  180. /package/dist/{packages/inspector/src/components → components}/ui/CustomCollapsible.d.ts +0 -0
  181. /package/dist/{packages/inspector/src/components → components}/ui/button.d.ts +0 -0
  182. /package/dist/{packages/inspector/src/components → components}/ui/color-picker.d.ts +0 -0
  183. /package/dist/{packages/inspector/src/components → components}/ui/input.d.ts +0 -0
  184. /package/dist/{packages/inspector/src/components → components}/ui/popover.d.ts +0 -0
  185. /package/dist/{packages/inspector/src/components → components}/ui/select.d.ts +0 -0
  186. /package/dist/{packages/inspector/src/components → components}/ui/slider.d.ts +0 -0
  187. /package/dist/{packages/inspector/src/components → components}/ui/textarea.d.ts +0 -0
  188. /package/dist/{packages/inspector/src/components → components}/ui/tooltip.d.ts +0 -0
  189. /package/dist/{packages/inspector/src/core → core}/highlighter.d.ts +0 -0
  190. /package/dist/{packages/inspector/src/hooks → hooks}/useMessageBridge.d.ts +0 -0
  191. /package/dist/{packages/inspector/src/hooks → hooks}/useStylePreview.d.ts +0 -0
  192. /package/dist/{packages/inspector/src/index.d.ts → index.d.ts} +0 -0
  193. /package/dist/{packages/inspector/src/lib → lib}/utils.d.ts +0 -0
  194. /package/dist/{packages/inspector/src/plugin.d.ts → plugin.d.ts} +0 -0
  195. /package/dist/{packages/inspector/src/store → store}/useInspectorStore.d.ts +0 -0
  196. /package/dist/{packages/inspector/src/styles.d.ts → styles.d.ts} +0 -0
  197. /package/dist/{packages/inspector/src/utils → utils}/colorUtils.d.ts +0 -0
  198. /package/dist/{packages/inspector/src/utils → utils}/elementNames.d.ts +0 -0
  199. /package/dist/{packages/inspector/src/utils → utils}/elementUtils.d.ts +0 -0
  200. /package/dist/{packages/inspector/src/utils → utils}/errorTracker.d.ts +0 -0
  201. /package/dist/{packages/inspector/src/utils → utils}/inputStyles.d.ts +0 -0
  202. /package/dist/{packages/inspector/src/utils → utils}/styleUtils.d.ts +0 -0
  203. /package/dist/{packages/inspector/src/utils → utils}/tailwindMapper.d.ts +0 -0
  204. /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
- }