agentation 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,9 +33,78 @@ The toolbar appears in the bottom-right corner. Click to activate, then click an
33
33
  - **Area selection** – Drag to annotate any region, even empty space
34
34
  - **Animation pause** – Freeze CSS animations to capture specific states
35
35
  - **Structured output** – Copy markdown with selectors, positions, and context
36
+ - **Programmatic access** – Callback prop for direct integration with tools
36
37
  - **Dark/light mode** – Matches your preference or set manually
37
38
  - **Zero dependencies** – Pure CSS animations, no runtime libraries
38
39
 
40
+ ## Props
41
+
42
+ | Prop | Type | Default | Description |
43
+ |------|------|---------|-------------|
44
+ | `onAnnotationAdd` | `(annotation: Annotation) => void` | - | Called when an annotation is created |
45
+ | `onAnnotationDelete` | `(annotation: Annotation) => void` | - | Called when an annotation is deleted |
46
+ | `onAnnotationUpdate` | `(annotation: Annotation) => void` | - | Called when an annotation is edited |
47
+ | `onAnnotationsClear` | `(annotations: Annotation[]) => void` | - | Called when all annotations are cleared |
48
+ | `onCopy` | `(markdown: string) => void` | - | Callback with markdown output when copy is clicked |
49
+ | `copyToClipboard` | `boolean` | `true` | Set to false to prevent writing to clipboard |
50
+
51
+ ### Programmatic Integration
52
+
53
+ Use callbacks to receive annotation data directly:
54
+
55
+ ```tsx
56
+ import { Agentation, type Annotation } from 'agentation';
57
+
58
+ function App() {
59
+ const handleAnnotation = (annotation: Annotation) => {
60
+ // Structured data - no parsing needed
61
+ console.log(annotation.element); // "Button"
62
+ console.log(annotation.elementPath); // "body > div > button"
63
+ console.log(annotation.boundingBox); // { x, y, width, height }
64
+ console.log(annotation.cssClasses); // "btn btn-primary"
65
+
66
+ // Send to your agent, API, etc.
67
+ sendToAgent(annotation);
68
+ };
69
+
70
+ return (
71
+ <>
72
+ <YourApp />
73
+ <Agentation
74
+ onAnnotationAdd={handleAnnotation}
75
+ copyToClipboard={false} // Don't write to clipboard
76
+ />
77
+ </>
78
+ );
79
+ }
80
+ ```
81
+
82
+ ### Annotation Type
83
+
84
+ ```typescript
85
+ type Annotation = {
86
+ id: string;
87
+ x: number; // % of viewport width
88
+ y: number; // px from top (viewport if fixed)
89
+ comment: string; // User's note
90
+ element: string; // e.g., "Button"
91
+ elementPath: string; // e.g., "body > div > button"
92
+ timestamp: number;
93
+
94
+ // Optional metadata (when available)
95
+ selectedText?: string;
96
+ boundingBox?: { x: number; y: number; width: number; height: number };
97
+ nearbyText?: string;
98
+ cssClasses?: string;
99
+ nearbyElements?: string;
100
+ computedStyles?: string;
101
+ fullPath?: string;
102
+ accessibility?: string;
103
+ isMultiSelect?: boolean;
104
+ isFixed?: boolean;
105
+ };
106
+ ```
107
+
39
108
  ## How it works
40
109
 
41
110
  Agentation captures class names, selectors, and element positions so AI agents can `grep` for the exact code you're referring to. Instead of describing "the blue button in the sidebar," you give the agent `.sidebar > button.primary` and your feedback.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,31 @@
1
1
  import * as react from 'react';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
 
4
+ type Annotation = {
5
+ id: string;
6
+ x: number;
7
+ y: number;
8
+ comment: string;
9
+ element: string;
10
+ elementPath: string;
11
+ timestamp: number;
12
+ selectedText?: string;
13
+ boundingBox?: {
14
+ x: number;
15
+ y: number;
16
+ width: number;
17
+ height: number;
18
+ };
19
+ nearbyText?: string;
20
+ cssClasses?: string;
21
+ nearbyElements?: string;
22
+ computedStyles?: string;
23
+ fullPath?: string;
24
+ accessibility?: string;
25
+ isMultiSelect?: boolean;
26
+ isFixed?: boolean;
27
+ };
28
+
4
29
  type DemoAnnotation = {
5
30
  selector: string;
6
31
  comment: string;
@@ -10,8 +35,22 @@ type PageFeedbackToolbarCSSProps = {
10
35
  demoAnnotations?: DemoAnnotation[];
11
36
  demoDelay?: number;
12
37
  enableDemoMode?: boolean;
38
+ /** Callback fired when an annotation is added. */
39
+ onAnnotationAdd?: (annotation: Annotation) => void;
40
+ /** Callback fired when an annotation is deleted. */
41
+ onAnnotationDelete?: (annotation: Annotation) => void;
42
+ /** Callback fired when an annotation comment is edited. */
43
+ onAnnotationUpdate?: (annotation: Annotation) => void;
44
+ /** Callback fired when all annotations are cleared. Receives the annotations that were cleared. */
45
+ onAnnotationsClear?: (annotations: Annotation[]) => void;
46
+ /** Callback fired when the copy button is clicked. Receives the markdown output. */
47
+ onCopy?: (markdown: string) => void;
48
+ /** Whether to copy to clipboard when the copy button is clicked. Defaults to true. */
49
+ copyToClipboard?: boolean;
13
50
  };
14
- declare function PageFeedbackToolbarCSS({ demoAnnotations, demoDelay, enableDemoMode, }?: PageFeedbackToolbarCSSProps): react.ReactPortal | null;
51
+ /** Alias for PageFeedbackToolbarCSSProps */
52
+ type AgentationProps = PageFeedbackToolbarCSSProps;
53
+ declare function PageFeedbackToolbarCSS({ demoAnnotations, demoDelay, enableDemoMode, onAnnotationAdd, onAnnotationDelete, onAnnotationUpdate, onAnnotationsClear, onCopy, copyToClipboard, }?: PageFeedbackToolbarCSSProps): react.ReactPortal | null;
15
54
 
16
55
  interface AnnotationPopupCSSProps {
17
56
  /** Element name to display in header */
@@ -163,33 +202,8 @@ declare function identifyAnimationElement(target: HTMLElement): string;
163
202
  */
164
203
  declare function getElementClasses(target: HTMLElement): string;
165
204
 
166
- type Annotation = {
167
- id: string;
168
- x: number;
169
- y: number;
170
- comment: string;
171
- element: string;
172
- elementPath: string;
173
- timestamp: number;
174
- selectedText?: string;
175
- boundingBox?: {
176
- x: number;
177
- y: number;
178
- width: number;
179
- height: number;
180
- };
181
- nearbyText?: string;
182
- cssClasses?: string;
183
- nearbyElements?: string;
184
- computedStyles?: string;
185
- fullPath?: string;
186
- accessibility?: string;
187
- isMultiSelect?: boolean;
188
- isFixed?: boolean;
189
- };
190
-
191
205
  declare function getStorageKey(pathname: string): string;
192
206
  declare function loadAnnotations<T = Annotation>(pathname: string): T[];
193
207
  declare function saveAnnotations<T = Annotation>(pathname: string, annotations: T[]): void;
194
208
 
195
- export { PageFeedbackToolbarCSS as Agentation, AnimatedBunny, type Annotation, AnnotationPopupCSS, type AnnotationPopupCSSHandle, type AnnotationPopupCSSProps, type DemoAnnotation, IconChatEllipsis, IconCheck, IconCheckSmall, IconCheckSmallAnimated, IconCheckmark, IconCheckmarkCircle, IconCheckmarkLarge, IconClose, IconCopyAlt, IconCopyAnimated, IconEye, IconEyeAlt, IconEyeAnimated, IconEyeClosed, IconEyeMinus, IconGear, IconHelp, IconListSparkle, IconMoon, IconPause, IconPauseAlt, IconPausePlayAnimated, IconPlayAlt, IconPlus, IconSun, IconTrashAlt, IconXmark, IconXmarkLarge, PageFeedbackToolbarCSS, getElementClasses, getElementPath, getNearbyText, getStorageKey, identifyAnimationElement, identifyElement, loadAnnotations, saveAnnotations };
209
+ export { PageFeedbackToolbarCSS as Agentation, type AgentationProps, AnimatedBunny, type Annotation, AnnotationPopupCSS, type AnnotationPopupCSSHandle, type AnnotationPopupCSSProps, type DemoAnnotation, IconChatEllipsis, IconCheck, IconCheckSmall, IconCheckSmallAnimated, IconCheckmark, IconCheckmarkCircle, IconCheckmarkLarge, IconClose, IconCopyAlt, IconCopyAnimated, IconEye, IconEyeAlt, IconEyeAnimated, IconEyeClosed, IconEyeMinus, IconGear, IconHelp, IconListSparkle, IconMoon, IconPause, IconPauseAlt, IconPausePlayAnimated, IconPlayAlt, IconPlus, IconSun, IconTrashAlt, IconXmark, IconXmarkLarge, PageFeedbackToolbarCSS, getElementClasses, getElementPath, getNearbyText, getStorageKey, identifyAnimationElement, identifyElement, loadAnnotations, saveAnnotations };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,31 @@
1
1
  import * as react from 'react';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
 
4
+ type Annotation = {
5
+ id: string;
6
+ x: number;
7
+ y: number;
8
+ comment: string;
9
+ element: string;
10
+ elementPath: string;
11
+ timestamp: number;
12
+ selectedText?: string;
13
+ boundingBox?: {
14
+ x: number;
15
+ y: number;
16
+ width: number;
17
+ height: number;
18
+ };
19
+ nearbyText?: string;
20
+ cssClasses?: string;
21
+ nearbyElements?: string;
22
+ computedStyles?: string;
23
+ fullPath?: string;
24
+ accessibility?: string;
25
+ isMultiSelect?: boolean;
26
+ isFixed?: boolean;
27
+ };
28
+
4
29
  type DemoAnnotation = {
5
30
  selector: string;
6
31
  comment: string;
@@ -10,8 +35,22 @@ type PageFeedbackToolbarCSSProps = {
10
35
  demoAnnotations?: DemoAnnotation[];
11
36
  demoDelay?: number;
12
37
  enableDemoMode?: boolean;
38
+ /** Callback fired when an annotation is added. */
39
+ onAnnotationAdd?: (annotation: Annotation) => void;
40
+ /** Callback fired when an annotation is deleted. */
41
+ onAnnotationDelete?: (annotation: Annotation) => void;
42
+ /** Callback fired when an annotation comment is edited. */
43
+ onAnnotationUpdate?: (annotation: Annotation) => void;
44
+ /** Callback fired when all annotations are cleared. Receives the annotations that were cleared. */
45
+ onAnnotationsClear?: (annotations: Annotation[]) => void;
46
+ /** Callback fired when the copy button is clicked. Receives the markdown output. */
47
+ onCopy?: (markdown: string) => void;
48
+ /** Whether to copy to clipboard when the copy button is clicked. Defaults to true. */
49
+ copyToClipboard?: boolean;
13
50
  };
14
- declare function PageFeedbackToolbarCSS({ demoAnnotations, demoDelay, enableDemoMode, }?: PageFeedbackToolbarCSSProps): react.ReactPortal | null;
51
+ /** Alias for PageFeedbackToolbarCSSProps */
52
+ type AgentationProps = PageFeedbackToolbarCSSProps;
53
+ declare function PageFeedbackToolbarCSS({ demoAnnotations, demoDelay, enableDemoMode, onAnnotationAdd, onAnnotationDelete, onAnnotationUpdate, onAnnotationsClear, onCopy, copyToClipboard, }?: PageFeedbackToolbarCSSProps): react.ReactPortal | null;
15
54
 
16
55
  interface AnnotationPopupCSSProps {
17
56
  /** Element name to display in header */
@@ -163,33 +202,8 @@ declare function identifyAnimationElement(target: HTMLElement): string;
163
202
  */
164
203
  declare function getElementClasses(target: HTMLElement): string;
165
204
 
166
- type Annotation = {
167
- id: string;
168
- x: number;
169
- y: number;
170
- comment: string;
171
- element: string;
172
- elementPath: string;
173
- timestamp: number;
174
- selectedText?: string;
175
- boundingBox?: {
176
- x: number;
177
- y: number;
178
- width: number;
179
- height: number;
180
- };
181
- nearbyText?: string;
182
- cssClasses?: string;
183
- nearbyElements?: string;
184
- computedStyles?: string;
185
- fullPath?: string;
186
- accessibility?: string;
187
- isMultiSelect?: boolean;
188
- isFixed?: boolean;
189
- };
190
-
191
205
  declare function getStorageKey(pathname: string): string;
192
206
  declare function loadAnnotations<T = Annotation>(pathname: string): T[];
193
207
  declare function saveAnnotations<T = Annotation>(pathname: string, annotations: T[]): void;
194
208
 
195
- export { PageFeedbackToolbarCSS as Agentation, AnimatedBunny, type Annotation, AnnotationPopupCSS, type AnnotationPopupCSSHandle, type AnnotationPopupCSSProps, type DemoAnnotation, IconChatEllipsis, IconCheck, IconCheckSmall, IconCheckSmallAnimated, IconCheckmark, IconCheckmarkCircle, IconCheckmarkLarge, IconClose, IconCopyAlt, IconCopyAnimated, IconEye, IconEyeAlt, IconEyeAnimated, IconEyeClosed, IconEyeMinus, IconGear, IconHelp, IconListSparkle, IconMoon, IconPause, IconPauseAlt, IconPausePlayAnimated, IconPlayAlt, IconPlus, IconSun, IconTrashAlt, IconXmark, IconXmarkLarge, PageFeedbackToolbarCSS, getElementClasses, getElementPath, getNearbyText, getStorageKey, identifyAnimationElement, identifyElement, loadAnnotations, saveAnnotations };
209
+ export { PageFeedbackToolbarCSS as Agentation, type AgentationProps, AnimatedBunny, type Annotation, AnnotationPopupCSS, type AnnotationPopupCSSHandle, type AnnotationPopupCSSProps, type DemoAnnotation, IconChatEllipsis, IconCheck, IconCheckSmall, IconCheckSmallAnimated, IconCheckmark, IconCheckmarkCircle, IconCheckmarkLarge, IconClose, IconCopyAlt, IconCopyAnimated, IconEye, IconEyeAlt, IconEyeAnimated, IconEyeClosed, IconEyeMinus, IconGear, IconHelp, IconListSparkle, IconMoon, IconPause, IconPauseAlt, IconPausePlayAnimated, IconPlayAlt, IconPlus, IconSun, IconTrashAlt, IconXmark, IconXmarkLarge, PageFeedbackToolbarCSS, getElementClasses, getElementPath, getNearbyText, getStorageKey, identifyAnimationElement, identifyElement, loadAnnotations, saveAnnotations };
package/dist/index.js CHANGED
@@ -1540,7 +1540,13 @@ function generateOutput(annotations, pathname, detailLevel = "standard") {
1540
1540
  function PageFeedbackToolbarCSS({
1541
1541
  demoAnnotations,
1542
1542
  demoDelay = 1e3,
1543
- enableDemoMode = false
1543
+ enableDemoMode = false,
1544
+ onAnnotationAdd,
1545
+ onAnnotationDelete,
1546
+ onAnnotationUpdate,
1547
+ onAnnotationsClear,
1548
+ onCopy,
1549
+ copyToClipboard = true
1544
1550
  } = {}) {
1545
1551
  const [isActive, setIsActive] = (0, import_react2.useState)(false);
1546
1552
  const [annotations, setAnnotations] = (0, import_react2.useState)([]);
@@ -2262,6 +2268,7 @@ function PageFeedbackToolbarCSS({
2262
2268
  setTimeout(() => {
2263
2269
  setAnimatedMarkers((prev) => new Set(prev).add(newAnnotation.id));
2264
2270
  }, 250);
2271
+ onAnnotationAdd?.(newAnnotation);
2265
2272
  setPendingExiting(true);
2266
2273
  setTimeout(() => {
2267
2274
  setPendingAnnotation(null);
@@ -2269,7 +2276,7 @@ function PageFeedbackToolbarCSS({
2269
2276
  }, 150);
2270
2277
  window.getSelection()?.removeAllRanges();
2271
2278
  },
2272
- [pendingAnnotation]
2279
+ [pendingAnnotation, onAnnotationAdd]
2273
2280
  );
2274
2281
  const cancelAnnotation = (0, import_react2.useCallback)(() => {
2275
2282
  setPendingExiting(true);
@@ -2281,8 +2288,12 @@ function PageFeedbackToolbarCSS({
2281
2288
  const deleteAnnotation = (0, import_react2.useCallback)(
2282
2289
  (id) => {
2283
2290
  const deletedIndex = annotations.findIndex((a) => a.id === id);
2291
+ const deletedAnnotation = annotations[deletedIndex];
2284
2292
  setDeletingMarkerId(id);
2285
2293
  setExitingMarkers((prev) => new Set(prev).add(id));
2294
+ if (deletedAnnotation) {
2295
+ onAnnotationDelete?.(deletedAnnotation);
2296
+ }
2286
2297
  setTimeout(() => {
2287
2298
  setAnnotations((prev) => prev.filter((a) => a.id !== id));
2288
2299
  setExitingMarkers((prev) => {
@@ -2297,7 +2308,7 @@ function PageFeedbackToolbarCSS({
2297
2308
  }
2298
2309
  }, 150);
2299
2310
  },
2300
- [annotations]
2311
+ [annotations, onAnnotationDelete]
2301
2312
  );
2302
2313
  const startEditAnnotation = (0, import_react2.useCallback)((annotation) => {
2303
2314
  setEditingAnnotation(annotation);
@@ -2306,18 +2317,20 @@ function PageFeedbackToolbarCSS({
2306
2317
  const updateAnnotation = (0, import_react2.useCallback)(
2307
2318
  (newComment) => {
2308
2319
  if (!editingAnnotation) return;
2320
+ const updatedAnnotation = { ...editingAnnotation, comment: newComment };
2309
2321
  setAnnotations(
2310
2322
  (prev) => prev.map(
2311
- (a) => a.id === editingAnnotation.id ? { ...a, comment: newComment } : a
2323
+ (a) => a.id === editingAnnotation.id ? updatedAnnotation : a
2312
2324
  )
2313
2325
  );
2326
+ onAnnotationUpdate?.(updatedAnnotation);
2314
2327
  setEditExiting(true);
2315
2328
  setTimeout(() => {
2316
2329
  setEditingAnnotation(null);
2317
2330
  setEditExiting(false);
2318
2331
  }, 150);
2319
2332
  },
2320
- [editingAnnotation]
2333
+ [editingAnnotation, onAnnotationUpdate]
2321
2334
  );
2322
2335
  const cancelEditAnnotation = (0, import_react2.useCallback)(() => {
2323
2336
  setEditExiting(true);
@@ -2329,6 +2342,7 @@ function PageFeedbackToolbarCSS({
2329
2342
  const clearAll = (0, import_react2.useCallback)(() => {
2330
2343
  const count = annotations.length;
2331
2344
  if (count === 0) return;
2345
+ onAnnotationsClear?.(annotations);
2332
2346
  setIsClearing(true);
2333
2347
  setCleared(true);
2334
2348
  const totalAnimationTime = count * 30 + 200;
@@ -2339,11 +2353,17 @@ function PageFeedbackToolbarCSS({
2339
2353
  setIsClearing(false);
2340
2354
  }, totalAnimationTime);
2341
2355
  setTimeout(() => setCleared(false), 1500);
2342
- }, [pathname, annotations.length]);
2356
+ }, [pathname, annotations, onAnnotationsClear]);
2343
2357
  const copyOutput = (0, import_react2.useCallback)(async () => {
2344
2358
  const output = generateOutput(annotations, pathname, settings.outputDetail);
2345
2359
  if (!output) return;
2346
- await navigator.clipboard.writeText(output);
2360
+ if (copyToClipboard) {
2361
+ try {
2362
+ await navigator.clipboard.writeText(output);
2363
+ } catch {
2364
+ }
2365
+ }
2366
+ onCopy?.(output);
2347
2367
  setCopied(true);
2348
2368
  setTimeout(() => setCopied(false), 2e3);
2349
2369
  if (settings.autoClearAfterCopy) {
@@ -2354,7 +2374,9 @@ function PageFeedbackToolbarCSS({
2354
2374
  pathname,
2355
2375
  settings.outputDetail,
2356
2376
  settings.autoClearAfterCopy,
2357
- clearAll
2377
+ clearAll,
2378
+ copyToClipboard,
2379
+ onCopy
2358
2380
  ]);
2359
2381
  (0, import_react2.useEffect)(() => {
2360
2382
  if (!dragStartPos) return;
@@ -2674,7 +2696,7 @@ function PageFeedbackToolbarCSS({
2674
2696
  ] }),
2675
2697
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: styles_module_default2.settingsVersion, children: [
2676
2698
  "v",
2677
- "1.1.0"
2699
+ "1.2.0"
2678
2700
  ] }),
2679
2701
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2680
2702
  "button",
@@ -2765,10 +2787,10 @@ function PageFeedbackToolbarCSS({
2765
2787
  className: `${styles_module_default2.colorOption} ${settings.annotationColor === color.value ? styles_module_default2.selected : ""}`,
2766
2788
  style: { backgroundColor: color.value },
2767
2789
  title: color.label
2768
- },
2769
- color.value
2790
+ }
2770
2791
  )
2771
- }
2792
+ },
2793
+ color.value
2772
2794
  )) })
2773
2795
  ] }),
2774
2796
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: styles_module_default2.settingsSection, children: [