@visual-agentic-dev/react-devtools 1.1.4

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/dist/index.js ADDED
@@ -0,0 +1,380 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ DevToolsProvider: () => DevToolsProvider,
24
+ Highlighter: () => Highlighter,
25
+ SelectionBox: () => SelectionBox,
26
+ createMessageHandler: () => createMessageHandler,
27
+ findSourceElement: () => findSourceElement,
28
+ getSourceFromElement: () => getSourceFromElement,
29
+ notifyReady: () => notifyReady,
30
+ parseSourceAttr: () => parseSourceAttr,
31
+ sendToExtension: () => sendToExtension,
32
+ useDevTools: () => useDevTools
33
+ });
34
+ module.exports = __toCommonJS(src_exports);
35
+
36
+ // src/components/DevToolsProvider.tsx
37
+ var import_react3 = require("react");
38
+
39
+ // src/overlay/Highlighter.tsx
40
+ var import_react = require("react");
41
+ var import_jsx_runtime = require("react/jsx-runtime");
42
+ var Highlighter = ({
43
+ element,
44
+ color = "rgba(66, 153, 225, 0.3)"
45
+ }) => {
46
+ const [rect, setRect] = (0, import_react.useState)(null);
47
+ (0, import_react.useEffect)(() => {
48
+ const update = () => setRect(element.getBoundingClientRect());
49
+ update();
50
+ const observer = new ResizeObserver(update);
51
+ observer.observe(element);
52
+ window.addEventListener("scroll", update, true);
53
+ window.addEventListener("resize", update);
54
+ return () => {
55
+ observer.disconnect();
56
+ window.removeEventListener("scroll", update, true);
57
+ window.removeEventListener("resize", update);
58
+ };
59
+ }, [element]);
60
+ if (!rect) return null;
61
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
62
+ "div",
63
+ {
64
+ style: {
65
+ position: "fixed",
66
+ top: rect.top,
67
+ left: rect.left,
68
+ width: rect.width,
69
+ height: rect.height,
70
+ backgroundColor: color,
71
+ border: "2px solid #4299e1",
72
+ pointerEvents: "none",
73
+ zIndex: 999999,
74
+ transition: "all 0.1s ease",
75
+ boxSizing: "border-box"
76
+ },
77
+ "data-vdev-overlay": "highlighter"
78
+ }
79
+ );
80
+ };
81
+
82
+ // src/overlay/SelectionBox.tsx
83
+ var import_react2 = require("react");
84
+
85
+ // src/utils/sourceLocator.ts
86
+ function getReactFiber(element) {
87
+ const key = Object.keys(element).find(
88
+ (k) => k.startsWith("__reactFiber$") || k.startsWith("__reactInternalInstance$")
89
+ );
90
+ return key ? element[key] : null;
91
+ }
92
+ function findFiberWithSource(fiber) {
93
+ let current = fiber;
94
+ while (current) {
95
+ if (current._debugSource) {
96
+ return current;
97
+ }
98
+ current = current.return;
99
+ }
100
+ return null;
101
+ }
102
+ function getSourceFromFiber(element) {
103
+ const fiber = getReactFiber(element);
104
+ if (!fiber) return null;
105
+ const fiberWithSource = findFiberWithSource(fiber);
106
+ if (fiberWithSource?._debugSource) {
107
+ const { fileName, lineNumber, columnNumber } = fiberWithSource._debugSource;
108
+ return {
109
+ fileName,
110
+ lineNumber,
111
+ columnNumber: columnNumber || 1
112
+ };
113
+ }
114
+ return null;
115
+ }
116
+ function parseSourceAttr(attrValue) {
117
+ if (!attrValue) return null;
118
+ try {
119
+ const parsed = JSON.parse(attrValue);
120
+ if (typeof parsed.fileName === "string" && typeof parsed.lineNumber === "number" && typeof parsed.columnNumber === "number") {
121
+ return parsed;
122
+ }
123
+ } catch {
124
+ }
125
+ return null;
126
+ }
127
+ function findSourceElement(target, prefix = "vdev") {
128
+ let current = target;
129
+ while (current && current !== document.body) {
130
+ if (getSourceFromFiber(current)) {
131
+ return current;
132
+ }
133
+ current = current.parentElement;
134
+ }
135
+ return target.closest(`[data-${prefix}-file], [data-${prefix}-source]`);
136
+ }
137
+ function getSourceFromElement(element, prefix = "vdev") {
138
+ const fiberSource = getSourceFromFiber(element);
139
+ if (fiberSource) {
140
+ return fiberSource;
141
+ }
142
+ const fileName = element.getAttribute(`data-${prefix}-file`);
143
+ const lineStr = element.getAttribute(`data-${prefix}-line`);
144
+ const colStr = element.getAttribute(`data-${prefix}-col`);
145
+ if (fileName && lineStr) {
146
+ return {
147
+ fileName,
148
+ lineNumber: parseInt(lineStr, 10),
149
+ columnNumber: colStr ? parseInt(colStr, 10) : 1
150
+ };
151
+ }
152
+ const attrValue = element.getAttribute(`data-${prefix}-source`);
153
+ return parseSourceAttr(attrValue);
154
+ }
155
+
156
+ // src/overlay/SelectionBox.tsx
157
+ var import_jsx_runtime2 = require("react/jsx-runtime");
158
+ var SelectionBox = ({ element, prefix = "vdev" }) => {
159
+ const [rect, setRect] = (0, import_react2.useState)(null);
160
+ const [source, setSource] = (0, import_react2.useState)(null);
161
+ (0, import_react2.useEffect)(() => {
162
+ const update = () => setRect(element.getBoundingClientRect());
163
+ update();
164
+ setSource(getSourceFromElement(element, prefix));
165
+ const observer = new ResizeObserver(update);
166
+ observer.observe(element);
167
+ window.addEventListener("scroll", update, true);
168
+ window.addEventListener("resize", update);
169
+ return () => {
170
+ observer.disconnect();
171
+ window.removeEventListener("scroll", update, true);
172
+ window.removeEventListener("resize", update);
173
+ };
174
+ }, [element, prefix]);
175
+ if (!rect) return null;
176
+ const fileName = source?.fileName.split("/").pop() || "unknown";
177
+ const lineInfo = source ? `${fileName}:${source.lineNumber}` : "";
178
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
179
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
180
+ "div",
181
+ {
182
+ style: {
183
+ position: "fixed",
184
+ top: rect.top,
185
+ left: rect.left,
186
+ width: rect.width,
187
+ height: rect.height,
188
+ border: "2px solid #6366f1",
189
+ backgroundColor: "rgba(99, 102, 241, 0.1)",
190
+ pointerEvents: "none",
191
+ zIndex: 999999,
192
+ boxSizing: "border-box"
193
+ },
194
+ "data-vdev-overlay": "selection"
195
+ }
196
+ ),
197
+ lineInfo && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
198
+ "div",
199
+ {
200
+ style: {
201
+ position: "fixed",
202
+ top: Math.max(0, rect.top - 24),
203
+ left: rect.left,
204
+ backgroundColor: "#6366f1",
205
+ color: "white",
206
+ fontSize: "11px",
207
+ fontFamily: "monospace",
208
+ padding: "2px 6px",
209
+ borderRadius: "3px",
210
+ pointerEvents: "none",
211
+ zIndex: 999999,
212
+ whiteSpace: "nowrap"
213
+ },
214
+ "data-vdev-overlay": "label",
215
+ children: lineInfo
216
+ }
217
+ )
218
+ ] });
219
+ };
220
+
221
+ // src/utils/messaging.ts
222
+ var MESSAGE_SOURCE = "vdev-react-sdk";
223
+ function sendToExtension(message) {
224
+ window.postMessage(
225
+ { ...message, source: MESSAGE_SOURCE },
226
+ "*"
227
+ );
228
+ }
229
+ function notifyReady() {
230
+ sendToExtension({ type: "VDEV_SDK_READY" });
231
+ }
232
+ function createMessageHandler(handler) {
233
+ return (event) => {
234
+ if (event.source !== window) return;
235
+ if (event.data?.source === MESSAGE_SOURCE) return;
236
+ if (event.data?.type?.startsWith("VDEV_")) {
237
+ handler(event.data);
238
+ }
239
+ };
240
+ }
241
+
242
+ // src/components/DevToolsProvider.tsx
243
+ var import_jsx_runtime3 = require("react/jsx-runtime");
244
+ var DevToolsContext = (0, import_react3.createContext)(null);
245
+ var useDevTools = () => {
246
+ const context = (0, import_react3.useContext)(DevToolsContext);
247
+ if (!context) {
248
+ throw new Error("useDevTools must be used within a DevToolsProvider");
249
+ }
250
+ return context;
251
+ };
252
+ var DevToolsProvider = ({
253
+ children,
254
+ enabled = true,
255
+ prefix = "vdev"
256
+ }) => {
257
+ const [isInspecting, setInspecting] = (0, import_react3.useState)(false);
258
+ const [hoveredElement, setHoveredElement] = (0, import_react3.useState)(null);
259
+ const [selectedElement, setSelectedElement] = (0, import_react3.useState)(null);
260
+ const [selectedSource, setSelectedSource] = (0, import_react3.useState)(null);
261
+ const clearSelection = (0, import_react3.useCallback)(() => {
262
+ setSelectedElement(null);
263
+ setSelectedSource(null);
264
+ }, []);
265
+ (0, import_react3.useEffect)(() => {
266
+ if (!enabled) return;
267
+ const handler = createMessageHandler((message) => {
268
+ console.log("[DevTools] Received message:", message);
269
+ if (message.type === "VDEV_START_INSPECT") {
270
+ console.log("[DevTools] Starting inspection");
271
+ setInspecting(true);
272
+ clearSelection();
273
+ } else if (message.type === "VDEV_STOP_INSPECT") {
274
+ console.log("[DevTools] Stopping inspection");
275
+ setInspecting(false);
276
+ setHoveredElement(null);
277
+ } else if (message.type === "VDEV_TOGGLE_INSPECT") {
278
+ console.log("[DevTools] Toggling inspection");
279
+ setInspecting((prev) => {
280
+ const newState = !prev;
281
+ if (newState) {
282
+ clearSelection();
283
+ } else {
284
+ setHoveredElement(null);
285
+ }
286
+ sendToExtension({
287
+ type: "VDEV_INSPECT_STATE_CHANGED",
288
+ payload: { isInspecting: newState }
289
+ });
290
+ return newState;
291
+ });
292
+ } else if (message.type === "VDEV_CLEAR_SELECTION") {
293
+ clearSelection();
294
+ }
295
+ });
296
+ window.addEventListener("message", handler);
297
+ notifyReady();
298
+ console.log("[DevTools] SDK Ready, listening for messages");
299
+ return () => window.removeEventListener("message", handler);
300
+ }, [enabled, clearSelection]);
301
+ (0, import_react3.useEffect)(() => {
302
+ if (!isInspecting || !enabled) return;
303
+ const handleMouseMove = (e) => {
304
+ const target = e.target;
305
+ if (target.hasAttribute("data-vdev-overlay")) return;
306
+ const sourceElement = findSourceElement(target, prefix);
307
+ if (sourceElement && sourceElement !== hoveredElement) {
308
+ console.log("[DevTools] Hovered element found:", sourceElement);
309
+ setHoveredElement(sourceElement);
310
+ }
311
+ };
312
+ const handleClick = (e) => {
313
+ e.preventDefault();
314
+ e.stopPropagation();
315
+ const target = e.target;
316
+ if (target.hasAttribute("data-vdev-overlay")) return;
317
+ const sourceElement = findSourceElement(target, prefix);
318
+ if (sourceElement) {
319
+ const source = getSourceFromElement(sourceElement, prefix);
320
+ setSelectedElement(sourceElement);
321
+ setSelectedSource(source);
322
+ setInspecting(false);
323
+ setHoveredElement(null);
324
+ sendToExtension({
325
+ type: "VDEV_ELEMENT_SELECTED",
326
+ payload: {
327
+ source,
328
+ elementInfo: {
329
+ tagName: sourceElement.tagName.toLowerCase(),
330
+ className: sourceElement.className,
331
+ textContent: sourceElement.textContent?.slice(0, 100) || ""
332
+ }
333
+ }
334
+ });
335
+ }
336
+ };
337
+ document.addEventListener("mousemove", handleMouseMove, true);
338
+ document.addEventListener("click", handleClick, true);
339
+ document.body.style.cursor = "crosshair";
340
+ return () => {
341
+ document.removeEventListener("mousemove", handleMouseMove, true);
342
+ document.removeEventListener("click", handleClick, true);
343
+ document.body.style.cursor = "";
344
+ };
345
+ }, [isInspecting, enabled, hoveredElement, prefix]);
346
+ if (!enabled) {
347
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
348
+ }
349
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
350
+ DevToolsContext.Provider,
351
+ {
352
+ value: {
353
+ isInspecting,
354
+ setInspecting,
355
+ selectedElement,
356
+ selectedSource,
357
+ clearSelection
358
+ },
359
+ children: [
360
+ children,
361
+ isInspecting && hoveredElement && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Highlighter, { element: hoveredElement }),
362
+ selectedElement && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SelectionBox, { element: selectedElement, prefix })
363
+ ]
364
+ }
365
+ );
366
+ };
367
+ // Annotate the CommonJS export names for ESM import in node:
368
+ 0 && (module.exports = {
369
+ DevToolsProvider,
370
+ Highlighter,
371
+ SelectionBox,
372
+ createMessageHandler,
373
+ findSourceElement,
374
+ getSourceFromElement,
375
+ notifyReady,
376
+ parseSourceAttr,
377
+ sendToExtension,
378
+ useDevTools
379
+ });
380
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/components/DevToolsProvider.tsx","../src/overlay/Highlighter.tsx","../src/overlay/SelectionBox.tsx","../src/utils/sourceLocator.ts","../src/utils/messaging.ts"],"sourcesContent":["// Components\nexport { DevToolsProvider, useDevTools } from './components';\n\n// Overlay (advanced usage)\nexport { Highlighter, SelectionBox } from './overlay';\n\n// Utilities\nexport {\n parseSourceAttr,\n findSourceElement,\n getSourceFromElement\n} from './utils/sourceLocator';\n\nexport {\n sendToExtension,\n notifyReady,\n createMessageHandler\n} from './utils/messaging';\n\n// Types\nexport type {\n SourceLocation,\n ElementInfo,\n VDevMessage,\n ElementSelectedPayload\n} from './types';\n","import React, {\n createContext,\n useContext,\n useState,\n useCallback,\n useEffect,\n type ReactNode\n} from 'react';\nimport { Highlighter } from '../overlay/Highlighter';\nimport { SelectionBox } from '../overlay/SelectionBox';\nimport { getSourceFromElement, findSourceElement } from '../utils/sourceLocator';\nimport { sendToExtension, createMessageHandler, notifyReady } from '../utils/messaging';\nimport type { SourceLocation, VDevMessage } from '../types';\n\ninterface DevToolsContextValue {\n isInspecting: boolean;\n setInspecting: (v: boolean) => void;\n selectedElement: HTMLElement | null;\n selectedSource: SourceLocation | null;\n clearSelection: () => void;\n}\n\nconst DevToolsContext = createContext<DevToolsContextValue | null>(null);\n\nexport const useDevTools = () => {\n const context = useContext(DevToolsContext);\n if (!context) {\n throw new Error('useDevTools must be used within a DevToolsProvider');\n }\n return context;\n};\n\ninterface DevToolsProviderProps {\n children: ReactNode;\n /** Only enable in development mode (default: true) */\n enabled?: boolean;\n /** Attribute prefix (default: 'vdev') */\n prefix?: string;\n}\n\nexport const DevToolsProvider: React.FC<DevToolsProviderProps> = ({\n children,\n enabled = true,\n prefix = 'vdev'\n}) => {\n const [isInspecting, setInspecting] = useState(false);\n const [hoveredElement, setHoveredElement] = useState<HTMLElement | null>(null);\n const [selectedElement, setSelectedElement] = useState<HTMLElement | null>(null);\n const [selectedSource, setSelectedSource] = useState<SourceLocation | null>(null);\n\n const clearSelection = useCallback(() => {\n setSelectedElement(null);\n setSelectedSource(null);\n }, []);\n\n // Listen to messages from extension\n useEffect(() => {\n if (!enabled) return;\n\n const handler = createMessageHandler((message: VDevMessage) => {\n console.log('[DevTools] Received message:', message);\n if (message.type === 'VDEV_START_INSPECT') {\n console.log('[DevTools] Starting inspection');\n setInspecting(true);\n clearSelection();\n } else if (message.type === 'VDEV_STOP_INSPECT') {\n console.log('[DevTools] Stopping inspection');\n setInspecting(false);\n setHoveredElement(null);\n } else if (message.type === 'VDEV_TOGGLE_INSPECT') {\n console.log('[DevTools] Toggling inspection');\n setInspecting(prev => {\n const newState = !prev;\n if (newState) {\n // Starting inspection, clear selection\n clearSelection();\n } else {\n // Stopping inspection, clear hovered\n setHoveredElement(null);\n }\n // Notify extension of state change\n sendToExtension({\n type: 'VDEV_INSPECT_STATE_CHANGED',\n payload: { isInspecting: newState }\n });\n return newState;\n });\n } else if (message.type === 'VDEV_CLEAR_SELECTION') {\n clearSelection();\n }\n });\n\n window.addEventListener('message', handler);\n\n // Notify extension that SDK is ready\n notifyReady();\n console.log('[DevTools] SDK Ready, listening for messages');\n\n return () => window.removeEventListener('message', handler);\n }, [enabled, clearSelection]);\n\n // Handle mouse events in inspect mode\n useEffect(() => {\n if (!isInspecting || !enabled) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n\n // Ignore our own overlay elements\n if (target.hasAttribute('data-vdev-overlay')) return;\n\n const sourceElement = findSourceElement(target, prefix);\n // console.log('[DevTools] Mouse move', target, sourceElement);\n\n if (sourceElement && sourceElement !== hoveredElement) {\n console.log('[DevTools] Hovered element found:', sourceElement);\n setHoveredElement(sourceElement);\n }\n };\n\n const handleClick = (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const target = e.target as HTMLElement;\n\n // Ignore clicks on overlay\n if (target.hasAttribute('data-vdev-overlay')) return;\n\n const sourceElement = findSourceElement(target, prefix);\n\n if (sourceElement) {\n const source = getSourceFromElement(sourceElement, prefix);\n setSelectedElement(sourceElement);\n setSelectedSource(source);\n setInspecting(false);\n setHoveredElement(null);\n\n // Notify extension of selection\n sendToExtension({\n type: 'VDEV_ELEMENT_SELECTED',\n payload: {\n source,\n elementInfo: {\n tagName: sourceElement.tagName.toLowerCase(),\n className: sourceElement.className,\n textContent: sourceElement.textContent?.slice(0, 100) || '',\n },\n },\n });\n }\n };\n\n // Use capture to intercept before normal handlers\n document.addEventListener('mousemove', handleMouseMove, true);\n document.addEventListener('click', handleClick, true);\n\n // Add cursor style\n document.body.style.cursor = 'crosshair';\n\n return () => {\n document.removeEventListener('mousemove', handleMouseMove, true);\n document.removeEventListener('click', handleClick, true);\n document.body.style.cursor = '';\n };\n }, [isInspecting, enabled, hoveredElement, prefix]);\n\n // Don't render anything if disabled\n if (!enabled) {\n return <>{children}</>;\n }\n\n return (\n <DevToolsContext.Provider\n value={{\n isInspecting,\n setInspecting,\n selectedElement,\n selectedSource,\n clearSelection\n }}\n >\n {children}\n\n {/* Hover highlighter */}\n {isInspecting && hoveredElement && (\n <Highlighter element={hoveredElement} />\n )}\n\n {/* Selection box */}\n {selectedElement && (\n <SelectionBox element={selectedElement} prefix={prefix} />\n )}\n </DevToolsContext.Provider>\n );\n};\n","import React, { useEffect, useState } from 'react';\n\ninterface Props {\n element: HTMLElement;\n color?: string;\n}\n\n/**\n * Highlighter overlay component - shows a blue overlay on hovered elements\n */\nexport const Highlighter: React.FC<Props> = ({\n element,\n color = 'rgba(66, 153, 225, 0.3)'\n}) => {\n const [rect, setRect] = useState<DOMRect | null>(null);\n\n useEffect(() => {\n const update = () => setRect(element.getBoundingClientRect());\n update();\n\n const observer = new ResizeObserver(update);\n observer.observe(element);\n\n window.addEventListener('scroll', update, true);\n window.addEventListener('resize', update);\n\n return () => {\n observer.disconnect();\n window.removeEventListener('scroll', update, true);\n window.removeEventListener('resize', update);\n };\n }, [element]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'fixed',\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n backgroundColor: color,\n border: '2px solid #4299e1',\n pointerEvents: 'none',\n zIndex: 999999,\n transition: 'all 0.1s ease',\n boxSizing: 'border-box',\n }}\n data-vdev-overlay=\"highlighter\"\n />\n );\n};\n","import React, { useEffect, useState } from 'react';\nimport type { SourceLocation } from '../types';\nimport { getSourceFromElement } from '../utils/sourceLocator';\n\ninterface Props {\n element: HTMLElement;\n prefix?: string;\n}\n\n/**\n * SelectionBox component - shows a persistent selection box with source info label\n */\nexport const SelectionBox: React.FC<Props> = ({ element, prefix = 'vdev' }) => {\n const [rect, setRect] = useState<DOMRect | null>(null);\n const [source, setSource] = useState<SourceLocation | null>(null);\n\n useEffect(() => {\n const update = () => setRect(element.getBoundingClientRect());\n update();\n\n // Get source info\n setSource(getSourceFromElement(element, prefix));\n\n const observer = new ResizeObserver(update);\n observer.observe(element);\n\n window.addEventListener('scroll', update, true);\n window.addEventListener('resize', update);\n\n return () => {\n observer.disconnect();\n window.removeEventListener('scroll', update, true);\n window.removeEventListener('resize', update);\n };\n }, [element, prefix]);\n\n if (!rect) return null;\n\n // Format file path for display (show only basename)\n const fileName = source?.fileName.split('/').pop() || 'unknown';\n const lineInfo = source ? `${fileName}:${source.lineNumber}` : '';\n\n return (\n <>\n {/* Selection border */}\n <div\n style={{\n position: 'fixed',\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n border: '2px solid #6366f1',\n backgroundColor: 'rgba(99, 102, 241, 0.1)',\n pointerEvents: 'none',\n zIndex: 999999,\n boxSizing: 'border-box',\n }}\n data-vdev-overlay=\"selection\"\n />\n\n {/* Label showing file:line */}\n {lineInfo && (\n <div\n style={{\n position: 'fixed',\n top: Math.max(0, rect.top - 24),\n left: rect.left,\n backgroundColor: '#6366f1',\n color: 'white',\n fontSize: '11px',\n fontFamily: 'monospace',\n padding: '2px 6px',\n borderRadius: '3px',\n pointerEvents: 'none',\n zIndex: 999999,\n whiteSpace: 'nowrap',\n }}\n data-vdev-overlay=\"label\"\n >\n {lineInfo}\n </div>\n )}\n </>\n );\n};\n","import type { SourceLocation } from '../types';\n\n/**\n * Get React Fiber node from DOM element\n * React attaches fiber information to DOM elements with internal keys\n */\nfunction getReactFiber(element: HTMLElement): any {\n const key = Object.keys(element).find(\n k => k.startsWith('__reactFiber$') || k.startsWith('__reactInternalInstance$')\n );\n return key ? (element as any)[key] : null;\n}\n\n/**\n * Walk up the fiber tree to find a fiber with _debugSource\n */\nfunction findFiberWithSource(fiber: any): any {\n let current = fiber;\n while (current) {\n if (current._debugSource) {\n return current;\n }\n current = current.return;\n }\n return null;\n}\n\n/**\n * Get source from React Fiber's _debugSource (runtime detection)\n * This is the preferred method as it doesn't require any build plugin\n */\nexport function getSourceFromFiber(element: HTMLElement): SourceLocation | null {\n const fiber = getReactFiber(element);\n if (!fiber) return null;\n\n const fiberWithSource = findFiberWithSource(fiber);\n if (fiberWithSource?._debugSource) {\n const { fileName, lineNumber, columnNumber } = fiberWithSource._debugSource;\n return {\n fileName,\n lineNumber,\n columnNumber: columnNumber || 1\n };\n }\n return null;\n}\n\n/**\n * Parse the data-vdev-source attribute value into a SourceLocation object\n * (Legacy support for projects using the babel/vite plugin)\n */\nexport function parseSourceAttr(attrValue: string | null): SourceLocation | null {\n if (!attrValue) return null;\n\n try {\n const parsed = JSON.parse(attrValue);\n if (\n typeof parsed.fileName === 'string' &&\n typeof parsed.lineNumber === 'number' &&\n typeof parsed.columnNumber === 'number'\n ) {\n return parsed as SourceLocation;\n }\n } catch {\n // Ignore parse errors\n }\n\n return null;\n}\n\n/**\n * Find the closest element with source information\n * First tries React Fiber (runtime), then falls back to data attributes\n */\nexport function findSourceElement(target: HTMLElement, prefix = 'vdev'): HTMLElement | null {\n // First, try to find source from React Fiber (runtime)\n let current: HTMLElement | null = target;\n while (current && current !== document.body) {\n if (getSourceFromFiber(current)) {\n return current;\n }\n current = current.parentElement;\n }\n\n // Fallback: check for data attributes (legacy plugin support)\n return target.closest(`[data-${prefix}-file], [data-${prefix}-source]`) as HTMLElement | null;\n}\n\n/**\n * Get source location from an element\n * Prioritizes React Fiber _debugSource, falls back to data attributes\n */\nexport function getSourceFromElement(element: HTMLElement, prefix = 'vdev'): SourceLocation | null {\n // 1. Try React Fiber _debugSource first (runtime, no plugin needed)\n const fiberSource = getSourceFromFiber(element);\n if (fiberSource) {\n return fiberSource;\n }\n\n // 2. Try new data attribute format (plugin-based)\n const fileName = element.getAttribute(`data-${prefix}-file`);\n const lineStr = element.getAttribute(`data-${prefix}-line`);\n const colStr = element.getAttribute(`data-${prefix}-col`);\n\n if (fileName && lineStr) {\n return {\n fileName,\n lineNumber: parseInt(lineStr, 10),\n columnNumber: colStr ? parseInt(colStr, 10) : 1\n };\n }\n\n // 3. Fallback to legacy format (JSON in single attribute)\n const attrValue = element.getAttribute(`data-${prefix}-source`);\n return parseSourceAttr(attrValue);\n}\n\n","import type { VDevMessage } from '../types';\n\nconst MESSAGE_SOURCE = 'vdev-react-sdk';\n\n/**\n * Send a message to the Chrome extension via window.postMessage\n */\nexport function sendToExtension(message: VDevMessage): void {\n window.postMessage(\n { ...message, source: MESSAGE_SOURCE },\n '*'\n );\n}\n\n/**\n * Notify extension that SDK is ready\n */\nexport function notifyReady(): void {\n sendToExtension({ type: 'VDEV_SDK_READY' });\n}\n\n/**\n * Create a message handler that only processes messages from the extension\n */\nexport function createMessageHandler(\n handler: (message: VDevMessage) => void\n): (event: MessageEvent) => void {\n return (event: MessageEvent) => {\n // Only process messages from the same window\n if (event.source !== window) return;\n\n // Only process messages from extension (not from SDK itself)\n if (event.data?.source === MESSAGE_SOURCE) return;\n\n // Process VDEV messages\n if (event.data?.type?.startsWith('VDEV_')) {\n handler(event.data as VDevMessage);\n }\n };\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","import_jsx_runtime"]}