ui-agent-annotation 0.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.
@@ -0,0 +1,1758 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
10
+
11
+ // src/store.tsx
12
+ import { createContext, useContext, useReducer } from "react";
13
+ import { jsx } from "react/jsx-runtime";
14
+ var initialState = {
15
+ mode: "disabled",
16
+ annotations: [],
17
+ hoveredElement: null,
18
+ hoveredComponentInfo: null,
19
+ isMinimized: false,
20
+ showList: false
21
+ };
22
+ var AnnotationContext = createContext(void 0);
23
+ function reducer(state, action) {
24
+ switch (action.type) {
25
+ case "SET_MODE":
26
+ return { ...state, mode: action.payload };
27
+ case "ADD_ANNOTATION":
28
+ return { ...state, annotations: [...state.annotations, action.payload] };
29
+ case "REMOVE_ANNOTATION":
30
+ return {
31
+ ...state,
32
+ annotations: state.annotations.filter((a) => a.id !== action.payload)
33
+ };
34
+ case "CLEAR_ALL_ANNOTATIONS":
35
+ return {
36
+ ...state,
37
+ annotations: []
38
+ };
39
+ case "SET_HOVERED":
40
+ if (state.hoveredElement === action.payload.element) return state;
41
+ return {
42
+ ...state,
43
+ hoveredElement: action.payload.element,
44
+ hoveredComponentInfo: action.payload.name ? { name: action.payload.name, details: action.payload.details } : null
45
+ };
46
+ case "RESET_HOVER":
47
+ return { ...state, hoveredElement: null, hoveredComponentInfo: null };
48
+ case "TOGGLE_MINIMIZED":
49
+ return { ...state, isMinimized: !state.isMinimized };
50
+ case "TOGGLE_LIST":
51
+ return { ...state, showList: !state.showList };
52
+ default:
53
+ return state;
54
+ }
55
+ }
56
+ function AgentAnnotationProvider({ children }) {
57
+ const [state, dispatch] = useReducer(reducer, initialState);
58
+ return /* @__PURE__ */ jsx(AnnotationContext.Provider, { value: { state, dispatch }, children });
59
+ }
60
+ function useAgentAnnotation() {
61
+ const context = useContext(AnnotationContext);
62
+ if (!context) {
63
+ throw new Error("useAgentAnnotation must be used within an AgentAnnotationProvider");
64
+ }
65
+ return context;
66
+ }
67
+
68
+ // src/components/Toolbar.tsx
69
+ import { useState as useState5, useEffect as useEffect4, useRef as useRef2 } from "react";
70
+
71
+ // src/components/Draggable.tsx
72
+ import { useState, useEffect, useRef } from "react";
73
+ import { jsx as jsx2 } from "react/jsx-runtime";
74
+ function Draggable({ children, initialPos = { x: 20, y: 20 } }) {
75
+ const [pos, setPos] = useState(initialPos);
76
+ const [dragging, setDragging] = useState(false);
77
+ const [rel, setRel] = useState({ x: 0, y: 0 });
78
+ const nodeRef = useRef(null);
79
+ const onMouseDown = (e) => {
80
+ if (e.button !== 0) return;
81
+ const node = nodeRef.current;
82
+ if (!node) return;
83
+ const rect = node.getBoundingClientRect();
84
+ setDragging(true);
85
+ setRel({
86
+ x: e.pageX - rect.left - window.scrollX,
87
+ y: e.pageY - rect.top - window.scrollY
88
+ });
89
+ e.preventDefault();
90
+ };
91
+ const onMouseMove = (e) => {
92
+ if (!dragging) return;
93
+ setPos({
94
+ x: e.pageX - rel.x,
95
+ y: e.pageY - rel.y
96
+ });
97
+ e.preventDefault();
98
+ };
99
+ const onMouseUp = () => {
100
+ setDragging(false);
101
+ };
102
+ useEffect(() => {
103
+ if (dragging) {
104
+ document.addEventListener("mousemove", onMouseMove);
105
+ document.addEventListener("mouseup", onMouseUp);
106
+ } else {
107
+ document.removeEventListener("mousemove", onMouseMove);
108
+ document.removeEventListener("mouseup", onMouseUp);
109
+ }
110
+ return () => {
111
+ document.removeEventListener("mousemove", onMouseMove);
112
+ document.removeEventListener("mouseup", onMouseUp);
113
+ };
114
+ }, [dragging]);
115
+ return /* @__PURE__ */ jsx2(
116
+ "div",
117
+ {
118
+ ref: nodeRef,
119
+ style: {
120
+ position: "fixed",
121
+ left: pos.x,
122
+ top: pos.y,
123
+ zIndex: 9999,
124
+ cursor: dragging ? "grabbing" : "grab"
125
+ },
126
+ onMouseDown,
127
+ children
128
+ }
129
+ );
130
+ }
131
+
132
+ // src/components/Toolbar.tsx
133
+ import { GripVertical, MousePointer2, List, Copy, Minus, Maximize2, Ban, Check } from "lucide-react";
134
+
135
+ // src/components/Highlighter.tsx
136
+ import { useEffect as useEffect3, useState as useState3 } from "react";
137
+
138
+ // src/components/AnnotationInput.tsx
139
+ import { useState as useState2, useEffect as useEffect2 } from "react";
140
+ import { X } from "lucide-react";
141
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
142
+ function formatComponentDetails(details) {
143
+ const lines = [];
144
+ lines.push("## Element");
145
+ let elementStr = `<${details.elementInfo.tagName}`;
146
+ if (details.elementInfo.id) elementStr += ` id="${details.elementInfo.id}"`;
147
+ if (details.elementInfo.className) elementStr += ` class="${details.elementInfo.className}"`;
148
+ elementStr += ">";
149
+ lines.push(elementStr);
150
+ if (details.elementInfo.textContent) {
151
+ lines.push(`Text: "${details.elementInfo.textContent}"`);
152
+ }
153
+ lines.push(`Child elements: ${details.elementInfo.childElementCount}`);
154
+ if (Object.keys(details.elementInfo.attributes).length > 0) {
155
+ lines.push("");
156
+ lines.push("## Attributes");
157
+ for (const [key, value] of Object.entries(details.elementInfo.attributes)) {
158
+ lines.push(`${key}="${value}"`);
159
+ }
160
+ }
161
+ if (details.parentHierarchy.length > 0) {
162
+ lines.push("");
163
+ lines.push("## Parent Components");
164
+ lines.push(details.parentHierarchy.join(" \u2192 "));
165
+ }
166
+ if (details.childComponents.length > 0) {
167
+ lines.push("");
168
+ lines.push(`## Child Components (${details.childComponents.length})`);
169
+ const childLines = details.childComponents.slice(0, 15).map((child) => {
170
+ let str = child.name;
171
+ if (child.count > 1) str += ` \xD7${child.count}`;
172
+ if (child.hasChildren) str += " (has children)";
173
+ return str;
174
+ });
175
+ lines.push(childLines.join(", "));
176
+ if (details.childComponents.length > 15) {
177
+ lines.push(`... and ${details.childComponents.length - 15} more`);
178
+ }
179
+ }
180
+ return lines.join("\n");
181
+ }
182
+ function AnnotationInput({ onClose, componentName, componentDetails }) {
183
+ const { dispatch } = useAgentAnnotation();
184
+ const [note, setNote] = useState2("");
185
+ const [includeDetails, setIncludeDetails] = useState2(true);
186
+ const [isVisible, setIsVisible] = useState2(false);
187
+ const [isClosing, setIsClosing] = useState2(false);
188
+ useEffect2(() => {
189
+ requestAnimationFrame(() => {
190
+ setIsVisible(true);
191
+ });
192
+ }, []);
193
+ useEffect2(() => {
194
+ const handleKeyDown = (e) => {
195
+ if (e.key === "Escape") {
196
+ e.preventDefault();
197
+ e.stopPropagation();
198
+ handleClose();
199
+ }
200
+ };
201
+ document.addEventListener("keydown", handleKeyDown);
202
+ return () => document.removeEventListener("keydown", handleKeyDown);
203
+ }, []);
204
+ const handleClose = () => {
205
+ setIsClosing(true);
206
+ setTimeout(() => {
207
+ onClose();
208
+ }, 200);
209
+ };
210
+ const handleSubmit = (e) => {
211
+ e.preventDefault();
212
+ if (!note.trim()) return;
213
+ let finalNote = note.trim();
214
+ if (includeDetails && componentDetails) {
215
+ const detailsText = formatComponentDetails(componentDetails);
216
+ finalNote = `${note.trim()}
217
+
218
+ ---
219
+ ${detailsText}`;
220
+ }
221
+ dispatch({
222
+ type: "ADD_ANNOTATION",
223
+ payload: {
224
+ id: Date.now().toString(),
225
+ componentName,
226
+ note: finalNote,
227
+ timestamp: Date.now(),
228
+ details: componentDetails
229
+ }
230
+ });
231
+ handleClose();
232
+ };
233
+ const detailsPreview = componentDetails ? /* @__PURE__ */ jsxs("div", { style: {
234
+ fontSize: "0.75rem",
235
+ color: "rgba(255, 255, 255, 0.6)",
236
+ marginTop: "4px"
237
+ }, children: [
238
+ componentDetails.parentHierarchy.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
239
+ "Parents: ",
240
+ componentDetails.parentHierarchy.slice(0, 3).join(" \u2192 "),
241
+ componentDetails.parentHierarchy.length > 3 ? "..." : ""
242
+ ] }),
243
+ componentDetails.childComponents.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
244
+ "Children: ",
245
+ componentDetails.childComponents.slice(0, 3).map((c) => c.name).join(", "),
246
+ componentDetails.childComponents.length > 3 ? "..." : ""
247
+ ] }),
248
+ /* @__PURE__ */ jsxs("div", { children: [
249
+ "Element: <",
250
+ componentDetails.elementInfo.tagName,
251
+ "> (",
252
+ componentDetails.elementInfo.childElementCount,
253
+ " children)"
254
+ ] })
255
+ ] }) : null;
256
+ return /* @__PURE__ */ jsx3(
257
+ "div",
258
+ {
259
+ style: {
260
+ position: "fixed",
261
+ top: 0,
262
+ left: 0,
263
+ right: 0,
264
+ bottom: 0,
265
+ backgroundColor: isVisible && !isClosing ? "rgba(0,0,0,0.5)" : "rgba(0,0,0,0)",
266
+ display: "flex",
267
+ alignItems: "center",
268
+ justifyContent: "center",
269
+ zIndex: 1e4,
270
+ transition: "background-color 0.2s ease"
271
+ },
272
+ "data-ai-annotation-ui": true,
273
+ onClick: handleClose,
274
+ children: /* @__PURE__ */ jsxs(
275
+ "div",
276
+ {
277
+ style: {
278
+ backgroundColor: "#1e1e1e",
279
+ color: "#e5e7eb",
280
+ padding: "20px",
281
+ borderRadius: "8px",
282
+ width: "500px",
283
+ maxWidth: "90%",
284
+ maxHeight: "80vh",
285
+ overflow: "auto",
286
+ boxShadow: "0 4px 6px rgba(0,0,0,0.3)",
287
+ transform: isVisible && !isClosing ? "scale(1) translateY(0)" : "scale(0.95) translateY(-10px)",
288
+ opacity: isVisible && !isClosing ? 1 : 0,
289
+ transition: "transform 0.2s ease, opacity 0.2s ease"
290
+ },
291
+ onClick: (e) => e.stopPropagation(),
292
+ children: [
293
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "16px" }, children: [
294
+ /* @__PURE__ */ jsx3("h3", { style: { margin: 0, fontSize: "1.1rem" }, children: "Add Annotation" }),
295
+ /* @__PURE__ */ jsx3("button", { onClick: handleClose, style: { background: "none", border: "none", color: "inherit", cursor: "pointer" }, children: /* @__PURE__ */ jsx3(X, { size: 20 }) })
296
+ ] }),
297
+ /* @__PURE__ */ jsxs("div", { style: { marginBottom: "12px", fontSize: "0.9rem", opacity: 0.8 }, children: [
298
+ "Component: ",
299
+ /* @__PURE__ */ jsx3("strong", { children: componentName })
300
+ ] }),
301
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
302
+ /* @__PURE__ */ jsx3(
303
+ "textarea",
304
+ {
305
+ value: note,
306
+ onChange: (e) => setNote(e.target.value),
307
+ placeholder: "Describe what this component does or what changes you need...",
308
+ style: {
309
+ width: "100%",
310
+ height: "120px",
311
+ padding: "8px",
312
+ borderRadius: "4px",
313
+ backgroundColor: "#2d2d2d",
314
+ border: "1px solid #404040",
315
+ color: "white",
316
+ marginBottom: "12px",
317
+ resize: "vertical",
318
+ fontFamily: "inherit"
319
+ },
320
+ autoFocus: true
321
+ }
322
+ ),
323
+ componentDetails && /* @__PURE__ */ jsx3("div", { style: { marginBottom: "16px" }, children: /* @__PURE__ */ jsxs(
324
+ "label",
325
+ {
326
+ style: {
327
+ display: "flex",
328
+ alignItems: "flex-start",
329
+ gap: "8px",
330
+ cursor: "pointer",
331
+ fontSize: "0.85rem"
332
+ },
333
+ children: [
334
+ /* @__PURE__ */ jsx3(
335
+ "input",
336
+ {
337
+ type: "checkbox",
338
+ checked: includeDetails,
339
+ onChange: (e) => setIncludeDetails(e.target.checked),
340
+ style: { marginTop: "2px" }
341
+ }
342
+ ),
343
+ /* @__PURE__ */ jsxs("div", { children: [
344
+ /* @__PURE__ */ jsx3("div", { style: { color: "#10b981", fontWeight: 500 }, children: "Include component details in annotation" }),
345
+ includeDetails && detailsPreview
346
+ ] })
347
+ ]
348
+ }
349
+ ) }),
350
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "flex-end", gap: "8px" }, children: [
351
+ /* @__PURE__ */ jsx3(
352
+ "button",
353
+ {
354
+ type: "button",
355
+ onClick: handleClose,
356
+ style: {
357
+ padding: "6px 12px",
358
+ borderRadius: "4px",
359
+ backgroundColor: "transparent",
360
+ border: "1px solid #404040",
361
+ color: "white",
362
+ cursor: "pointer"
363
+ },
364
+ children: "Cancel"
365
+ }
366
+ ),
367
+ /* @__PURE__ */ jsx3(
368
+ "button",
369
+ {
370
+ type: "submit",
371
+ style: {
372
+ padding: "6px 12px",
373
+ borderRadius: "4px",
374
+ backgroundColor: "#3b82f6",
375
+ border: "none",
376
+ color: "white",
377
+ cursor: "pointer"
378
+ },
379
+ children: "Save Annotation"
380
+ }
381
+ )
382
+ ] })
383
+ ] })
384
+ ]
385
+ }
386
+ )
387
+ }
388
+ );
389
+ }
390
+
391
+ // src/utils/screenshot.ts
392
+ import html2canvas from "html2canvas";
393
+ function isTauriEnv() {
394
+ return typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
395
+ }
396
+ async function copyToClipboardTauri(blob) {
397
+ if (typeof window.__TAURI_CLIPBOARD_WRITE_IMAGE__ === "function") {
398
+ const arrayBuffer = await blob.arrayBuffer();
399
+ const bytes = new Uint8Array(arrayBuffer);
400
+ await window.__TAURI_CLIPBOARD_WRITE_IMAGE__(bytes);
401
+ return;
402
+ }
403
+ throw new Error("Tauri clipboard function not available");
404
+ }
405
+ async function copyToClipboardBrowser(blob, dataUrl) {
406
+ try {
407
+ await navigator.clipboard.write([
408
+ new ClipboardItem({
409
+ "image/png": blob
410
+ })
411
+ ]);
412
+ } catch (clipboardError) {
413
+ console.warn("Failed to copy to clipboard:", clipboardError);
414
+ try {
415
+ await navigator.clipboard.writeText(dataUrl);
416
+ } catch {
417
+ }
418
+ }
419
+ }
420
+ async function captureScreenshot(element, options = {}) {
421
+ const {
422
+ scale = 2,
423
+ backgroundColor = null,
424
+ copyToClipboard = true,
425
+ download = false,
426
+ filename = "screenshot.png"
427
+ } = options;
428
+ try {
429
+ const canvas = await html2canvas(element, {
430
+ scale,
431
+ backgroundColor,
432
+ logging: false,
433
+ useCORS: true,
434
+ allowTaint: true,
435
+ // Capture just the element
436
+ x: window.scrollX,
437
+ y: window.scrollY,
438
+ scrollX: -window.scrollX,
439
+ scrollY: -window.scrollY,
440
+ windowWidth: document.documentElement.scrollWidth,
441
+ windowHeight: document.documentElement.scrollHeight,
442
+ // Ignore annotation UI elements
443
+ ignoreElements: (el) => {
444
+ return el.hasAttribute("data-ai-annotation-ui");
445
+ }
446
+ });
447
+ const blob = await new Promise((resolve, reject) => {
448
+ canvas.toBlob((b) => {
449
+ if (b) resolve(b);
450
+ else reject(new Error("Failed to create blob"));
451
+ }, "image/png");
452
+ });
453
+ const dataUrl = canvas.toDataURL("image/png");
454
+ if (copyToClipboard) {
455
+ if (isTauriEnv()) {
456
+ try {
457
+ await copyToClipboardTauri(blob);
458
+ } catch (tauriErr) {
459
+ console.warn("Tauri clipboard failed, falling back to browser API:", tauriErr);
460
+ await copyToClipboardBrowser(blob, dataUrl);
461
+ }
462
+ } else {
463
+ await copyToClipboardBrowser(blob, dataUrl);
464
+ }
465
+ }
466
+ if (download) {
467
+ const link = document.createElement("a");
468
+ link.href = dataUrl;
469
+ link.download = filename;
470
+ document.body.appendChild(link);
471
+ link.click();
472
+ document.body.removeChild(link);
473
+ }
474
+ return {
475
+ success: true,
476
+ dataUrl,
477
+ blob
478
+ };
479
+ } catch (error) {
480
+ const message = error instanceof Error ? error.message : "Unknown error";
481
+ console.error("Screenshot capture failed:", message);
482
+ return {
483
+ success: false,
484
+ error: message
485
+ };
486
+ }
487
+ }
488
+
489
+ // src/utils/fiber.ts
490
+ function getReactFiber(dom) {
491
+ const key = Object.keys(dom).find(
492
+ (key2) => key2.startsWith("__reactFiber$")
493
+ );
494
+ return key ? dom[key] : null;
495
+ }
496
+ function getComponentDisplayName(fiber) {
497
+ let curr = fiber;
498
+ while (curr) {
499
+ const name = curr.type?.displayName || curr.type?.name;
500
+ if (name && typeof curr.type === "function") return name;
501
+ curr = curr.return;
502
+ }
503
+ return "Unknown";
504
+ }
505
+ function getElementFromFiber(fiber) {
506
+ let curr = fiber;
507
+ while (curr) {
508
+ if (curr.stateNode instanceof HTMLElement) {
509
+ return curr.stateNode;
510
+ }
511
+ curr = curr.child;
512
+ }
513
+ return null;
514
+ }
515
+ function getParentHierarchy(fiber, maxDepth = 10) {
516
+ const hierarchy = [];
517
+ let curr = fiber?.return;
518
+ let depth = 0;
519
+ while (curr && depth < maxDepth) {
520
+ const name = curr.type?.displayName || curr.type?.name;
521
+ if (name && typeof curr.type === "function") {
522
+ if (!name.includes("$") && !name.startsWith("_")) {
523
+ hierarchy.push(name);
524
+ }
525
+ }
526
+ curr = curr.return;
527
+ depth++;
528
+ }
529
+ return hierarchy;
530
+ }
531
+ function getChildComponents(fiber, maxDepth = 5) {
532
+ const children = /* @__PURE__ */ new Map();
533
+ function traverse(node, depth) {
534
+ if (!node || depth > maxDepth) return;
535
+ const name = node.type?.displayName || node.type?.name;
536
+ if (name && typeof node.type === "function" && !name.includes("$") && !name.startsWith("_")) {
537
+ const existing = children.get(name);
538
+ const hasChildComponents = checkHasChildComponents(node.child);
539
+ if (existing) {
540
+ existing.count++;
541
+ if (depth < existing.depth) {
542
+ existing.depth = depth;
543
+ }
544
+ existing.hasChildren = existing.hasChildren || hasChildComponents;
545
+ } else {
546
+ children.set(name, { count: 1, depth, hasChildren: hasChildComponents });
547
+ }
548
+ }
549
+ if (node.child) traverse(node.child, depth + 1);
550
+ if (node.sibling) traverse(node.sibling, depth);
551
+ }
552
+ if (fiber?.child) {
553
+ traverse(fiber.child, 1);
554
+ }
555
+ return Array.from(children.entries()).map(([name, info]) => ({
556
+ name,
557
+ depth: info.depth,
558
+ count: info.count,
559
+ hasChildren: info.hasChildren
560
+ })).sort((a, b) => a.depth - b.depth);
561
+ }
562
+ function checkHasChildComponents(fiber, maxDepth = 3) {
563
+ if (!fiber || maxDepth <= 0) return false;
564
+ const name = fiber.type?.displayName || fiber.type?.name;
565
+ if (name && typeof fiber.type === "function" && !name.includes("$")) {
566
+ return true;
567
+ }
568
+ if (fiber.child && checkHasChildComponents(fiber.child, maxDepth - 1)) return true;
569
+ if (fiber.sibling && checkHasChildComponents(fiber.sibling, maxDepth - 1)) return true;
570
+ return false;
571
+ }
572
+ function getElementInfo(element) {
573
+ const importantAttributes = ["data-testid", "role", "aria-label", "type", "name", "href", "src"];
574
+ const attributes = {};
575
+ importantAttributes.forEach((attr) => {
576
+ const value = element.getAttribute(attr);
577
+ if (value) {
578
+ attributes[attr] = value;
579
+ }
580
+ });
581
+ let textContent;
582
+ const directText = Array.from(element.childNodes).filter((node) => node.nodeType === Node.TEXT_NODE).map((node) => node.textContent?.trim()).filter(Boolean).join(" ");
583
+ if (directText) {
584
+ textContent = directText.length > 100 ? directText.substring(0, 100) + "..." : directText;
585
+ }
586
+ return {
587
+ tagName: element.tagName.toLowerCase(),
588
+ id: element.id || void 0,
589
+ className: element.className && typeof element.className === "string" ? element.className.split(" ").slice(0, 5).join(" ") + (element.className.split(" ").length > 5 ? "..." : "") : void 0,
590
+ attributes,
591
+ childElementCount: element.childElementCount,
592
+ textContent
593
+ };
594
+ }
595
+ function getComponentProps(fiber, maxProps = 10) {
596
+ if (!fiber?.memoizedProps) return void 0;
597
+ const props = fiber.memoizedProps;
598
+ const safeProps = {};
599
+ let count = 0;
600
+ for (const key of Object.keys(props)) {
601
+ if (count >= maxProps) {
602
+ safeProps["..."] = `${Object.keys(props).length - maxProps} more props`;
603
+ break;
604
+ }
605
+ if (key === "children") continue;
606
+ const value = props[key];
607
+ const type = typeof value;
608
+ if (type === "function") {
609
+ safeProps[key] = "[Function]";
610
+ } else if (type === "object" && value !== null) {
611
+ if (Array.isArray(value)) {
612
+ safeProps[key] = `[Array(${value.length})]`;
613
+ } else if (value.$$typeof) {
614
+ safeProps[key] = "[ReactElement]";
615
+ } else {
616
+ try {
617
+ const json = JSON.stringify(value);
618
+ safeProps[key] = json.length > 100 ? "[Object]" : value;
619
+ } catch {
620
+ safeProps[key] = "[Object]";
621
+ }
622
+ }
623
+ } else {
624
+ safeProps[key] = value;
625
+ }
626
+ count++;
627
+ }
628
+ return Object.keys(safeProps).length > 0 ? safeProps : void 0;
629
+ }
630
+ function getComponentDetails(element, options) {
631
+ const { includeProps = false, maxParentDepth = 10, maxChildDepth = 5 } = options || {};
632
+ const fiber = getReactFiber(element);
633
+ const name = fiber ? getComponentDisplayName(fiber) : "Unknown";
634
+ let componentFiber = fiber;
635
+ while (componentFiber && typeof componentFiber.type !== "function") {
636
+ componentFiber = componentFiber.return;
637
+ }
638
+ return {
639
+ name,
640
+ parentHierarchy: getParentHierarchy(componentFiber, maxParentDepth),
641
+ childComponents: getChildComponents(componentFiber, maxChildDepth),
642
+ elementInfo: getElementInfo(element),
643
+ props: includeProps ? getComponentProps(componentFiber) : void 0
644
+ };
645
+ }
646
+
647
+ // src/components/Highlighter.tsx
648
+ import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
649
+ function Highlighter() {
650
+ const { state, dispatch } = useAgentAnnotation();
651
+ const { hoveredElement, mode, hoveredComponentInfo } = state;
652
+ const [rect, setRect] = useState3(null);
653
+ const [showInput, setShowInput] = useState3(false);
654
+ const [mousePos, setMousePos] = useState3({ x: 0, y: 0 });
655
+ const [isLocked, setIsLocked] = useState3(false);
656
+ const [lockedPos, setLockedPos] = useState3({ x: 0, y: 0 });
657
+ const [isCapturing, setIsCapturing] = useState3(false);
658
+ const [captureSuccess, setCaptureSuccess] = useState3(false);
659
+ const [showDetails, setShowDetails] = useState3(false);
660
+ const componentName = hoveredComponentInfo?.name || "";
661
+ const componentDetails = hoveredComponentInfo?.details;
662
+ useEffect3(() => {
663
+ if (mode !== "inspecting") return;
664
+ const handleMouseOver = (e) => {
665
+ if (isLocked) return;
666
+ const target = e.target;
667
+ if (target.closest("[data-ai-annotation-ui]") || target.closest("[data-annotation-tooltip]")) {
668
+ return;
669
+ }
670
+ const details = getComponentDetails(target, {
671
+ includeProps: false,
672
+ maxParentDepth: 10,
673
+ maxChildDepth: 5
674
+ });
675
+ dispatch({
676
+ type: "SET_HOVERED",
677
+ payload: { element: target, name: details.name, details }
678
+ });
679
+ };
680
+ document.addEventListener("mouseover", handleMouseOver);
681
+ return () => {
682
+ document.removeEventListener("mouseover", handleMouseOver);
683
+ };
684
+ }, [mode, isLocked, dispatch]);
685
+ useEffect3(() => {
686
+ if (mode !== "inspecting") return;
687
+ const handleGlobalEsc = (e) => {
688
+ if (e.key === "Escape" && !isLocked) {
689
+ e.preventDefault();
690
+ e.stopPropagation();
691
+ dispatch({ type: "SET_MODE", payload: "disabled" });
692
+ }
693
+ };
694
+ document.addEventListener("keydown", handleGlobalEsc);
695
+ return () => document.removeEventListener("keydown", handleGlobalEsc);
696
+ }, [mode, isLocked, dispatch]);
697
+ useEffect3(() => {
698
+ if (mode === "disabled") {
699
+ setRect(null);
700
+ setShowInput(false);
701
+ setIsLocked(false);
702
+ setMousePos({ x: 0, y: 0 });
703
+ setLockedPos({ x: 0, y: 0 });
704
+ setIsCapturing(false);
705
+ setCaptureSuccess(false);
706
+ setShowDetails(false);
707
+ dispatch({ type: "RESET_HOVER" });
708
+ }
709
+ }, [mode, dispatch]);
710
+ useEffect3(() => {
711
+ if (!hoveredElement) {
712
+ setRect(null);
713
+ setShowInput(false);
714
+ setIsLocked(false);
715
+ return;
716
+ }
717
+ const updateRect = () => {
718
+ const newRect = hoveredElement.getBoundingClientRect();
719
+ setRect(newRect);
720
+ };
721
+ updateRect();
722
+ const handleMouseMove = (e) => {
723
+ if (!isLocked) {
724
+ setMousePos({ x: e.clientX, y: e.clientY });
725
+ }
726
+ };
727
+ const handleClick = (e) => {
728
+ const target = e.target;
729
+ if (target.closest("[data-annotation-tooltip]")) {
730
+ return;
731
+ }
732
+ if (target.closest("[data-ai-annotation-ui]")) {
733
+ return;
734
+ }
735
+ if (!isLocked) {
736
+ e.preventDefault();
737
+ e.stopPropagation();
738
+ setIsLocked(true);
739
+ setLockedPos({ x: e.clientX, y: e.clientY });
740
+ } else {
741
+ setIsLocked(false);
742
+ }
743
+ };
744
+ const handleKeyDown = (e) => {
745
+ if (e.key === "Escape" && isLocked) {
746
+ e.preventDefault();
747
+ e.stopPropagation();
748
+ setIsLocked(false);
749
+ setShowInput(false);
750
+ }
751
+ };
752
+ window.addEventListener("scroll", updateRect, true);
753
+ window.addEventListener("resize", updateRect);
754
+ document.addEventListener("mousemove", handleMouseMove);
755
+ document.addEventListener("click", handleClick, true);
756
+ document.addEventListener("keydown", handleKeyDown);
757
+ return () => {
758
+ window.removeEventListener("scroll", updateRect, true);
759
+ window.removeEventListener("resize", updateRect);
760
+ document.removeEventListener("mousemove", handleMouseMove);
761
+ document.removeEventListener("click", handleClick, true);
762
+ document.removeEventListener("keydown", handleKeyDown);
763
+ };
764
+ }, [hoveredElement, isLocked]);
765
+ const handleScreenshot = async (e) => {
766
+ e.stopPropagation();
767
+ if (!hoveredElement || isCapturing) return;
768
+ setIsCapturing(true);
769
+ try {
770
+ const result = await captureScreenshot(hoveredElement, {
771
+ copyToClipboard: true,
772
+ scale: 2
773
+ });
774
+ if (result.success) {
775
+ setCaptureSuccess(true);
776
+ setTimeout(() => {
777
+ setCaptureSuccess(false);
778
+ setIsLocked(false);
779
+ }, 1500);
780
+ }
781
+ } catch (error) {
782
+ console.error("Screenshot failed:", error);
783
+ } finally {
784
+ setIsCapturing(false);
785
+ }
786
+ };
787
+ const handleAddClick = (e) => {
788
+ e.stopPropagation();
789
+ setShowInput(true);
790
+ setShowDetails(false);
791
+ setIsLocked(false);
792
+ };
793
+ const handleDetailsClick = (e) => {
794
+ e.stopPropagation();
795
+ setShowDetails(!showDetails);
796
+ };
797
+ const handleCloseInput = () => {
798
+ setShowInput(false);
799
+ };
800
+ if (mode !== "inspecting" || !rect) return null;
801
+ const tooltipX = isLocked ? lockedPos.x : mousePos.x;
802
+ const tooltipY = isLocked ? lockedPos.y : mousePos.y;
803
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
804
+ /* @__PURE__ */ jsx4(
805
+ "div",
806
+ {
807
+ "data-annotation-ui": "true",
808
+ style: {
809
+ position: "fixed",
810
+ left: rect.left - 2,
811
+ top: rect.top - 2,
812
+ width: rect.width + 4,
813
+ height: rect.height + 4,
814
+ border: "2px solid #3b82f6",
815
+ borderRadius: 4,
816
+ pointerEvents: "none",
817
+ zIndex: 99998,
818
+ backgroundColor: "rgba(59, 130, 246, 0.1)"
819
+ }
820
+ }
821
+ ),
822
+ componentName && /* @__PURE__ */ jsx4(
823
+ "div",
824
+ {
825
+ "data-annotation-ui": "true",
826
+ style: {
827
+ position: "fixed",
828
+ left: rect.left,
829
+ top: rect.top - 24,
830
+ backgroundColor: "#3b82f6",
831
+ color: "white",
832
+ padding: "2px 8px",
833
+ borderRadius: 4,
834
+ fontSize: 12,
835
+ fontFamily: "monospace",
836
+ pointerEvents: "none",
837
+ zIndex: 99999
838
+ },
839
+ children: componentName
840
+ }
841
+ ),
842
+ !showInput && /* @__PURE__ */ jsxs2(
843
+ "div",
844
+ {
845
+ "data-annotation-ui": "true",
846
+ "data-annotation-tooltip": "true",
847
+ style: {
848
+ position: "fixed",
849
+ left: tooltipX + 16,
850
+ top: tooltipY + 16,
851
+ display: "flex",
852
+ flexDirection: "column",
853
+ gap: 6,
854
+ padding: 6,
855
+ backgroundColor: isLocked ? "rgba(0, 0, 0, 0.95)" : "rgba(0, 0, 0, 0.85)",
856
+ borderRadius: 8,
857
+ boxShadow: isLocked ? "0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 2px rgba(59, 130, 246, 0.5)" : "0 4px 12px rgba(0, 0, 0, 0.3)",
858
+ zIndex: 1e5,
859
+ pointerEvents: isLocked ? "auto" : "none",
860
+ backdropFilter: "blur(8px)",
861
+ transition: isLocked ? "none" : "left 0.05s ease-out, top 0.05s ease-out",
862
+ maxWidth: showDetails ? 400 : "auto"
863
+ },
864
+ children: [
865
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: 6 }, children: [
866
+ /* @__PURE__ */ jsx4(
867
+ "button",
868
+ {
869
+ onClick: handleScreenshot,
870
+ disabled: isCapturing || !isLocked,
871
+ style: {
872
+ width: 32,
873
+ height: 32,
874
+ borderRadius: 6,
875
+ border: "none",
876
+ backgroundColor: captureSuccess ? "#22c55e" : isCapturing ? "#6b7280" : "#8b5cf6",
877
+ color: "white",
878
+ cursor: isLocked ? "pointer" : "default",
879
+ display: "flex",
880
+ alignItems: "center",
881
+ justifyContent: "center",
882
+ fontSize: 16,
883
+ transition: "all 0.15s ease",
884
+ opacity: isLocked ? 1 : 0.7
885
+ },
886
+ title: "Capture screenshot",
887
+ children: captureSuccess ? "\u2713" : isCapturing ? "..." : "\u{1F4F7}"
888
+ }
889
+ ),
890
+ /* @__PURE__ */ jsx4(
891
+ "button",
892
+ {
893
+ onClick: handleAddClick,
894
+ disabled: !isLocked,
895
+ style: {
896
+ width: 32,
897
+ height: 32,
898
+ borderRadius: 6,
899
+ border: "none",
900
+ backgroundColor: "#3b82f6",
901
+ color: "white",
902
+ cursor: isLocked ? "pointer" : "default",
903
+ display: "flex",
904
+ alignItems: "center",
905
+ justifyContent: "center",
906
+ fontSize: 18,
907
+ fontWeight: "bold",
908
+ transition: "all 0.15s ease",
909
+ opacity: isLocked ? 1 : 0.7
910
+ },
911
+ title: "Add annotation",
912
+ children: "+"
913
+ }
914
+ ),
915
+ /* @__PURE__ */ jsx4(
916
+ "button",
917
+ {
918
+ onClick: handleDetailsClick,
919
+ disabled: !isLocked,
920
+ style: {
921
+ width: 32,
922
+ height: 32,
923
+ borderRadius: 6,
924
+ border: showDetails ? "2px solid #10b981" : "none",
925
+ backgroundColor: showDetails ? "#10b981" : "#6b7280",
926
+ color: "white",
927
+ cursor: isLocked ? "pointer" : "default",
928
+ display: "flex",
929
+ alignItems: "center",
930
+ justifyContent: "center",
931
+ fontSize: 14,
932
+ transition: "all 0.15s ease",
933
+ opacity: isLocked ? 1 : 0.7
934
+ },
935
+ title: "Show component details",
936
+ children: "\u24D8"
937
+ }
938
+ )
939
+ ] }),
940
+ !isLocked && /* @__PURE__ */ jsx4(
941
+ "div",
942
+ {
943
+ style: {
944
+ position: "absolute",
945
+ bottom: -20,
946
+ left: "50%",
947
+ transform: "translateX(-50%)",
948
+ fontSize: 10,
949
+ color: "rgba(255, 255, 255, 0.7)",
950
+ whiteSpace: "nowrap",
951
+ pointerEvents: "none"
952
+ },
953
+ children: "Click to lock"
954
+ }
955
+ ),
956
+ showDetails && componentDetails && /* @__PURE__ */ jsxs2(
957
+ "div",
958
+ {
959
+ style: {
960
+ padding: "8px 4px 4px 4px",
961
+ borderTop: "1px solid rgba(255, 255, 255, 0.2)",
962
+ fontSize: 11,
963
+ color: "rgba(255, 255, 255, 0.9)",
964
+ maxHeight: 300,
965
+ overflowY: "auto"
966
+ },
967
+ children: [
968
+ /* @__PURE__ */ jsxs2("div", { style: { marginBottom: 8 }, children: [
969
+ /* @__PURE__ */ jsx4("div", { style: { color: "#60a5fa", fontWeight: "bold", marginBottom: 4 }, children: "Element" }),
970
+ /* @__PURE__ */ jsxs2("div", { style: { fontFamily: "monospace", color: "#f59e0b" }, children: [
971
+ "<",
972
+ componentDetails.elementInfo.tagName,
973
+ componentDetails.elementInfo.id && ` id="${componentDetails.elementInfo.id}"`,
974
+ componentDetails.elementInfo.className && ` class="${componentDetails.elementInfo.className}"`,
975
+ ">"
976
+ ] }),
977
+ componentDetails.elementInfo.textContent && /* @__PURE__ */ jsxs2("div", { style: { color: "rgba(255, 255, 255, 0.6)", marginTop: 2, fontStyle: "italic" }, children: [
978
+ '"',
979
+ componentDetails.elementInfo.textContent,
980
+ '"'
981
+ ] }),
982
+ /* @__PURE__ */ jsxs2("div", { style: { color: "rgba(255, 255, 255, 0.5)", marginTop: 2 }, children: [
983
+ componentDetails.elementInfo.childElementCount,
984
+ " child element(s)"
985
+ ] })
986
+ ] }),
987
+ componentDetails.parentHierarchy.length > 0 && /* @__PURE__ */ jsxs2("div", { style: { marginBottom: 8 }, children: [
988
+ /* @__PURE__ */ jsx4("div", { style: { color: "#60a5fa", fontWeight: "bold", marginBottom: 4 }, children: "Parent Components" }),
989
+ /* @__PURE__ */ jsxs2("div", { style: { fontFamily: "monospace" }, children: [
990
+ componentDetails.parentHierarchy.slice(0, 5).map((parent, i) => /* @__PURE__ */ jsxs2("div", { style: { color: "#a78bfa", paddingLeft: i * 8 }, children: [
991
+ "\u2190 ",
992
+ parent
993
+ ] }, i)),
994
+ componentDetails.parentHierarchy.length > 5 && /* @__PURE__ */ jsxs2("div", { style: { color: "rgba(255, 255, 255, 0.5)" }, children: [
995
+ "... and ",
996
+ componentDetails.parentHierarchy.length - 5,
997
+ " more"
998
+ ] })
999
+ ] })
1000
+ ] }),
1001
+ componentDetails.childComponents.length > 0 && /* @__PURE__ */ jsxs2("div", { style: { marginBottom: 8 }, children: [
1002
+ /* @__PURE__ */ jsxs2("div", { style: { color: "#60a5fa", fontWeight: "bold", marginBottom: 4 }, children: [
1003
+ "Child Components (",
1004
+ componentDetails.childComponents.length,
1005
+ ")"
1006
+ ] }),
1007
+ /* @__PURE__ */ jsxs2("div", { style: { fontFamily: "monospace" }, children: [
1008
+ componentDetails.childComponents.slice(0, 10).map((child, i) => /* @__PURE__ */ jsxs2(
1009
+ "div",
1010
+ {
1011
+ style: {
1012
+ display: "flex",
1013
+ justifyContent: "space-between",
1014
+ gap: 8,
1015
+ color: "#34d399"
1016
+ },
1017
+ children: [
1018
+ /* @__PURE__ */ jsxs2("span", { children: [
1019
+ "\u2192 ",
1020
+ child.name,
1021
+ child.hasChildren && " \u25BE"
1022
+ ] }),
1023
+ child.count > 1 && /* @__PURE__ */ jsxs2("span", { style: { color: "rgba(255, 255, 255, 0.5)" }, children: [
1024
+ "\xD7",
1025
+ child.count
1026
+ ] })
1027
+ ]
1028
+ },
1029
+ i
1030
+ )),
1031
+ componentDetails.childComponents.length > 10 && /* @__PURE__ */ jsxs2("div", { style: { color: "rgba(255, 255, 255, 0.5)" }, children: [
1032
+ "... and ",
1033
+ componentDetails.childComponents.length - 10,
1034
+ " more"
1035
+ ] })
1036
+ ] })
1037
+ ] }),
1038
+ Object.keys(componentDetails.elementInfo.attributes).length > 0 && /* @__PURE__ */ jsxs2("div", { children: [
1039
+ /* @__PURE__ */ jsx4("div", { style: { color: "#60a5fa", fontWeight: "bold", marginBottom: 4 }, children: "Attributes" }),
1040
+ /* @__PURE__ */ jsx4("div", { style: { fontFamily: "monospace" }, children: Object.entries(componentDetails.elementInfo.attributes).map(([key, value]) => /* @__PURE__ */ jsxs2("div", { style: { color: "#fbbf24" }, children: [
1041
+ key,
1042
+ '="',
1043
+ value,
1044
+ '"'
1045
+ ] }, key)) })
1046
+ ] })
1047
+ ]
1048
+ }
1049
+ )
1050
+ ]
1051
+ }
1052
+ ),
1053
+ showInput && /* @__PURE__ */ jsx4(
1054
+ AnnotationInput,
1055
+ {
1056
+ onClose: handleCloseInput,
1057
+ componentName: componentName || "Unknown",
1058
+ componentDetails
1059
+ }
1060
+ )
1061
+ ] });
1062
+ }
1063
+
1064
+ // src/components/AnnotationList.tsx
1065
+ import { useState as useState4 } from "react";
1066
+ import { X as X2, Trash2, Trash, ChevronDown, ChevronRight } from "lucide-react";
1067
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1068
+ function AnnotationList() {
1069
+ const { state, dispatch } = useAgentAnnotation();
1070
+ const [expandedId, setExpandedId] = useState4(null);
1071
+ if (!state.showList) return null;
1072
+ const toggleExpand = (id) => {
1073
+ setExpandedId(expandedId === id ? null : id);
1074
+ };
1075
+ return /* @__PURE__ */ jsx5(
1076
+ "div",
1077
+ {
1078
+ style: {
1079
+ position: "fixed",
1080
+ top: 0,
1081
+ left: 0,
1082
+ right: 0,
1083
+ bottom: 0,
1084
+ backgroundColor: "rgba(0,0,0,0.5)",
1085
+ display: "flex",
1086
+ alignItems: "center",
1087
+ justifyContent: "center",
1088
+ zIndex: 1e4
1089
+ },
1090
+ "data-ai-annotation-ui": true,
1091
+ onClick: () => dispatch({ type: "TOGGLE_LIST" }),
1092
+ children: /* @__PURE__ */ jsxs3(
1093
+ "div",
1094
+ {
1095
+ style: {
1096
+ backgroundColor: "#1e1e1e",
1097
+ color: "#e5e7eb",
1098
+ padding: "20px",
1099
+ borderRadius: "8px",
1100
+ width: "600px",
1101
+ maxWidth: "90%",
1102
+ maxHeight: "80vh",
1103
+ display: "flex",
1104
+ flexDirection: "column",
1105
+ boxShadow: "0 4px 6px rgba(0,0,0,0.3)"
1106
+ },
1107
+ onClick: (e) => e.stopPropagation(),
1108
+ children: [
1109
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "16px", alignItems: "center" }, children: [
1110
+ /* @__PURE__ */ jsxs3("h3", { style: { margin: 0 }, children: [
1111
+ "Annotations (",
1112
+ state.annotations.length,
1113
+ ")"
1114
+ ] }),
1115
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1116
+ state.annotations.length > 0 && /* @__PURE__ */ jsxs3(
1117
+ "button",
1118
+ {
1119
+ onClick: () => dispatch({ type: "CLEAR_ALL_ANNOTATIONS" }),
1120
+ style: {
1121
+ background: "#ef4444",
1122
+ border: "none",
1123
+ color: "white",
1124
+ cursor: "pointer",
1125
+ padding: "6px 12px",
1126
+ borderRadius: "4px",
1127
+ fontSize: "12px",
1128
+ display: "flex",
1129
+ alignItems: "center",
1130
+ gap: "4px"
1131
+ },
1132
+ title: "Clear all annotations",
1133
+ children: [
1134
+ /* @__PURE__ */ jsx5(Trash, { size: 14 }),
1135
+ "Clear All"
1136
+ ]
1137
+ }
1138
+ ),
1139
+ /* @__PURE__ */ jsx5(
1140
+ "button",
1141
+ {
1142
+ onClick: () => dispatch({ type: "TOGGLE_LIST" }),
1143
+ style: { background: "none", border: "none", color: "inherit", cursor: "pointer" },
1144
+ children: /* @__PURE__ */ jsx5(X2, { size: 20 })
1145
+ }
1146
+ )
1147
+ ] })
1148
+ ] }),
1149
+ /* @__PURE__ */ jsx5("div", { style: { overflowY: "auto", flex: 1, display: "flex", flexDirection: "column", gap: "8px" }, children: state.annotations.length === 0 ? /* @__PURE__ */ jsx5("p", { style: { textAlign: "center", opacity: 0.6, padding: "20px" }, children: "No annotations yet." }) : state.annotations.map((ann) => {
1150
+ const isExpanded = expandedId === ann.id;
1151
+ const hasDetails = !!ann.details;
1152
+ return /* @__PURE__ */ jsxs3(
1153
+ "div",
1154
+ {
1155
+ style: {
1156
+ backgroundColor: "#2d2d2d",
1157
+ borderRadius: "4px",
1158
+ overflow: "hidden"
1159
+ },
1160
+ children: [
1161
+ /* @__PURE__ */ jsxs3(
1162
+ "div",
1163
+ {
1164
+ style: {
1165
+ padding: "12px",
1166
+ display: "flex",
1167
+ justifyContent: "space-between",
1168
+ alignItems: "flex-start",
1169
+ gap: "12px"
1170
+ },
1171
+ children: [
1172
+ /* @__PURE__ */ jsxs3("div", { style: { flex: 1 }, children: [
1173
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "4px" }, children: [
1174
+ hasDetails && /* @__PURE__ */ jsx5(
1175
+ "button",
1176
+ {
1177
+ onClick: () => toggleExpand(ann.id),
1178
+ style: {
1179
+ background: "none",
1180
+ border: "none",
1181
+ color: "#60a5fa",
1182
+ cursor: "pointer",
1183
+ padding: 0,
1184
+ display: "flex",
1185
+ alignItems: "center"
1186
+ },
1187
+ children: isExpanded ? /* @__PURE__ */ jsx5(ChevronDown, { size: 16 }) : /* @__PURE__ */ jsx5(ChevronRight, { size: 16 })
1188
+ }
1189
+ ),
1190
+ /* @__PURE__ */ jsx5("div", { style: { fontWeight: "bold", fontSize: "0.9rem", color: "#60a5fa" }, children: ann.componentName })
1191
+ ] }),
1192
+ /* @__PURE__ */ jsx5("div", { style: { fontSize: "0.9rem", whiteSpace: "pre-wrap", marginLeft: hasDetails ? 24 : 0 }, children: ann.note })
1193
+ ] }),
1194
+ /* @__PURE__ */ jsx5(
1195
+ "button",
1196
+ {
1197
+ onClick: () => dispatch({ type: "REMOVE_ANNOTATION", payload: ann.id }),
1198
+ style: {
1199
+ background: "none",
1200
+ border: "none",
1201
+ color: "#ef4444",
1202
+ cursor: "pointer",
1203
+ padding: "4px",
1204
+ flexShrink: 0
1205
+ },
1206
+ title: "Remove annotation",
1207
+ children: /* @__PURE__ */ jsx5(Trash2, { size: 16 })
1208
+ }
1209
+ )
1210
+ ]
1211
+ }
1212
+ ),
1213
+ isExpanded && ann.details && /* @__PURE__ */ jsxs3(
1214
+ "div",
1215
+ {
1216
+ style: {
1217
+ padding: "12px",
1218
+ paddingTop: 0,
1219
+ borderTop: "1px solid #404040",
1220
+ marginTop: "8px",
1221
+ fontSize: "0.8rem"
1222
+ },
1223
+ children: [
1224
+ /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "12px" }, children: [
1225
+ /* @__PURE__ */ jsx5("div", { style: { color: "#10b981", fontWeight: "bold", marginBottom: "4px" }, children: "Element" }),
1226
+ /* @__PURE__ */ jsxs3("div", { style: { fontFamily: "monospace", color: "#f59e0b", fontSize: "0.75rem" }, children: [
1227
+ "<",
1228
+ ann.details.elementInfo.tagName,
1229
+ ann.details.elementInfo.id && ` id="${ann.details.elementInfo.id}"`,
1230
+ ann.details.elementInfo.className && ` class="${ann.details.elementInfo.className}"`,
1231
+ ">"
1232
+ ] }),
1233
+ ann.details.elementInfo.textContent && /* @__PURE__ */ jsxs3("div", { style: { color: "rgba(255, 255, 255, 0.6)", marginTop: "4px", fontStyle: "italic" }, children: [
1234
+ 'Text: "',
1235
+ ann.details.elementInfo.textContent,
1236
+ '"'
1237
+ ] })
1238
+ ] }),
1239
+ ann.details.parentHierarchy.length > 0 && /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "12px" }, children: [
1240
+ /* @__PURE__ */ jsx5("div", { style: { color: "#10b981", fontWeight: "bold", marginBottom: "4px" }, children: "Parent Components" }),
1241
+ /* @__PURE__ */ jsx5("div", { style: { fontFamily: "monospace", fontSize: "0.75rem" }, children: ann.details.parentHierarchy.map((parent, i) => /* @__PURE__ */ jsxs3("span", { style: { color: "#a78bfa" }, children: [
1242
+ i > 0 && " \u2192 ",
1243
+ parent
1244
+ ] }, i)) })
1245
+ ] }),
1246
+ ann.details.childComponents.length > 0 && /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "12px" }, children: [
1247
+ /* @__PURE__ */ jsxs3("div", { style: { color: "#10b981", fontWeight: "bold", marginBottom: "4px" }, children: [
1248
+ "Child Components (",
1249
+ ann.details.childComponents.length,
1250
+ ")"
1251
+ ] }),
1252
+ /* @__PURE__ */ jsx5("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: ann.details.childComponents.map((child, i) => /* @__PURE__ */ jsxs3(
1253
+ "span",
1254
+ {
1255
+ style: {
1256
+ backgroundColor: "#374151",
1257
+ padding: "2px 8px",
1258
+ borderRadius: "4px",
1259
+ fontFamily: "monospace",
1260
+ fontSize: "0.75rem",
1261
+ color: "#34d399"
1262
+ },
1263
+ children: [
1264
+ child.name,
1265
+ child.count > 1 && ` \xD7${child.count}`,
1266
+ child.hasChildren && " \u25BE"
1267
+ ]
1268
+ },
1269
+ i
1270
+ )) })
1271
+ ] }),
1272
+ Object.keys(ann.details.elementInfo.attributes).length > 0 && /* @__PURE__ */ jsxs3("div", { children: [
1273
+ /* @__PURE__ */ jsx5("div", { style: { color: "#10b981", fontWeight: "bold", marginBottom: "4px" }, children: "Attributes" }),
1274
+ /* @__PURE__ */ jsx5("div", { style: { fontFamily: "monospace", fontSize: "0.75rem" }, children: Object.entries(ann.details.elementInfo.attributes).map(([key, value]) => /* @__PURE__ */ jsxs3("div", { style: { color: "#fbbf24" }, children: [
1275
+ key,
1276
+ '="',
1277
+ value,
1278
+ '"'
1279
+ ] }, key)) })
1280
+ ] })
1281
+ ]
1282
+ }
1283
+ )
1284
+ ]
1285
+ },
1286
+ ann.id
1287
+ );
1288
+ }) })
1289
+ ]
1290
+ }
1291
+ )
1292
+ }
1293
+ );
1294
+ }
1295
+
1296
+ // src/components/Toolbar.tsx
1297
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1298
+ function Toolbar() {
1299
+ const { state, dispatch } = useAgentAnnotation();
1300
+ const [showCopied, setShowCopied] = useState5(false);
1301
+ const [isAnimating, setIsAnimating] = useState5(false);
1302
+ const contentRef = useRef2(null);
1303
+ const [contentWidth, setContentWidth] = useState5(null);
1304
+ useEffect4(() => {
1305
+ if (contentRef.current && !state.isMinimized) {
1306
+ requestAnimationFrame(() => {
1307
+ if (contentRef.current) {
1308
+ setContentWidth(contentRef.current.scrollWidth);
1309
+ }
1310
+ });
1311
+ }
1312
+ }, [state.isMinimized, showCopied, state.annotations.length]);
1313
+ const handleToggleMinimized = () => {
1314
+ setIsAnimating(true);
1315
+ dispatch({ type: "TOGGLE_MINIMIZED" });
1316
+ setTimeout(() => setIsAnimating(false), 300);
1317
+ };
1318
+ const handleCopy = () => {
1319
+ if (state.annotations.length === 0) return;
1320
+ const sections = state.annotations.map((a, index) => {
1321
+ const lines = [];
1322
+ lines.push(`${"=".repeat(50)}`);
1323
+ lines.push(`Annotation ${index + 1}`);
1324
+ lines.push(`Component: ${a.componentName}`);
1325
+ lines.push(`${"=".repeat(50)}`);
1326
+ lines.push("");
1327
+ lines.push("## Instruction");
1328
+ lines.push(a.note);
1329
+ return lines.join("\n");
1330
+ });
1331
+ const text = sections.join("\n\n");
1332
+ navigator.clipboard.writeText(text).then(() => {
1333
+ setShowCopied(true);
1334
+ setTimeout(() => setShowCopied(false), 2e3);
1335
+ });
1336
+ };
1337
+ const toggleMode = () => {
1338
+ dispatch({
1339
+ type: "SET_MODE",
1340
+ payload: state.mode === "disabled" ? "inspecting" : "disabled"
1341
+ });
1342
+ };
1343
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1344
+ /* @__PURE__ */ jsx6(Highlighter, {}),
1345
+ /* @__PURE__ */ jsx6(AnnotationList, {}),
1346
+ /* @__PURE__ */ jsx6(Draggable, { children: /* @__PURE__ */ jsxs4(
1347
+ "div",
1348
+ {
1349
+ style: {
1350
+ backgroundColor: "#1e1e1e",
1351
+ border: "1px solid #333",
1352
+ borderRadius: "8px",
1353
+ padding: "8px",
1354
+ boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
1355
+ display: "flex",
1356
+ alignItems: "center",
1357
+ gap: "8px",
1358
+ color: "#e5e7eb",
1359
+ transition: "width 0.2s"
1360
+ },
1361
+ "data-ai-annotation-ui": true,
1362
+ children: [
1363
+ /* @__PURE__ */ jsx6("div", { style: { cursor: "grab", color: "#666", display: "flex" }, title: "Drag", children: /* @__PURE__ */ jsx6(GripVertical, { size: 20 }) }),
1364
+ /* @__PURE__ */ jsx6(
1365
+ "div",
1366
+ {
1367
+ ref: contentRef,
1368
+ style: {
1369
+ display: "flex",
1370
+ alignItems: "center",
1371
+ gap: "8px",
1372
+ overflow: "hidden",
1373
+ transition: "max-width 0.3s ease, opacity 0.2s ease",
1374
+ maxWidth: state.isMinimized ? 0 : contentWidth || 300,
1375
+ opacity: state.isMinimized ? 0 : 1,
1376
+ paddingTop: "4px",
1377
+ paddingBottom: "4px",
1378
+ marginTop: "-4px",
1379
+ marginBottom: "-4px"
1380
+ },
1381
+ children: /* @__PURE__ */ jsxs4(Fragment2, { children: [
1382
+ /* @__PURE__ */ jsx6("div", { style: { width: "1px", height: "24px", backgroundColor: "#333" } }),
1383
+ /* @__PURE__ */ jsx6(
1384
+ "button",
1385
+ {
1386
+ onClick: toggleMode,
1387
+ title: state.mode === "inspecting" ? "Disable Inspection" : "Enable Inspection",
1388
+ style: {
1389
+ background: state.mode === "inspecting" ? "#3b82f6" : "transparent",
1390
+ border: "none",
1391
+ borderRadius: "4px",
1392
+ padding: "6px",
1393
+ color: state.mode === "inspecting" ? "white" : "inherit",
1394
+ cursor: "pointer",
1395
+ display: "flex"
1396
+ },
1397
+ children: state.mode === "inspecting" ? /* @__PURE__ */ jsx6(MousePointer2, { size: 18 }) : /* @__PURE__ */ jsx6(Ban, { size: 18 })
1398
+ }
1399
+ ),
1400
+ /* @__PURE__ */ jsxs4(
1401
+ "button",
1402
+ {
1403
+ onClick: () => dispatch({ type: "TOGGLE_LIST" }),
1404
+ title: "List Annotations",
1405
+ style: {
1406
+ background: "transparent",
1407
+ border: "none",
1408
+ borderRadius: "4px",
1409
+ padding: "6px",
1410
+ color: "inherit",
1411
+ cursor: "pointer",
1412
+ display: "flex",
1413
+ position: "relative"
1414
+ },
1415
+ children: [
1416
+ /* @__PURE__ */ jsx6(List, { size: 18 }),
1417
+ state.annotations.length > 0 && /* @__PURE__ */ jsx6("span", { style: {
1418
+ position: "absolute",
1419
+ top: -2,
1420
+ right: -2,
1421
+ background: "#ef4444",
1422
+ color: "white",
1423
+ fontSize: "9px",
1424
+ width: "14px",
1425
+ height: "14px",
1426
+ borderRadius: "50%",
1427
+ display: "flex",
1428
+ alignItems: "center",
1429
+ justifyContent: "center"
1430
+ }, children: state.annotations.length })
1431
+ ]
1432
+ }
1433
+ ),
1434
+ /* @__PURE__ */ jsx6(
1435
+ "button",
1436
+ {
1437
+ onClick: handleCopy,
1438
+ title: "Copy Annotations",
1439
+ style: {
1440
+ background: showCopied ? "#22c55e" : "transparent",
1441
+ border: "none",
1442
+ borderRadius: "4px",
1443
+ padding: "6px",
1444
+ color: showCopied ? "white" : "inherit",
1445
+ cursor: "pointer",
1446
+ display: "flex",
1447
+ alignItems: "center",
1448
+ gap: "4px",
1449
+ transition: "background-color 0.2s, color 0.2s",
1450
+ minWidth: showCopied ? "75px" : "auto"
1451
+ },
1452
+ children: showCopied ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
1453
+ /* @__PURE__ */ jsx6(Check, { size: 18 }),
1454
+ /* @__PURE__ */ jsx6("span", { style: { fontSize: "12px", whiteSpace: "nowrap" }, children: "Copied!" })
1455
+ ] }) : /* @__PURE__ */ jsx6(Copy, { size: 18 })
1456
+ }
1457
+ )
1458
+ ] })
1459
+ }
1460
+ ),
1461
+ /* @__PURE__ */ jsx6("div", { style: { width: "1px", height: "24px", backgroundColor: "#333", marginLeft: state.isMinimized ? 0 : "auto" } }),
1462
+ /* @__PURE__ */ jsx6(
1463
+ "button",
1464
+ {
1465
+ onClick: handleToggleMinimized,
1466
+ title: state.isMinimized ? "Expand" : "Minimize",
1467
+ style: {
1468
+ background: "transparent",
1469
+ border: "none",
1470
+ borderRadius: "4px",
1471
+ padding: "6px",
1472
+ color: "inherit",
1473
+ cursor: "pointer",
1474
+ display: "flex"
1475
+ },
1476
+ children: state.isMinimized ? /* @__PURE__ */ jsx6(Maximize2, { size: 18 }) : /* @__PURE__ */ jsx6(Minus, { size: 18 })
1477
+ }
1478
+ )
1479
+ ]
1480
+ }
1481
+ ) })
1482
+ ] });
1483
+ }
1484
+
1485
+ // src/components/ErrorBoundary.tsx
1486
+ import { Component } from "react";
1487
+ import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1488
+ var defaultStyles = {
1489
+ container: {
1490
+ display: "flex",
1491
+ flexDirection: "column",
1492
+ alignItems: "center",
1493
+ justifyContent: "center",
1494
+ minHeight: "100vh",
1495
+ padding: "24px",
1496
+ backgroundColor: "#1e1e1e",
1497
+ color: "#e5e7eb",
1498
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
1499
+ },
1500
+ content: {
1501
+ maxWidth: "600px",
1502
+ width: "100%",
1503
+ textAlign: "center"
1504
+ },
1505
+ icon: {
1506
+ fontSize: "48px",
1507
+ marginBottom: "16px"
1508
+ },
1509
+ title: {
1510
+ fontSize: "24px",
1511
+ fontWeight: 600,
1512
+ marginBottom: "8px",
1513
+ color: "#f87171"
1514
+ },
1515
+ subtitle: {
1516
+ fontSize: "16px",
1517
+ color: "#9ca3af",
1518
+ marginBottom: "24px"
1519
+ },
1520
+ errorBox: {
1521
+ backgroundColor: "#2d2d2d",
1522
+ border: "1px solid #404040",
1523
+ borderRadius: "8px",
1524
+ padding: "16px",
1525
+ marginBottom: "24px",
1526
+ textAlign: "left",
1527
+ maxHeight: "200px",
1528
+ overflow: "auto"
1529
+ },
1530
+ errorText: {
1531
+ fontFamily: "monospace",
1532
+ fontSize: "12px",
1533
+ color: "#f87171",
1534
+ whiteSpace: "pre-wrap",
1535
+ wordBreak: "break-word",
1536
+ margin: 0
1537
+ },
1538
+ buttonContainer: {
1539
+ display: "flex",
1540
+ gap: "12px",
1541
+ justifyContent: "center",
1542
+ flexWrap: "wrap"
1543
+ },
1544
+ button: {
1545
+ padding: "10px 20px",
1546
+ borderRadius: "6px",
1547
+ border: "none",
1548
+ fontSize: "14px",
1549
+ fontWeight: 500,
1550
+ cursor: "pointer",
1551
+ transition: "all 0.2s"
1552
+ },
1553
+ primaryButton: {
1554
+ backgroundColor: "#3b82f6",
1555
+ color: "white"
1556
+ },
1557
+ secondaryButton: {
1558
+ backgroundColor: "#404040",
1559
+ color: "#e5e7eb"
1560
+ },
1561
+ successButton: {
1562
+ backgroundColor: "#22c55e",
1563
+ color: "white"
1564
+ }
1565
+ };
1566
+ var ErrorBoundary = class extends Component {
1567
+ constructor(props) {
1568
+ super(props);
1569
+ __publicField(this, "handleReset", () => {
1570
+ this.props.onReset?.();
1571
+ this.setState({
1572
+ hasError: false,
1573
+ error: null,
1574
+ errorInfo: null,
1575
+ copied: false
1576
+ });
1577
+ });
1578
+ __publicField(this, "handleCopyToClipboard", async () => {
1579
+ const text = this.formatError();
1580
+ try {
1581
+ await navigator.clipboard.writeText(text);
1582
+ this.setState({ copied: true });
1583
+ setTimeout(() => this.setState({ copied: false }), 2e3);
1584
+ } catch (err) {
1585
+ console.error("Failed to copy error details:", err);
1586
+ }
1587
+ });
1588
+ this.state = {
1589
+ hasError: false,
1590
+ error: null,
1591
+ errorInfo: null,
1592
+ copied: false
1593
+ };
1594
+ }
1595
+ static getDerivedStateFromError(error) {
1596
+ return { hasError: true, error };
1597
+ }
1598
+ componentDidCatch(error, errorInfo) {
1599
+ this.setState({ errorInfo });
1600
+ this.props.onError?.(error, errorInfo);
1601
+ }
1602
+ formatError() {
1603
+ const { error, errorInfo } = this.state;
1604
+ if (!error) return "";
1605
+ const lines = [
1606
+ "=".repeat(50),
1607
+ "ERROR REPORT",
1608
+ "=".repeat(50),
1609
+ "",
1610
+ `Error: ${error.name}`,
1611
+ `Message: ${error.message}`,
1612
+ "",
1613
+ "Stack Trace:",
1614
+ error.stack || "No stack trace available"
1615
+ ];
1616
+ if (errorInfo?.componentStack) {
1617
+ lines.push("", "Component Stack:", errorInfo.componentStack);
1618
+ }
1619
+ lines.push("", `Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}`);
1620
+ lines.push(`User Agent: ${typeof navigator !== "undefined" ? navigator.userAgent : "N/A"}`);
1621
+ return lines.join("\n");
1622
+ }
1623
+ getErrorInfo() {
1624
+ return {
1625
+ error: this.state.error,
1626
+ errorInfo: this.state.errorInfo,
1627
+ formattedError: this.formatError(),
1628
+ reset: this.handleReset
1629
+ };
1630
+ }
1631
+ renderDefaultFallback() {
1632
+ const {
1633
+ title = "Something went wrong",
1634
+ subtitle = "An unexpected error occurred",
1635
+ showErrorDetails = true,
1636
+ showCopyButton = true,
1637
+ showRetryButton = true,
1638
+ retryButtonLabel = "Try Again",
1639
+ copyButtonLabel = "Copy Error Details",
1640
+ customButtons = [],
1641
+ containerStyle,
1642
+ errorDetailsStyle
1643
+ } = this.props;
1644
+ const { error, copied } = this.state;
1645
+ const errorInfo = this.getErrorInfo();
1646
+ return /* @__PURE__ */ jsx7("div", { style: { ...defaultStyles.container, ...containerStyle }, children: /* @__PURE__ */ jsxs5("div", { style: defaultStyles.content, children: [
1647
+ /* @__PURE__ */ jsx7("div", { style: defaultStyles.icon, children: "\u26A0\uFE0F" }),
1648
+ /* @__PURE__ */ jsx7("h1", { style: defaultStyles.title, children: title }),
1649
+ /* @__PURE__ */ jsx7("p", { style: defaultStyles.subtitle, children: subtitle }),
1650
+ showErrorDetails && error && /* @__PURE__ */ jsx7("div", { style: { ...defaultStyles.errorBox, ...errorDetailsStyle }, children: /* @__PURE__ */ jsxs5("pre", { style: defaultStyles.errorText, children: [
1651
+ error.name,
1652
+ ": ",
1653
+ error.message,
1654
+ error.stack && `
1655
+
1656
+ ${error.stack.split("\n").slice(1, 5).join("\n")}`
1657
+ ] }) }),
1658
+ /* @__PURE__ */ jsxs5("div", { style: defaultStyles.buttonContainer, children: [
1659
+ showRetryButton && /* @__PURE__ */ jsx7(
1660
+ "button",
1661
+ {
1662
+ onClick: this.handleReset,
1663
+ style: { ...defaultStyles.button, ...defaultStyles.primaryButton },
1664
+ children: retryButtonLabel
1665
+ }
1666
+ ),
1667
+ showCopyButton && /* @__PURE__ */ jsx7(
1668
+ "button",
1669
+ {
1670
+ onClick: this.handleCopyToClipboard,
1671
+ style: {
1672
+ ...defaultStyles.button,
1673
+ ...copied ? defaultStyles.successButton : defaultStyles.secondaryButton
1674
+ },
1675
+ children: copied ? "\u2713 Copied!" : copyButtonLabel
1676
+ }
1677
+ ),
1678
+ customButtons.map((btn, index) => /* @__PURE__ */ jsx7(
1679
+ "button",
1680
+ {
1681
+ onClick: () => btn.onClick(errorInfo),
1682
+ style: { ...defaultStyles.button, ...defaultStyles.secondaryButton, ...btn.style },
1683
+ className: btn.className,
1684
+ children: btn.label
1685
+ },
1686
+ index
1687
+ ))
1688
+ ] })
1689
+ ] }) });
1690
+ }
1691
+ render() {
1692
+ const { hasError } = this.state;
1693
+ const { children, fallback: FallbackComponent, fallbackElement } = this.props;
1694
+ if (hasError) {
1695
+ if (FallbackComponent) {
1696
+ const errorInfo = this.getErrorInfo();
1697
+ return /* @__PURE__ */ jsx7(
1698
+ FallbackComponent,
1699
+ {
1700
+ ...errorInfo,
1701
+ copyToClipboard: this.handleCopyToClipboard
1702
+ }
1703
+ );
1704
+ }
1705
+ if (fallbackElement) {
1706
+ return /* @__PURE__ */ jsx7(Fragment3, { children: fallbackElement });
1707
+ }
1708
+ return this.renderDefaultFallback();
1709
+ }
1710
+ return children;
1711
+ }
1712
+ };
1713
+
1714
+ // src/utils/platform.ts
1715
+ var isWeb = typeof document !== "undefined" && typeof window !== "undefined";
1716
+ var isNative = !isWeb && typeof global !== "undefined";
1717
+ function getPlatform() {
1718
+ if (isWeb) return "web";
1719
+ try {
1720
+ const { Platform } = __require("react-native");
1721
+ if (Platform.OS === "ios") return "ios";
1722
+ if (Platform.OS === "android") return "android";
1723
+ return "native";
1724
+ } catch {
1725
+ return "native";
1726
+ }
1727
+ }
1728
+ function isTauriEnv2() {
1729
+ return isWeb && typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
1730
+ }
1731
+
1732
+ // src/index.tsx
1733
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1734
+ function AgentAnnotationProvider2({ children }) {
1735
+ return /* @__PURE__ */ jsxs6(AgentAnnotationProvider, { children: [
1736
+ children,
1737
+ /* @__PURE__ */ jsx8(Toolbar, {})
1738
+ ] });
1739
+ }
1740
+ export {
1741
+ AgentAnnotationProvider2 as AgentAnnotationProvider,
1742
+ AnnotationInput,
1743
+ AnnotationList,
1744
+ Draggable,
1745
+ ErrorBoundary,
1746
+ Highlighter,
1747
+ Toolbar,
1748
+ captureScreenshot,
1749
+ getComponentDisplayName,
1750
+ getElementFromFiber,
1751
+ getPlatform,
1752
+ getReactFiber,
1753
+ isNative,
1754
+ isTauriEnv2 as isTauriEnv,
1755
+ isWeb,
1756
+ useAgentAnnotation
1757
+ };
1758
+ //# sourceMappingURL=index.js.map