@coframe-gtm/annotations 1.0.3 → 1.1.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/package.json +16 -8
- package/src/README.md +4 -3
- package/src/api.ts +12 -0
- package/src/bundle.ts +11 -5
- package/src/inject/build.ts +0 -2
- package/src/inject/bundle-source.generated.ts +1 -1
- package/src/signal.ts +56 -0
- package/src/store.ts +2 -2
- package/src/ui/Composer.ts +166 -0
- package/src/ui/Cursors.ts +52 -0
- package/src/ui/Pins.ts +68 -0
- package/src/ui/ThreadPanel.ts +120 -0
- package/src/ui/Toolbar.ts +88 -0
- package/src/ui/constants.ts +24 -0
- package/src/ui/dom.ts +95 -0
- package/src/ui/helpers.ts +50 -0
- package/src/ui/overlay.ts +155 -0
- package/src/ui/styles.ts +23 -0
- package/src/ui/App.ts +0 -516
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coframe-gtm/annotations",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Clean-room AFS v1.1 annotation overlay (frontend) + transport-agnostic ingest core (backend). Injects into any page; humans + agents annotate bidirectionally.",
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
"directory": "coframe-agentation/frontend"
|
|
11
11
|
},
|
|
12
12
|
"main": "./src/index.ts",
|
|
13
|
-
"files": [
|
|
13
|
+
"files": [
|
|
14
|
+
"src",
|
|
15
|
+
"README.md",
|
|
16
|
+
"!src/**/*.stories.ts"
|
|
17
|
+
],
|
|
14
18
|
"publishConfig": {
|
|
15
19
|
"access": "public"
|
|
16
20
|
},
|
|
@@ -25,20 +29,24 @@
|
|
|
25
29
|
"scripts": {
|
|
26
30
|
"typecheck": "tsc --noEmit",
|
|
27
31
|
"test": "vitest run",
|
|
28
|
-
"build": "node --experimental-strip-types src/inject/build.ts"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"preact": "^10.24.0",
|
|
32
|
-
"@preact/signals": "^2.0.0"
|
|
32
|
+
"build": "node --experimental-strip-types src/inject/build.ts",
|
|
33
|
+
"storybook": "storybook dev -p 6006",
|
|
34
|
+
"build-storybook": "storybook build"
|
|
33
35
|
},
|
|
36
|
+
"dependencies": {},
|
|
34
37
|
"devDependencies": {
|
|
38
|
+
"@storybook/html-vite": "^10.4.1",
|
|
35
39
|
"@types/node": "^22.10.5",
|
|
36
40
|
"esbuild": "^0.28.0",
|
|
37
41
|
"jsdom": "^25.0.0",
|
|
42
|
+
"storybook": "^10.4.1",
|
|
38
43
|
"typescript": "^5.9.2",
|
|
44
|
+
"vite": "^8.0.14",
|
|
39
45
|
"vitest": "^4.1.5"
|
|
40
46
|
},
|
|
41
47
|
"pnpm": {
|
|
42
|
-
"onlyBuiltDependencies": [
|
|
48
|
+
"onlyBuiltDependencies": [
|
|
49
|
+
"esbuild"
|
|
50
|
+
]
|
|
43
51
|
}
|
|
44
52
|
}
|
package/src/README.md
CHANGED
|
@@ -5,7 +5,7 @@ The clean-room injection bundle described in
|
|
|
5
5
|
this scaffold:
|
|
6
6
|
|
|
7
7
|
- Closed Shadow DOM mount (`shadow.ts`)
|
|
8
|
-
-
|
|
8
|
+
- Vanilla DOM overlay (`ui/overlay.ts`)
|
|
9
9
|
- `window.__annotations` API surface (`api.ts`)
|
|
10
10
|
- Outbound webhook emitter (`webhook.ts`)
|
|
11
11
|
- CDP install helpers (`inject/install.ts`)
|
|
@@ -61,14 +61,15 @@ src/v1/
|
|
|
61
61
|
├── README.md # this file
|
|
62
62
|
├── index.ts # public Node surface (install helpers, types)
|
|
63
63
|
├── types.ts # data model
|
|
64
|
-
├── store.ts #
|
|
64
|
+
├── store.ts # reactive signals (vanilla, ./signal.ts)
|
|
65
65
|
├── ulid.ts # tiny inlined ULID
|
|
66
66
|
├── shadow.ts # closed Shadow DOM mount
|
|
67
67
|
├── webhook.ts # outbound POST emitter
|
|
68
68
|
├── api.ts # window.__annotations
|
|
69
69
|
├── bundle.ts # IIFE entry
|
|
70
|
+
├── signal.ts # tiny vanilla reactive primitive
|
|
70
71
|
├── ui/
|
|
71
|
-
│ └──
|
|
72
|
+
│ └── overlay.ts # vanilla per-layer overlay mount
|
|
72
73
|
└── inject/
|
|
73
74
|
├── install.ts # CDP install helpers
|
|
74
75
|
└── build.ts # esbuild build script
|
package/src/api.ts
CHANGED
|
@@ -90,6 +90,10 @@ export interface AnnotationsApi {
|
|
|
90
90
|
/** Remove all cursors. */
|
|
91
91
|
clearCursors(): void;
|
|
92
92
|
setMode(next: Mode): void;
|
|
93
|
+
/** Current overlay mode. Lets a parent frame (headless) read view/comment state. */
|
|
94
|
+
getMode(): Mode;
|
|
95
|
+
/** Subscribe to mode changes. Returns an unsubscribe function. */
|
|
96
|
+
subscribeMode(fn: (mode: Mode) => void): () => void;
|
|
93
97
|
setTheme(next: Theme): void;
|
|
94
98
|
getAnnotations(): Annotation[];
|
|
95
99
|
}
|
|
@@ -242,6 +246,14 @@ export const api: AnnotationsApi = {
|
|
|
242
246
|
emit("session.updated", { mode: next });
|
|
243
247
|
},
|
|
244
248
|
|
|
249
|
+
getMode() {
|
|
250
|
+
return mode.value;
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
subscribeMode(fn) {
|
|
254
|
+
return mode.subscribe(fn);
|
|
255
|
+
},
|
|
256
|
+
|
|
245
257
|
setTheme(next) {
|
|
246
258
|
theme.value = next;
|
|
247
259
|
},
|
package/src/bundle.ts
CHANGED
|
@@ -11,13 +11,11 @@
|
|
|
11
11
|
* starting state.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import { render, h } from "preact";
|
|
15
|
-
|
|
16
14
|
import { api, initSession } from "./api.js";
|
|
17
15
|
import { installPicker, setPickerHost } from "./picker.js";
|
|
18
16
|
import { mountShadow } from "./shadow.js";
|
|
19
17
|
import { author, mode, ready, theme, viewportTick } from "./store.js";
|
|
20
|
-
import {
|
|
18
|
+
import { mountOverlay as mountOverlayUi } from "./ui/overlay.js";
|
|
21
19
|
|
|
22
20
|
import type { AnnotationsApi } from "./api.js";
|
|
23
21
|
import type { Mode, Theme } from "./types.js";
|
|
@@ -28,6 +26,12 @@ interface InitOptions {
|
|
|
28
26
|
author?: { kind: "human" | "agent"; id?: string; displayName?: string };
|
|
29
27
|
mode?: Mode;
|
|
30
28
|
theme?: Theme;
|
|
29
|
+
/**
|
|
30
|
+
* Headless mode: mount pins/cursors/composer/thread but NOT the
|
|
31
|
+
* toolbar, so a parent frame drives view/comment mode via
|
|
32
|
+
* `window.__annotations.setMode(...)`.
|
|
33
|
+
*/
|
|
34
|
+
headless?: boolean;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
declare global {
|
|
@@ -37,12 +41,14 @@ declare global {
|
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
let mounted = false;
|
|
44
|
+
let headless = false;
|
|
40
45
|
|
|
41
46
|
function init(opts: InitOptions = {}): void {
|
|
42
47
|
initSession(opts);
|
|
43
48
|
if (opts.author) author.value = opts.author;
|
|
44
49
|
if (opts.mode) mode.value = opts.mode;
|
|
45
50
|
if (opts.theme) theme.value = opts.theme;
|
|
51
|
+
if (opts.headless) headless = true;
|
|
46
52
|
|
|
47
53
|
mountOverlay();
|
|
48
54
|
|
|
@@ -51,7 +57,7 @@ function init(opts: InitOptions = {}): void {
|
|
|
51
57
|
console.info("[annotations v1] ready on", location.href);
|
|
52
58
|
}
|
|
53
59
|
|
|
54
|
-
// Mount the shadow host +
|
|
60
|
+
// Mount the shadow host + overlay tree once the DOM root exists. When the
|
|
55
61
|
// bundle is injected at document-start (e.g. via
|
|
56
62
|
// `Page.addScriptToEvaluateOnNewDocument`), `document.documentElement` is
|
|
57
63
|
// still null, so `mountShadow()` would throw and the overlay would never
|
|
@@ -69,7 +75,7 @@ function mountOverlay(): void {
|
|
|
69
75
|
const { host, appRoot } = mountShadow();
|
|
70
76
|
setPickerHost(host);
|
|
71
77
|
installPicker();
|
|
72
|
-
|
|
78
|
+
mountOverlayUi(appRoot, { headless });
|
|
73
79
|
|
|
74
80
|
const bump = (): void => {
|
|
75
81
|
viewportTick.value++;
|
package/src/inject/build.ts
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
// This file is generated by `pnpm build`.
|
|
3
3
|
// Do not edit by hand. Regenerate by running the build script.
|
|
4
4
|
export const ANNOTATIONS_V1_BUNDLE_SOURCE: string =
|
|
5
|
-
"\"use strict\";(()=>{var de,m,it,Ne,O,tt,at,st,$e,se,Q,lt,Ie,Pe,Me,sn,ce={},ue=[],ln=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,pe=Array.isArray;function U(e,t){for(var n in t)e[n]=t[n];return e}function Be(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function d(e,t,n){var o,r,i,s={};for(i in t)i==\"key\"?o=t[i]:i==\"ref\"?r=t[i]:s[i]=t[i];if(arguments.length>2&&(s.children=arguments.length>3?de.call(arguments,2):n),typeof e==\"function\"&&e.defaultProps!=null)for(i in e.defaultProps)s[i]===void 0&&(s[i]=e.defaultProps[i]);return le(e,s,o,r,null)}function le(e,t,n,o,r){var i={type:e,props:t,key:n,ref:o,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:r??++it,__i:-1,__u:0};return r==null&&m.vnode!=null&&m.vnode(i),i}function V(e){return e.children}function q(e,t){this.props=e,this.context=t}function K(e,t){if(t==null)return e.__?K(e.__,e.__i+1):null;for(var n;t<e.__k.length;t++)if((n=e.__k[t])!=null&&n.__e!=null)return n.__e;return typeof e.type==\"function\"?K(e):null}function cn(e){if(e.__P&&e.__d){var t=e.__v,n=t.__e,o=[],r=[],i=U({},t);i.__v=t.__v+1,m.vnode&&m.vnode(i),Re(e.__P,i,t,e.__n,e.__P.namespaceURI,32&t.__u?[n]:null,o,n??K(t),!!(32&t.__u),r),i.__v=t.__v,i.__.__k[i.__i]=i,dt(o,i,r),t.__e=t.__=null,i.__e!=n&&ct(i)}}function ct(e){if((e=e.__)!=null&&e.__c!=null)return e.__e=e.__c.base=null,e.__k.some(function(t){if(t!=null&&t.__e!=null)return e.__e=e.__c.base=t.__e}),ct(e)}function nt(e){(!e.__d&&(e.__d=!0)&&O.push(e)&&!fe.__r++||tt!=m.debounceRendering)&&((tt=m.debounceRendering)||at)(fe)}function fe(){try{for(var e,t=1;O.length;)O.length>t&&O.sort(st),e=O.shift(),t=O.length,cn(e)}finally{O.length=fe.__r=0}}function ut(e,t,n,o,r,i,s,c,f,l,u){var a,_,p,C,M,S,v,h=o&&o.__k||ue,D=t.length;for(f=un(n,t,h,f,D),a=0;a<D;a++)(p=n.__k[a])!=null&&(_=p.__i!=-1&&h[p.__i]||ce,p.__i=a,S=Re(e,p,_,r,i,s,c,f,l,u),C=p.__e,p.ref&&_.ref!=p.ref&&(_.ref&&Ue(_.ref,null,p),u.push(p.ref,p.__c||C,p)),M==null&&C!=null&&(M=C),(v=!!(4&p.__u))||_.__k===p.__k?(f=ft(p,f,e,v),v&&_.__e&&(_.__e=null)):typeof p.type==\"function\"&&S!==void 0?f=S:C&&(f=C.nextSibling),p.__u&=-7);return n.__e=M,f}function un(e,t,n,o,r){var i,s,c,f,l,u=n.length,a=u,_=0;for(e.__k=new Array(r),i=0;i<r;i++)(s=t[i])!=null&&typeof s!=\"boolean\"&&typeof s!=\"function\"?(typeof s==\"string\"||typeof s==\"number\"||typeof s==\"bigint\"||s.constructor==String?s=e.__k[i]=le(null,s,null,null,null):pe(s)?s=e.__k[i]=le(V,{children:s},null,null,null):s.constructor===void 0&&s.__b>0?s=e.__k[i]=le(s.type,s.props,s.key,s.ref?s.ref:null,s.__v):e.__k[i]=s,f=i+_,s.__=e,s.__b=e.__b+1,c=null,(l=s.__i=fn(s,n,f,a))!=-1&&(a--,(c=n[l])&&(c.__u|=2)),c==null||c.__v==null?(l==-1&&(r>u?_--:r<u&&_++),typeof s.type!=\"function\"&&(s.__u|=4)):l!=f&&(l==f-1?_--:l==f+1?_++:(l>f?_--:_++,s.__u|=4))):e.__k[i]=null;if(a)for(i=0;i<u;i++)(c=n[i])!=null&&(2&c.__u)==0&&(c.__e==o&&(o=K(c)),_t(c,c));return o}function ft(e,t,n,o){var r,i;if(typeof e.type==\"function\"){for(r=e.__k,i=0;r&&i<r.length;i++)r[i]&&(r[i].__=e,t=ft(r[i],t,n,o));return t}e.__e!=t&&(o&&(t&&e.type&&!t.parentNode&&(t=K(e)),n.insertBefore(e.__e,t||null)),t=e.__e);do t=t&&t.nextSibling;while(t!=null&&t.nodeType==8);return t}function fn(e,t,n,o){var r,i,s,c=e.key,f=e.type,l=t[n],u=l!=null&&(2&l.__u)==0;if(l===null&&c==null||u&&c==l.key&&f==l.type)return n;if(o>(u?1:0)){for(r=n-1,i=n+1;r>=0||i<t.length;)if((l=t[s=r>=0?r--:i++])!=null&&(2&l.__u)==0&&c==l.key&&f==l.type)return s}return-1}function ot(e,t,n){t[0]==\"-\"?e.setProperty(t,n??\"\"):e[t]=n==null?\"\":typeof n!=\"number\"||ln.test(t)?n:n+\"px\"}function ae(e,t,n,o,r){var i,s;e:if(t==\"style\")if(typeof n==\"string\")e.style.cssText=n;else{if(typeof o==\"string\"&&(e.style.cssText=o=\"\"),o)for(t in o)n&&t in n||ot(e.style,t,\"\");if(n)for(t in n)o&&n[t]==o[t]||ot(e.style,t,n[t])}else if(t[0]==\"o\"&&t[1]==\"n\")i=t!=(t=t.replace(lt,\"$1\")),s=t.toLowerCase(),t=s in e||t==\"onFocusOut\"||t==\"onFocusIn\"?s.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+i]=n,n?o?n[Q]=o[Q]:(n[Q]=Ie,e.addEventListener(t,i?Me:Pe,i)):e.removeEventListener(t,i?Me:Pe,i);else{if(r==\"http://www.w3.org/2000/svg\")t=t.replace(/xlink(H|:h)/,\"h\").replace(/sName$/,\"s\");else if(t!=\"width\"&&t!=\"height\"&&t!=\"href\"&&t!=\"list\"&&t!=\"form\"&&t!=\"tabIndex\"&&t!=\"download\"&&t!=\"rowSpan\"&&t!=\"colSpan\"&&t!=\"role\"&&t!=\"popover\"&&t in e)try{e[t]=n??\"\";break e}catch{}typeof n==\"function\"||(n==null||n===!1&&t[4]!=\"-\"?e.removeAttribute(t):e.setAttribute(t,t==\"popover\"&&n==1?\"\":n))}}function rt(e){return function(t){if(this.l){var n=this.l[t.type+e];if(t[se]==null)t[se]=Ie++;else if(t[se]<n[Q])return;return n(m.event?m.event(t):t)}}}function Re(e,t,n,o,r,i,s,c,f,l){var u,a,_,p,C,M,S,v,h,D,H,J,et,ie,Te,N=t.type;if(t.constructor!==void 0)return null;128&n.__u&&(f=!!(32&n.__u),i=[c=t.__e=n.__e]),(u=m.__b)&&u(t);e:if(typeof N==\"function\")try{if(v=t.props,h=N.prototype&&N.prototype.render,D=(u=N.contextType)&&o[u.__c],H=u?D?D.props.value:u.__:o,n.__c?S=(a=t.__c=n.__c).__=a.__E:(h?t.__c=a=new N(v,H):(t.__c=a=new q(v,H),a.constructor=N,a.render=pn),D&&D.sub(a),a.state||(a.state={}),a.__n=o,_=a.__d=!0,a.__h=[],a._sb=[]),h&&a.__s==null&&(a.__s=a.state),h&&N.getDerivedStateFromProps!=null&&(a.__s==a.state&&(a.__s=U({},a.__s)),U(a.__s,N.getDerivedStateFromProps(v,a.__s))),p=a.props,C=a.state,a.__v=t,_)h&&N.getDerivedStateFromProps==null&&a.componentWillMount!=null&&a.componentWillMount(),h&&a.componentDidMount!=null&&a.__h.push(a.componentDidMount);else{if(h&&N.getDerivedStateFromProps==null&&v!==p&&a.componentWillReceiveProps!=null&&a.componentWillReceiveProps(v,H),t.__v==n.__v||!a.__e&&a.shouldComponentUpdate!=null&&a.shouldComponentUpdate(v,a.__s,H)===!1){t.__v!=n.__v&&(a.props=v,a.state=a.__s,a.__d=!1),t.__e=n.__e,t.__k=n.__k,t.__k.some(function(Y){Y&&(Y.__=t)}),ue.push.apply(a.__h,a._sb),a._sb=[],a.__h.length&&s.push(a);break e}a.componentWillUpdate!=null&&a.componentWillUpdate(v,a.__s,H),h&&a.componentDidUpdate!=null&&a.__h.push(function(){a.componentDidUpdate(p,C,M)})}if(a.context=H,a.props=v,a.__P=e,a.__e=!1,J=m.__r,et=0,h)a.state=a.__s,a.__d=!1,J&&J(t),u=a.render(a.props,a.state,a.context),ue.push.apply(a.__h,a._sb),a._sb=[];else do a.__d=!1,J&&J(t),u=a.render(a.props,a.state,a.context),a.state=a.__s;while(a.__d&&++et<25);a.state=a.__s,a.getChildContext!=null&&(o=U(U({},o),a.getChildContext())),h&&!_&&a.getSnapshotBeforeUpdate!=null&&(M=a.getSnapshotBeforeUpdate(p,C)),ie=u!=null&&u.type===V&&u.key==null?pt(u.props.children):u,c=ut(e,pe(ie)?ie:[ie],t,n,o,r,i,s,c,f,l),a.base=t.__e,t.__u&=-161,a.__h.length&&s.push(a),S&&(a.__E=a.__=null)}catch(Y){if(t.__v=null,f||i!=null)if(Y.then){for(t.__u|=f?160:128;c&&c.nodeType==8&&c.nextSibling;)c=c.nextSibling;i[i.indexOf(c)]=null,t.__e=c}else{for(Te=i.length;Te--;)Be(i[Te]);Le(t)}else t.__e=n.__e,t.__k=n.__k,Y.then||Le(t);m.__e(Y,t,n)}else i==null&&t.__v==n.__v?(t.__k=n.__k,t.__e=n.__e):c=t.__e=dn(n.__e,t,n,o,r,i,s,f,l);return(u=m.diffed)&&u(t),128&t.__u?void 0:c}function Le(e){e&&(e.__c&&(e.__c.__e=!0),e.__k&&e.__k.some(Le))}function dt(e,t,n){for(var o=0;o<n.length;o++)Ue(n[o],n[++o],n[++o]);m.__c&&m.__c(t,e),e.some(function(r){try{e=r.__h,r.__h=[],e.some(function(i){i.call(r)})}catch(i){m.__e(i,r.__v)}})}function pt(e){return typeof e!=\"object\"||e==null||e.__b>0?e:pe(e)?e.map(pt):e.constructor!==void 0?null:U({},e)}function dn(e,t,n,o,r,i,s,c,f){var l,u,a,_,p,C,M,S=n.props||ce,v=t.props,h=t.type;if(h==\"svg\"?r=\"http://www.w3.org/2000/svg\":h==\"math\"?r=\"http://www.w3.org/1998/Math/MathML\":r||(r=\"http://www.w3.org/1999/xhtml\"),i!=null){for(l=0;l<i.length;l++)if((p=i[l])&&\"setAttribute\"in p==!!h&&(h?p.localName==h:p.nodeType==3)){e=p,i[l]=null;break}}if(e==null){if(h==null)return document.createTextNode(v);e=document.createElementNS(r,h,v.is&&v),c&&(m.__m&&m.__m(t,i),c=!1),i=null}if(h==null)S===v||c&&e.data==v||(e.data=v);else{if(i=h==\"textarea\"&&v.defaultValue!=null?null:i&&de.call(e.childNodes),!c&&i!=null)for(S={},l=0;l<e.attributes.length;l++)S[(p=e.attributes[l]).name]=p.value;for(l in S)p=S[l],l==\"dangerouslySetInnerHTML\"?a=p:l==\"children\"||l in v||l==\"value\"&&\"defaultValue\"in v||l==\"checked\"&&\"defaultChecked\"in v||ae(e,l,null,p,r);for(l in v)p=v[l],l==\"children\"?_=p:l==\"dangerouslySetInnerHTML\"?u=p:l==\"value\"?C=p:l==\"checked\"?M=p:c&&typeof p!=\"function\"||S[l]===p||ae(e,l,p,S[l],r);if(u)c||a&&(u.__html==a.__html||u.__html==e.innerHTML)||(e.innerHTML=u.__html),t.__k=[];else if(a&&(e.innerHTML=\"\"),ut(t.type==\"template\"?e.content:e,pe(_)?_:[_],t,n,o,h==\"foreignObject\"?\"http://www.w3.org/1999/xhtml\":r,i,s,i?i[0]:n.__k&&K(n,0),c,f),i!=null)for(l=i.length;l--;)Be(i[l]);c&&h!=\"textarea\"||(l=\"value\",h==\"progress\"&&C==null?e.removeAttribute(\"value\"):C!=null&&(C!==e[l]||h==\"progress\"&&!C||h==\"option\"&&C!=S[l])&&ae(e,l,C,S[l],r),l=\"checked\",M!=null&&M!=e[l]&&ae(e,l,M,S[l],r))}return e}function Ue(e,t,n){try{if(typeof e==\"function\"){var o=typeof e.__u==\"function\";o&&e.__u(),o&&t==null||(e.__u=e(t))}else e.current=t}catch(r){m.__e(r,n)}}function _t(e,t,n){var o,r;if(m.unmount&&m.unmount(e),(o=e.ref)&&(o.current&&o.current!=e.__e||Ue(o,null,t)),(o=e.__c)!=null){if(o.componentWillUnmount)try{o.componentWillUnmount()}catch(i){m.__e(i,t)}o.base=o.__P=null}if(o=e.__k)for(r=0;r<o.length;r++)o[r]&&_t(o[r],t,n||typeof e.type!=\"function\");n||Be(e.__e),e.__c=e.__=e.__e=void 0}function pn(e,t,n){return this.constructor(e,n)}function mt(e,t,n){var o,r,i,s;t==document&&(t=document.documentElement),m.__&&m.__(e,t),r=(o=typeof n==\"function\")?null:n&&n.__k||t.__k,i=[],s=[],Re(t,e=(!o&&n||t).__k=d(V,null,[e]),r||ce,ce,t.namespaceURI,!o&&n?[n]:r?null:t.firstChild?de.call(t.childNodes):null,i,!o&&n?n:r?r.__e:t.firstChild,o,s),dt(i,e,s)}de=ue.slice,m={__e:function(e,t,n,o){for(var r,i,s;t=t.__;)if((r=t.__c)&&!r.__)try{if((i=r.constructor)&&i.getDerivedStateFromError!=null&&(r.setState(i.getDerivedStateFromError(e)),s=r.__d),r.componentDidCatch!=null&&(r.componentDidCatch(e,o||{}),s=r.__d),s)return r.__E=r}catch(c){e=c}throw e}},it=0,Ne=function(e){return e!=null&&e.constructor===void 0},q.prototype.setState=function(e,t){var n;n=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=U({},this.state),typeof e==\"function\"&&(e=e(U({},n),this.props)),e&&U(n,e),e!=null&&this.__v&&(t&&this._sb.push(t),nt(this))},q.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),nt(this))},q.prototype.render=V,O=[],at=typeof Promise==\"function\"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,st=function(e,t){return e.__v.__b-t.__v.__b},fe.__r=0,$e=Math.random().toString(8),se=\"__d\"+$e,Q=\"__a\"+$e,lt=/(PointerCapture)$|Capture$/i,Ie=0,Pe=rt(!1),Me=rt(!0),sn=0;var ht=\"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";function _e(e=Date.now()){let t=e,n=\"\";for(let r=0;r<10;r++)n=ht[t&31]+n,t=Math.floor(t/32);let o=\"\";for(let r=0;r<16;r++)o+=ht[Math.floor(Math.random()*32)];return n+o}var he,y,Fe,vt,De=0,St=[],k=m,gt=k.__b,yt=k.__r,bt=k.diffed,xt=k.__c,kt=k.unmount,wt=k.__;function At(e,t){k.__h&&k.__h(y,e,De||t),De=0;var n=y.__H||(y.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function ee(e){return De=1,_n(Et,e)}function _n(e,t,n){var o=At(he++,2);if(o.t=e,!o.__c&&(o.__=[n?n(t):Et(void 0,t),function(c){var f=o.__N?o.__N[0]:o.__[0],l=o.t(f,c);f!==l&&(o.__N=[l,o.__[1]],o.__c.setState({}))}],o.__c=y,!y.__f)){var r=function(c,f,l){if(!o.__c.__H)return!0;var u=o.__c.__H.__.filter(function(_){return _.__c});if(u.every(function(_){return!_.__N}))return!i||i.call(this,c,f,l);var a=o.__c.props!==c;return u.some(function(_){if(_.__N){var p=_.__[0];_.__=_.__N,_.__N=void 0,p!==_.__[0]&&(a=!0)}}),i&&i.call(this,c,f,l)||a};y.__f=!0;var i=y.shouldComponentUpdate,s=y.componentWillUpdate;y.componentWillUpdate=function(c,f,l){if(this.__e){var u=i;i=void 0,r(c,f,l),i=u}s&&s.call(this,c,f,l)},y.shouldComponentUpdate=r}return o.__N||o.__}function He(e,t){var n=At(he++,7);return vn(n.__H,t)&&(n.__=e(),n.__H=t,n.__h=e),n.__}function mn(){for(var e;e=St.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(me),t.__h.some(Oe),t.__h=[]}catch(n){t.__h=[],k.__e(n,e.__v)}}}k.__b=function(e){y=null,gt&>(e)},k.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),wt&&wt(e,t)},k.__r=function(e){yt&&yt(e),he=0;var t=(y=e.__c).__H;t&&(Fe===y?(t.__h=[],y.__h=[],t.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(t.__h.some(me),t.__h.some(Oe),t.__h=[],he=0)),Fe=y},k.diffed=function(e){bt&&bt(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(St.push(t)!==1&&vt===k.requestAnimationFrame||((vt=k.requestAnimationFrame)||hn)(mn)),t.__H.__.some(function(n){n.u&&(n.__H=n.u),n.u=void 0})),Fe=y=null},k.__c=function(e,t){t.some(function(n){try{n.__h.some(me),n.__h=n.__h.filter(function(o){return!o.__||Oe(o)})}catch(o){t.some(function(r){r.__h&&(r.__h=[])}),t=[],k.__e(o,n.__v)}}),xt&&xt(e,t)},k.unmount=function(e){kt&&kt(e);var t,n=e.__c;n&&n.__H&&(n.__H.__.some(function(o){try{me(o)}catch(r){t=r}}),n.__H=void 0,t&&k.__e(t,n.__v))};var Ct=typeof requestAnimationFrame==\"function\";function hn(e){var t,n=function(){clearTimeout(o),Ct&&cancelAnimationFrame(t),setTimeout(e)},o=setTimeout(n,35);Ct&&(t=requestAnimationFrame(n))}function me(e){var t=y,n=e.__c;typeof n==\"function\"&&(e.__c=void 0,n()),y=t}function Oe(e){var t=y;e.__c=e.__(),y=t}function vn(e,t){return!e||e.length!==t.length||t.some(function(n,o){return n!==e[o]})}function Et(e,t){return typeof t==\"function\"?t(e):t}var gn=Symbol.for(\"preact-signals\");function be(){if(F>1)F--;else{var e,t=!1;for((function(){var r=ge;for(ge=void 0;r!==void 0;)r.S.v===r.v&&(r.S.i=r.i),r=r.o})();te!==void 0;){var n=te;for(te=void 0,ve++;n!==void 0;){var o=n.u;if(n.u=void 0,n.f&=-3,!(8&n.f)&&Pt(n))try{n.c()}catch(r){t||(e=r,t=!0)}n=o}}if(ve=0,F--,t)throw e}}function ze(e){if(F>0)return e();je=++yn,F++;try{return e()}finally{be()}}var g=void 0;function xe(e){var t=g;g=void 0;try{return e()}finally{g=t}}var Tt,te=void 0,F=0,ve=0,yn=0,je=0,ge=void 0,ye=0;function $t(e){if(g!==void 0){var t=e.n;if(t===void 0||t.t!==g)return t={i:0,S:e,p:g.s,n:void 0,t:g,e:void 0,x:void 0,r:t},g.s!==void 0&&(g.s.n=t),g.s=t,e.n=t,32&g.f&&e.S(t),t;if(t.i===-1)return t.i=0,t.n!==void 0&&(t.n.p=t.p,t.p!==void 0&&(t.p.n=t.n),t.p=g.s,t.n=void 0,g.s.n=t,g.s=t),t}}function w(e,t){this.v=e,this.i=0,this.n=void 0,this.t=void 0,this.l=0,this.W=t?.watched,this.Z=t?.unwatched,this.name=t?.name}w.prototype.brand=gn;w.prototype.h=function(){return!0};w.prototype.S=function(e){var t=this,n=this.t;n!==e&&e.e===void 0&&(e.x=n,this.t=e,n!==void 0?n.e=e:xe(function(){var o;(o=t.W)==null||o.call(t)}))};w.prototype.U=function(e){var t=this;if(this.t!==void 0){var n=e.e,o=e.x;n!==void 0&&(n.x=o,e.e=void 0),o!==void 0&&(o.e=n,e.x=void 0),e===this.t&&(this.t=o,o===void 0&&xe(function(){var r;(r=t.Z)==null||r.call(t)}))}};w.prototype.subscribe=function(e){var t=this;return z(function(){var n=t.value,o=g;g=void 0;try{e(n)}finally{g=o}},{name:\"sub\"})};w.prototype.valueOf=function(){return this.value};w.prototype.toString=function(){return this.value+\"\"};w.prototype.toJSON=function(){return this.value};w.prototype.peek=function(){var e=this;return xe(function(){return e.value})};Object.defineProperty(w.prototype,\"value\",{get:function(){var e=$t(this);return e!==void 0&&(e.i=this.i),this.v},set:function(e){if(e!==this.v){if(ve>100)throw new Error(\"Cycle detected\");(function(n){F!==0&&ve===0&&n.l!==je&&(n.l=je,ge={S:n,v:n.v,i:n.i,o:ge})})(this),this.v=e,this.i++,ye++,F++;try{for(var t=this.t;t!==void 0;t=t.x)t.t.N()}finally{be()}}}});function b(e,t){return new w(e,t)}function Pt(e){for(var t=e.s;t!==void 0;t=t.n)if(t.S.i!==t.i||!t.S.h()||t.S.i!==t.i)return!0;return!1}function Mt(e){for(var t=e.s;t!==void 0;t=t.n){var n=t.S.n;if(n!==void 0&&(t.r=n),t.S.n=t,t.i=-1,t.n===void 0){e.s=t;break}}}function Lt(e){for(var t=e.s,n=void 0;t!==void 0;){var o=t.p;t.i===-1?(t.S.U(t),o!==void 0&&(o.n=t.n),t.n!==void 0&&(t.n.p=o)):n=t,t.S.n=t.r,t.r!==void 0&&(t.r=void 0),t=o}e.s=n}function j(e,t){w.call(this,void 0),this.x=e,this.s=void 0,this.g=ye-1,this.f=4,this.W=t?.watched,this.Z=t?.unwatched,this.name=t?.name}j.prototype=new w;j.prototype.h=function(){if(this.f&=-3,1&this.f)return!1;if((36&this.f)==32||(this.f&=-5,this.g===ye))return!0;if(this.g=ye,this.f|=1,this.i>0&&!Pt(this))return this.f&=-2,!0;var e=g;try{Mt(this),g=this;var t=this.x();(16&this.f||this.v!==t||this.i===0)&&(this.v=t,this.f&=-17,this.i++)}catch(n){this.v=n,this.f|=16,this.i++}return g=e,Lt(this),this.f&=-2,!0};j.prototype.S=function(e){if(this.t===void 0){this.f|=36;for(var t=this.s;t!==void 0;t=t.n)t.S.S(t)}w.prototype.S.call(this,e)};j.prototype.U=function(e){if(this.t!==void 0&&(w.prototype.U.call(this,e),this.t===void 0)){this.f&=-33;for(var t=this.s;t!==void 0;t=t.n)t.S.U(t)}};j.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var e=this.t;e!==void 0;e=e.x)e.t.N()}};Object.defineProperty(j.prototype,\"value\",{get:function(){if(1&this.f)throw new Error(\"Cycle detected\");var e=$t(this);if(this.h(),e!==void 0&&(e.i=this.i),16&this.f)throw this.v;return this.v}});function ke(e,t){return new j(e,t)}function Nt(e){var t=e.m;if(e.m=void 0,typeof t==\"function\"){F++;var n=g;g=void 0;try{t()}catch(o){throw e.f&=-2,e.f|=8,We(e),o}finally{g=n,be()}}}function We(e){for(var t=e.s;t!==void 0;t=t.n)t.S.U(t);e.x=void 0,e.s=void 0,Nt(e)}function bn(e){if(g!==this)throw new Error(\"Out-of-order effect\");Lt(this),g=e,this.f&=-2,8&this.f&&We(this),be()}function X(e,t){this.x=e,this.m=void 0,this.s=void 0,this.u=void 0,this.f=32,this.name=t?.name,Tt&&Tt.push(this)}X.prototype.c=function(){var e=this.S();try{if(8&this.f||this.x===void 0)return;var t=this.x();typeof t==\"function\"&&(this.m=t)}finally{e()}};X.prototype.S=function(){if(1&this.f)throw new Error(\"Cycle detected\");this.f|=1,this.f&=-9,Nt(this),Mt(this),F++;var e=g;return g=this,bn.bind(this,e)};X.prototype.N=function(){2&this.f||(this.f|=2,this.u=te,te=this)};X.prototype.d=function(){this.f|=8,1&this.f||We(this)};X.prototype.dispose=function(){this.d()};function z(e,t){var n=new X(e,t);try{n.c()}catch(r){throw n.d(),r}var o=n.d.bind(n);return o[Symbol.dispose]=o,o}var It,Ye,we,xn=typeof window<\"u\"&&!!window.__PREACT_SIGNALS_DEVTOOLS__;var Bt=[];z(function(){It=this.N})();function Z(e,t){m[e]=t.bind(null,m[e]||function(){})}function Ce(e){if(we){var t=we;we=void 0,t()}we=e&&e.S()}function Rt(e){var t=this,n=e.data,o=wn(n);o.value=n;var r=He(function(){for(var c=t,f=t.__v;f=f.__;)if(f.__c){f.__c.__$f|=4;break}var l=ke(function(){var p=o.value.value;return p===0?0:p===!0?\"\":p||\"\"}),u=ke(function(){return!Array.isArray(l.value)&&!Ne(l.value)}),a=z(function(){if(this.N=Ut,u.value){var p=l.value;c.__v&&c.__v.__e&&c.__v.__e.nodeType===3&&(c.__v.__e.data=p)}}),_=t.__$u.d;return t.__$u.d=function(){a(),_.call(this)},[u,l]},[]),i=r[0],s=r[1];return i.value?s.peek():s.value}Rt.displayName=\"ReactiveTextNode\";Object.defineProperties(w.prototype,{constructor:{configurable:!0,value:void 0},type:{configurable:!0,value:Rt},props:{configurable:!0,get:function(){var e=this;return{data:{get value(){return e.value}}}}},__b:{configurable:!0,value:1}});Z(\"__b\",function(e,t){if(typeof t.type==\"string\"){var n,o=t.props;for(var r in o)if(r!==\"children\"){var i=o[r];i instanceof w&&(n||(t.__np=n={}),n[r]=i,o[r]=i.peek())}}e(t)});Z(\"__r\",function(e,t){if(e(t),t.type!==V){Ce();var n,o=t.__c;o&&(o.__$f&=-2,(n=o.__$u)===void 0&&(o.__$u=n=(function(r,i){var s;return z(function(){s=this},{name:i}),s.c=r,s})(function(){var r;xn&&((r=n.y)==null||r.call(n)),o.__$f|=1,o.setState({})},typeof t.type==\"function\"?t.type.displayName||t.type.name:\"\"))),Ye=o,Ce(n)}});Z(\"__e\",function(e,t,n,o){Ce(),Ye=void 0,e(t,n,o)});Z(\"diffed\",function(e,t){Ce(),Ye=void 0;var n;if(typeof t.type==\"string\"&&(n=t.__e)){var o=t.__np,r=t.props;if(o){var i=n.U;if(i)for(var s in i){var c=i[s];c!==void 0&&!(s in o)&&(c.d(),i[s]=void 0)}else i={},n.U=i;for(var f in o){var l=i[f],u=o[f];l===void 0?(l=kn(n,f,u),i[f]=l):l.o(u,r)}}}e(t)});function kn(e,t,n,o){var r=t in e&&e.ownerSVGElement===void 0,i=b(n),s=n.peek();return{o:function(c,f){i.value=c,s=c.peek()},d:z(function(){this.N=Ut;var c=i.value.value;s!==c?(s=void 0,r?e[t]=c:c!=null&&(c!==!1||t[4]===\"-\")?e.setAttribute(t,c):e.removeAttribute(t)):s=void 0})}}Z(\"unmount\",function(e,t){if(typeof t.type==\"string\"){var n=t.__e;if(n){var o=n.U;if(o){n.U=void 0;for(var r in o){var i=o[r];i&&i.d()}}}var s=t.__np;if(s){var c=t.props;for(var f in s)c[f]=s[f]}t.__np=void 0}else{var l=t.__c;if(l){var u=l.__$u;u&&(l.__$u=void 0,u.d())}}e(t)});Z(\"__h\",function(e,t,n,o){(o<3||o===9)&&(t.__$f|=2),e(t,n,o)});q.prototype.shouldComponentUpdate=function(e,t){if(this.__R)return!0;var n=this.__$u,o=n&&n.s!==void 0;for(var r in t)return!0;if(this.__f||typeof this.u==\"boolean\"&&this.u===!0){var i=2&this.__$f;if(!(o||i||4&this.__$f)||1&this.__$f)return!0}else if(!(o||4&this.__$f)||3&this.__$f)return!0;for(var s in e)if(s!==\"__source\"&&e[s]!==this.props[s])return!0;for(var c in this.props)if(!(c in e))return!0;return!1};function wn(e,t){return He(function(){return b(e,t)},[])}var Cn=function(e){queueMicrotask(function(){queueMicrotask(e)})};function Sn(){ze(function(){for(var e;e=Bt.shift();)It.call(e)})}function Ut(){Bt.push(this)===1&&(m.requestAnimationFrame||Cn)(Sn)}var x=b([]),A=b(\"view\"),W=b(\"dark\"),Se=b(null),ne=b(\"\"),Ft=b(0),Dt=b(!1),I=b({kind:\"human\",id:\"human\",displayName:\"You\"}),E=b(\"element\"),T=b(null),$=b(null),P=b([]),B=b(null),Ae=b(0),L=b([]);function R(e,t){let n=Se.value,o={type:e,timestamp:new Date().toISOString(),sessionId:ne.value,sequence:++Ft.value,payload:t};if(n)try{fetch(n,{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify(o),keepalive:!0}).catch(r=>console.warn(\"[annotations] webhook emit failed\",r))}catch(r){console.warn(\"[annotations] webhook emit threw synchronously\",r)}}var G={version:\"0.1.0\",schema:\"afs-1.1\",addAnnotation(e){let t=e.id??`ann_${_e().slice(-12).toLowerCase()}`,n=Date.now(),o={id:t,comment:e.comment,elementPath:e.elementPath,element:e.element,x:e.x,y:e.y,timestamp:e.timestamp??n,url:e.url,boundingBox:e.boundingBox,reactComponents:e.reactComponents,cssClasses:e.cssClasses,computedStyles:e.computedStyles,accessibility:e.accessibility,nearbyText:e.nearbyText,selectedText:e.selectedText,isFixed:e.isFixed,isMultiSelect:e.isMultiSelect,fullPath:e.fullPath,nearbyElements:e.nearbyElements,elementBoundingBoxes:e.elementBoundingBoxes,intent:e.intent,severity:e.severity,kind:e.kind??\"feedback\",placement:e.placement,rearrange:e.rearrange,status:e.status??\"pending\",thread:[],author:e.author??{kind:\"agent\",id:\"agent\",displayName:\"Agent\"},createdAt:new Date(n).toISOString(),updatedAt:new Date(n).toISOString()};return x.value=[...x.value,o],R(\"annotation.created\",o),t},replyToAnnotation(e,t){if(!x.value.find(r=>r.id===e))return null;let o={id:`msg_${_e().slice(-10).toLowerCase()}`,role:t.role,content:t.content,timestamp:Date.now()};return x.value=x.value.map(r=>r.id===e?{...r,thread:[...r.thread??[],o],updatedAt:new Date().toISOString()}:r),R(\"thread.message\",{annotationId:e,message:o}),o.id},updateAnnotation(e,t){let n=!1;return x.value=x.value.map(o=>o.id!==e?o:(n=!0,{...o,...t,updatedAt:new Date().toISOString()})),n&&R(\"annotation.updated\",{id:e,patch:t}),n},acknowledgeAnnotation(e){return this.updateAnnotation(e,{status:\"acknowledged\"})},resolveAnnotation(e,t=\"agent\"){return this.updateAnnotation(e,{status:\"resolved\",resolvedAt:new Date().toISOString(),resolvedBy:t})},dismissAnnotation(e){return this.updateAnnotation(e,{status:\"dismissed\"})},removeAnnotation(e){let t=x.value.length;x.value=x.value.filter(o=>o.id!==e);let n=x.value.length<t;return n&&R(\"annotation.deleted\",{id:e}),n},clearAnnotations(){let e=x.value.length;return x.value=[],B.value=null,R(\"session.updated\",{cleared:e}),e},focusAnnotation(e){let t=x.value.some(n=>n.id===e);return t&&(B.value=e),t},closeThread(){B.value=null},setCursors(e){L.value=e},setCursor(e){let t=L.value.filter(n=>n.id!==e.id);L.value=[...t,e]},removeCursor(e){let t=L.value.length;return L.value=L.value.filter(n=>n.id!==e),L.value.length<t},clearCursors(){L.value=[]},setMode(e){A.value!==e&&(A.value=e,R(\"session.updated\",{mode:e}))},setTheme(e){W.value=e},getAnnotations(){return x.value}};function Ot(e){e.webhookUrl!==void 0&&(Se.value=e.webhookUrl),ne.value=e.sessionId??`cf_${_e().slice(-12).toLowerCase()}`,R(\"session.created\",{sessionId:ne.value,pageUrl:typeof location<\"u\"?location.href:\"\"})}var An=[\"display\",\"position\",\"width\",\"height\",\"margin\",\"padding\",\"color\",\"background-color\",\"background\",\"font-family\",\"font-size\",\"font-weight\",\"line-height\",\"border\",\"border-radius\",\"box-shadow\",\"flex-direction\",\"justify-content\",\"align-items\",\"gap\",\"grid-template-columns\",\"z-index\",\"opacity\",\"text-align\"],En=[\"role\",\"aria-label\",\"aria-labelledby\",\"aria-describedby\",\"aria-hidden\",\"aria-expanded\",\"aria-checked\",\"aria-selected\",\"alt\",\"title\",\"tabindex\",\"type\",\"name\",\"for\",\"href\"];function Ee(e){let t=e.getBoundingClientRect(),n=Fn(e),o=window.scrollX,r=window.scrollY,i={x:t.left+(n?0:o),y:t.top+(n?0:r),width:t.width,height:t.height};return{element:e.tagName.toLowerCase(),elementPath:Tn(e),fullPath:$n(e),x:Dn((t.left+t.width/2)/window.innerWidth*100),y:n?t.top:t.top+r,url:location.href,boundingBox:i,isFixed:n,cssClasses:Pn(e),computedStyles:Mn(e),accessibility:Ln(e),nearbyText:Nn(e),nearbyElements:In(e),reactComponents:Rn(e)}}function Tn(e){if(e.id&&Ht(e.id))return`#${Ke(e.id)}`;let t=e.getAttribute(\"data-testid\");if(t)return`[data-testid=\"${t}\"]`;let n=e.tagName.toLowerCase(),o=jt(e);return o?`${n}.${Ke(o)}`:n}function $n(e){let t=[],n=e;for(;n&&n.nodeType===1&&n.tagName.toLowerCase()!==\"html\";){if(n.id&&Ht(n.id)){t.unshift(`#${Ke(n.id)}`);break}let o=n.tagName.toLowerCase(),r=n.parentElement;if(r){let i=Array.from(r.children).filter(s=>s.tagName===n.tagName);i.length>1&&(o+=`:nth-of-type(${i.indexOf(n)+1})`)}t.unshift(o),n=r}return t.join(\" > \")}function Ve(e){if(!e)return null;try{return document.querySelector(e)}catch{return null}}function Ht(e){return!(e.length>40||/^[:]?r[a-z0-9]+[:]?$/i.test(e)||/^(radix|headlessui|mui|react-aria)[-:]/i.test(e))}function jt(e){for(let t of Array.from(e.classList))if(!(/^[a-z0-9_-]*[a-f0-9]{6,}$/i.test(t)&&/\\d/.test(t))&&!t.startsWith(\"cf-\"))return t;return e.classList[0]??null}function Ke(e){return typeof CSS<\"u\"&&typeof CSS.escape==\"function\"?CSS.escape(e):e.replace(/([^\\w-])/g,\"\\\\$1\")}function Pn(e){let t=Array.from(e.classList).filter(n=>!n.startsWith(\"cf-\"));return t.length?t.join(\" \"):void 0}function Mn(e){let t=window.getComputedStyle(e),n=[];for(let o of An){let r=t.getPropertyValue(o);r&&r!==\"none\"&&r!==\"normal\"&&r!==\"auto\"&&n.push(`${o}: ${r};`)}return n.length?n.join(`\n`):void 0}function Ln(e){let t=[];for(let o of En){let r=e.getAttribute(o);r!==null&&r!==\"\"&&t.push(`${o}=\"${r}\"`)}let n=Bn(e);return n&&t.push(`text=\"${Xe(n,60)}\"`),t.length?t.join(\" \"):void 0}function Nn(e){let t=(e.textContent??\"\").replace(/\\s+/g,\" \").trim();if(t)return Xe(t,200)}function In(e){let t=[];e.parentElement&&t.push(`parent: ${qe(e.parentElement)}`);let n=e.previousElementSibling;n&&t.push(`prev: ${qe(n)}`);let o=e.nextElementSibling;return o&&t.push(`next: ${qe(o)}`),t.length?t.join(\" | \"):void 0}function qe(e){let t=e.tagName.toLowerCase(),n=jt(e),o=(e.textContent??\"\").replace(/\\s+/g,\" \").trim().slice(0,30);return`${t}${n?`.${n}`:\"\"}${o?` \"${o}\"`:\"\"}`}function Bn(e){let t=\"\";for(let n of Array.from(e.childNodes))n.nodeType===3&&(t+=n.textContent??\"\");return t.replace(/\\s+/g,\" \").trim()}function Rn(e){let t=Object.keys(e).find(f=>f.startsWith(\"__reactFiber$\")||f.startsWith(\"__reactInternalInstance$\"));if(!t)return;let n=e[t],o=[],r,i=0;for(;n&&i<30;){let f=n.type,l=typeof f==\"function\"?f.displayName??f.name:void 0;if(l&&/^[A-Z]/.test(l)&&!o.includes(l)&&(o.push(l),!r&&n.memoizedProps&&(r=n.memoizedProps),o.length>=3))break;n=n.return,i++}if(!o.length)return;let s=o[0],c=r?Un(r):\"\";return c?`${s} (${c})`:s}function Un(e){let t=[];for(let[n,o]of Object.entries(e))if(n!==\"children\"&&(typeof o==\"string\"?t.push(`${n}=${JSON.stringify(Xe(o,40))}`):(typeof o==\"number\"||typeof o==\"boolean\")&&t.push(`${n}=${o}`),t.length>=5))break;return t.join(\", \")}function Fn(e){let t=e,n=0;for(;t&&n<20;){if(window.getComputedStyle(t).position===\"fixed\")return!0;t=t.parentElement,n++}return!1}function Xe(e,t){return e.length>t?`${e.slice(0,t-1)}\\u2026`:e}function Dn(e){return Math.max(0,Math.min(100,Math.round(e*10)/10))}var Ze=null,zt=!1,Wt=0;function On(e){let t=Date.now();t-Wt<120||(Wt=t,R(\"presence.cursor\",{id:I.value.id??\"human\",label:I.value.displayName??\"You\",kind:I.value.kind,x:e.clientX/window.innerWidth*100,y:e.clientY+window.scrollY}))}function Yt(e){Ze=e}function Ge(e){return Ze?e.composedPath().includes(Ze):!1}function qt(e){return!(e instanceof Element)||e.tagName===\"HTML\"||e.tagName===\"BODY\"?null:e}function Hn(e){if(Ge(e)||On(e),A.value!==\"feedback\"||$.value){T.value=null;return}if(Ge(e)){T.value=null;return}if(E.value===\"text\"){T.value=null;return}let t=qt(e.target);if(!t){T.value=null;return}let n=t.getBoundingClientRect();T.value={top:n.top,left:n.left,width:n.width,height:n.height}}function jn(e){if(A.value!==\"feedback\"||Ge(e)||E.value===\"text\"||$.value)return;let t=qt(e.target);if(t){if(e.preventDefault(),e.stopPropagation(),E.value===\"multi\"){Yn(t);return}Je(Ee(t))}}function zn(){if(A.value!==\"feedback\"||E.value!==\"text\"||$.value)return;let e=window.getSelection(),t=e?.toString().trim();if(!t||!e||e.rangeCount===0)return;let n=e.getRangeAt(0),o=n.commonAncestorContainer.nodeType===1?n.commonAncestorContainer:n.commonAncestorContainer.parentElement;if(!o)return;let r=Ee(o);Je({...r,selectedText:t})}function Wn(e){if(e.key===\"Escape\"){if($.value){$.value=null;return}if(P.value.length){P.value=[],T.value=null;return}A.value===\"feedback\"&&(A.value=\"view\",T.value=null)}}function Yn(e){let t=P.value;P.value=t.includes(e)?t.filter(n=>n!==e):[...t,e]}function Kt(){let e=P.value;if(!e.length)return;let t=Ee(e[0]),n=e.map(r=>{let i=r.getBoundingClientRect();return{x:i.left+window.scrollX,y:i.top+window.scrollY,width:i.width,height:i.height}}),o=e.map(r=>r.tagName.toLowerCase()).join(\", \");Je({...t,isMultiSelect:!0,elementBoundingBoxes:n,nearbyElements:`${e.length} elements: ${o}`})}function Je(e){P.value=[],T.value=null,$.value=e}function Vt(){zt||(zt=!0,document.addEventListener(\"mousemove\",Hn,!0),document.addEventListener(\"click\",jn,!0),document.addEventListener(\"mouseup\",zn,!0),document.addEventListener(\"keydown\",Wn,!0))}var Xt=\"annotations-v1-host\",qn=`\n:host {\n all: initial;\n contain: layout style;\n font-family: -apple-system, \"SF Pro Text\", system-ui, sans-serif;\n font-size: 14px;\n line-height: 1.45;\n color: #f4f4f4;\n}\n*, *::before, *::after { box-sizing: border-box; }\nbutton { font: inherit; cursor: pointer; }\n[hidden] { display: none !important; }\n`,oe=null;function Zt(){if(oe&&document.contains(oe.host))return oe;let e=document.getElementById(Xt);e&&e.remove();let t=document.createElement(\"div\");t.id=Xt,t.style.cssText=[\"all: initial\",\"position: fixed\",\"inset: 0\",\"pointer-events: none\",\"z-index: 2147483647\"].join(\";\");let n=t.attachShadow({mode:\"closed\"}),o=document.createElement(\"style\");o.textContent=qn,n.appendChild(o);let r=document.createElement(\"div\");return r.id=\"cf-app\",r.style.cssText=\"pointer-events: auto;\",n.appendChild(r),document.documentElement.appendChild(t),oe={host:t,shadow:n,appRoot:r},oe}var Gt=`\n.cf-overlay {\n position: fixed;\n inset: 0;\n pointer-events: none;\n font-family: -apple-system, \"SF Pro Text\", system-ui, sans-serif;\n font-size: 13px;\n color: #f4f4f5;\n --cf-bg: rgba(18, 18, 22, 0.96);\n --cf-border: rgba(255, 255, 255, 0.1);\n --cf-muted: rgba(255, 255, 255, 0.55);\n --cf-accent: #a78bfa;\n}\n.cf-overlay[data-theme=\"light\"] {\n color: #18181b;\n --cf-bg: rgba(252, 252, 253, 0.97);\n --cf-border: rgba(0, 0, 0, 0.1);\n --cf-muted: rgba(0, 0, 0, 0.5);\n}\n\n/* Hover highlight + multi-select boxes */\n.cf-hover {\n position: fixed;\n pointer-events: none;\n border: 2px solid var(--cf-accent);\n background: rgba(167, 139, 250, 0.1);\n border-radius: 4px;\n box-shadow: 0 0 0 1px rgba(167, 139, 250, 0.4);\n transition: top .06s ease, left .06s ease, width .06s ease, height .06s ease;\n z-index: 1;\n}\n.cf-multi-box {\n position: fixed;\n pointer-events: none;\n border: 2px solid #3ecf8e;\n background: rgba(62, 207, 142, 0.12);\n border-radius: 4px;\n z-index: 1;\n animation: cf-multi-pulse 1.4s ease-in-out infinite;\n}\n@keyframes cf-multi-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(62,207,142,0.0); }\n 50% { box-shadow: 0 0 0 3px rgba(62,207,142,0.25); }\n}\n\n/* Live presence cursors (multi-cursor collaboration) */\n.cf-cursor {\n position: fixed;\n z-index: 6;\n pointer-events: none;\n display: flex;\n align-items: flex-start;\n gap: 4px;\n /* Glide to new positions so multiple actors read as \"live\". */\n transition: top .12s ease, left .12s ease;\n will-change: top, left;\n}\n.cf-cursor-arrow { display: block; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.4)); }\n.cf-cursor-label {\n transform: translateY(2px);\n background: var(--cf-cursor, #a78bfa);\n color: #0b0b0f;\n font: 700 11px -apple-system, system-ui;\n padding: 2px 7px;\n border-radius: 8px;\n white-space: nowrap;\n box-shadow: 0 2px 8px rgba(0,0,0,0.35);\n}\n.cf-cursor-human .cf-cursor-label { color: #18181b; }\n.cf-cursor-agent .cf-cursor-label { color: #0b0b0f; }\n\n/* Pins */\n.cf-pin {\n position: fixed;\n width: 22px; height: 22px;\n border-radius: 50% 50% 50% 2px;\n background: var(--cf-pin, #a78bfa);\n color: #fff;\n border: 2px solid rgba(255,255,255,0.9);\n font: 700 11px -apple-system, system-ui;\n display: flex; align-items: center; justify-content: center;\n cursor: pointer;\n pointer-events: auto;\n box-shadow: 0 2px 8px rgba(0,0,0,0.35);\n z-index: 3;\n transition: transform .12s cubic-bezier(.34,1.56,.64,1);\n padding: 0;\n /* Pop in when a pin first renders so new annotations are obvious. */\n animation: cf-pin-pop .32s cubic-bezier(.34,1.56,.64,1) both;\n}\n.cf-pin:hover { transform: scale(1.2); }\n.cf-pin.resolved { opacity: 0.45; }\n/* Agent-pushed pins pulse a ring so reviewers spot what the agent added. */\n.cf-pin.agent { border-style: dashed; }\n.cf-pin.agent::after {\n content: \"\";\n position: absolute; inset: -4px;\n border-radius: inherit;\n border: 2px solid var(--cf-pin, #a78bfa);\n animation: cf-pin-ring 1.6s ease-out 3;\n pointer-events: none;\n}\n\n@keyframes cf-pin-pop {\n 0% { transform: scale(0); opacity: 0; }\n 60% { transform: scale(1.25); opacity: 1; }\n 100% { transform: scale(1); opacity: 1; }\n}\n@keyframes cf-pin-ring {\n 0% { transform: scale(1); opacity: .7; }\n 100% { transform: scale(2.4); opacity: 0; }\n}\n\n/* Toolbar */\n.cf-toolbar {\n position: fixed;\n left: 16px; bottom: 16px;\n pointer-events: auto;\n background: var(--cf-bg);\n border: 1px solid var(--cf-border);\n border-radius: 14px;\n padding: 10px;\n display: flex; flex-direction: column; gap: 8px;\n backdrop-filter: blur(16px) saturate(140%);\n box-shadow: 0 16px 48px rgba(0,0,0,0.5);\n min-width: 220px;\n z-index: 4;\n}\n.cf-toolbar-head {\n display: flex; align-items: center; gap: 7px;\n font-weight: 700; letter-spacing: 0.02em;\n}\n.cf-logo-dot {\n width: 8px; height: 8px; border-radius: 50%;\n background: var(--cf-accent);\n box-shadow: 0 0 10px var(--cf-accent);\n}\n.cf-count {\n margin-left: auto;\n font: 700 11px -apple-system, system-ui;\n color: var(--cf-muted);\n background: rgba(255,255,255,0.08);\n padding: 1px 7px; border-radius: 8px;\n}\n.cf-overlay[data-theme=\"light\"] .cf-count { background: rgba(0,0,0,0.06); }\n\n.cf-seg {\n display: flex; gap: 2px;\n background: rgba(255,255,255,0.06);\n border-radius: 9px; padding: 2px;\n}\n.cf-overlay[data-theme=\"light\"] .cf-seg { background: rgba(0,0,0,0.05); }\n.cf-seg-btn {\n flex: 1; border: none; background: transparent; color: var(--cf-muted);\n padding: 5px 10px; border-radius: 7px; font: 600 12px -apple-system, system-ui;\n}\n.cf-seg-btn.on {\n background: var(--cf-accent); color: #fff;\n box-shadow: 0 1px 4px rgba(0,0,0,0.3);\n}\n.cf-tools .cf-seg-btn.on { background: rgba(255,255,255,0.16); color: #fff; }\n.cf-overlay[data-theme=\"light\"] .cf-tools .cf-seg-btn.on { background: rgba(0,0,0,0.12); color: #111; }\n.cf-hint { font-size: 11px; color: var(--cf-muted); padding: 0 2px; }\n.cf-commit { width: 100%; }\n\n/* Buttons */\n.cf-btn {\n border: 1px solid var(--cf-border); background: transparent; color: inherit;\n padding: 6px 12px; border-radius: 8px; font: 600 12px -apple-system, system-ui;\n}\n.cf-btn:hover { background: rgba(255,255,255,0.06); }\n.cf-overlay[data-theme=\"light\"] .cf-btn:hover { background: rgba(0,0,0,0.04); }\n.cf-btn-primary {\n background: var(--cf-accent); border-color: var(--cf-accent); color: #fff;\n}\n.cf-btn-primary:hover { background: #9173f0; }\n.cf-btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }\n.cf-btn-ghost { border-color: transparent; color: var(--cf-muted); }\n\n/* Popups (composer + thread) */\n.cf-popup {\n position: fixed;\n left: 16px; bottom: 92px;\n width: 320px;\n pointer-events: auto;\n background: var(--cf-bg);\n border: 1px solid var(--cf-border);\n border-radius: 14px;\n padding: 12px;\n display: flex; flex-direction: column; gap: 10px;\n backdrop-filter: blur(16px) saturate(140%);\n box-shadow: 0 16px 48px rgba(0,0,0,0.55);\n z-index: 5;\n animation: cf-rise .2s cubic-bezier(.16,1,.3,1) both;\n}\n@keyframes cf-rise {\n from { transform: translateY(10px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n.cf-popup-head {\n display: flex; align-items: center; gap: 8px;\n}\n.cf-popup-target {\n font: 600 12px ui-monospace, \"SF Mono\", monospace;\n color: var(--cf-accent);\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n}\n.cf-icon-btn {\n margin-left: auto; border: none; background: transparent;\n color: var(--cf-muted); font-size: 13px; cursor: pointer;\n width: 22px; height: 22px; border-radius: 6px;\n}\n.cf-icon-btn:hover { background: rgba(255,255,255,0.08); }\n\n.cf-textarea {\n width: 100%; min-height: 72px; resize: vertical;\n background: rgba(255,255,255,0.04);\n border: 1px solid var(--cf-border); border-radius: 9px;\n padding: 8px 10px; color: inherit; font: 400 13px -apple-system, system-ui;\n line-height: 1.45;\n}\n.cf-overlay[data-theme=\"light\"] .cf-textarea { background: rgba(0,0,0,0.03); }\n.cf-textarea:focus { outline: none; border-color: var(--cf-accent); }\n.cf-textarea-sm { min-height: 48px; }\n\n.cf-field { display: flex; flex-direction: column; gap: 5px; }\n.cf-field-label {\n font: 700 10px -apple-system, system-ui; letter-spacing: 0.06em;\n text-transform: uppercase; color: var(--cf-muted);\n}\n.cf-chipset { display: flex; flex-wrap: wrap; gap: 5px; }\n.cf-chip {\n border: 1px solid var(--cf-border); background: transparent; color: var(--cf-muted);\n padding: 4px 10px; border-radius: 20px; font: 600 11px -apple-system, system-ui;\n text-transform: capitalize;\n}\n.cf-chip.on {\n background: var(--cf-chip, var(--cf-accent));\n border-color: var(--cf-chip, var(--cf-accent));\n color: #fff;\n}\n.cf-popup-actions { display: flex; gap: 8px; justify-content: flex-end; }\n\n/* Thread */\n.cf-thread-body {\n display: flex; flex-direction: column; gap: 12px;\n max-height: 280px; overflow-y: auto; padding-right: 2px;\n}\n.cf-msg { display: flex; flex-direction: column; gap: 3px; }\n.cf-msg-meta { display: flex; align-items: center; gap: 6px; }\n.cf-avatar { font-size: 12px; }\n.cf-msg-name {\n font: 700 11px -apple-system, system-ui; color: var(--cf-muted);\n}\n.cf-msg-body {\n font-size: 13px; line-height: 1.5; white-space: pre-wrap; word-break: break-word;\n background: rgba(255,255,255,0.04); border-radius: 9px; padding: 7px 10px;\n}\n.cf-overlay[data-theme=\"light\"] .cf-msg-body { background: rgba(0,0,0,0.03); }\n.cf-msg-agent .cf-msg-body { border-left: 2px solid var(--cf-accent); }\n.cf-thread-compose { display: flex; flex-direction: column; gap: 8px; }\n.cf-thread-actions { display: flex; gap: 8px; align-items: center; }\n.cf-thread-actions .cf-btn-primary { margin-left: auto; }\n.cf-resolved-tag { font: 600 11px -apple-system, system-ui; color: #3ecf8e; }\n.cf-tag {\n font: 700 9px -apple-system, system-ui; text-transform: uppercase;\n letter-spacing: 0.05em; padding: 2px 6px; border-radius: 5px;\n background: var(--cf-tag, var(--cf-accent)); color: #fff;\n}\n\n/* Respect reduced-motion: keep the UI usable, drop the motion. */\n@media (prefers-reduced-motion: reduce) {\n .cf-pin, .cf-popup, .cf-multi-box { animation: none !important; }\n .cf-pin.agent::after { display: none; }\n}\n`;var Qe={blocking:\"#ef4444\",important:\"#f59e0b\",suggestion:\"#3ecf8e\"},Kn=\"#a78bfa\",Vn=[\"fix\",\"change\",\"question\",\"approve\"],Xn=[\"blocking\",\"important\",\"suggestion\"];function tn(){let e=W.value===\"auto\"?\"dark\":W.value;return Ae.value,d(\"div\",{class:\"cf-overlay\",\"data-theme\":e},[d(\"style\",{key:\"styles\"},Gt),T.value&&!$.value?d(\"div\",{key:\"hover\",class:\"cf-hover\",style:nn(T.value)}):null,...P.value.map((t,n)=>eo(t,n)),d(\"div\",{key:\"pins\"},x.value.map((t,n)=>Jn(t,n+1))),d(\"div\",{key:\"cursors\"},L.value.map(t=>to(t))),Zn(),$.value?d(oo,{key:\"composer\",target:$.value}):null,B.value?d(io,{key:\"thread\",id:B.value}):null])}function Zn(){let e=A.value===\"feedback\",t=x.value.length,n=P.value.length;return d(\"div\",{key:\"toolbar\",class:\"cf-toolbar\"},[d(\"div\",{key:\"head\",class:\"cf-toolbar-head\"},[d(\"span\",{key:\"dot\",class:\"cf-logo-dot\"}),d(\"span\",{key:\"label\"},\"Annotations\"),d(\"span\",{key:\"count\",class:\"cf-count\"},String(t))]),d(\"div\",{key:\"modes\",class:\"cf-seg\"},[re(\"View\",A.value===\"view\",()=>{A.value=\"view\",T.value=null,P.value=[]}),re(\"Comment\",e,()=>{A.value=\"feedback\"})]),e?d(\"div\",{key:\"tools\",class:\"cf-seg cf-tools\"},[re(\"Element\",E.value===\"element\",()=>{E.value=\"element\",P.value=[]}),re(\"Text\",E.value===\"text\",()=>{E.value=\"text\",P.value=[]}),re(\"Multi\",E.value===\"multi\",()=>{E.value=\"multi\"})]):null,e&&E.value===\"multi\"&&n?d(\"button\",{key:\"commit\",class:\"cf-btn cf-btn-primary cf-commit\",onClick:Kt},`Comment ${n} element${n===1?\"\":\"s\"}`):null,e?d(\"div\",{key:\"hint\",class:\"cf-hint\"},Gn(E.value)):null])}function Gn(e){return e===\"text\"?\"Select text on the page to annotate it.\":e===\"multi\"?\"Click elements to group them, then commit.\":\"Click any element to comment. Esc to exit.\"}function re(e,t,n){return d(\"button\",{key:e,class:`cf-seg-btn${t?\" on\":\"\"}`,onClick:n},e)}function Jn(e,t){let n=Qn(e);if(!n)return null;let o=e.severity?Qe[e.severity]:Kn,r=e.status===\"resolved\"||e.status===\"dismissed\";return d(\"button\",{key:e.id,class:`cf-pin${r?\" resolved\":\"\"}${e.author?.kind===\"agent\"?\" agent\":\"\"}`,style:`top:${n.top}px;left:${n.left}px;--cf-pin:${o};`,title:ao(e.comment),onClick:()=>{B.value=B.value===e.id?null:e.id}},e.author?.kind===\"agent\"?\"\\u2605\":String(t))}function Qn(e){let t=Ve(e.fullPath??\"\")??Ve(e.elementPath??\"\");if(t){let n=t.getBoundingClientRect();return{top:n.top-11,left:n.left-11}}return e.boundingBox?{top:e.boundingBox.y-(e.isFixed?0:window.scrollY)-11,left:e.boundingBox.x-(e.isFixed?0:window.scrollX)-11}:null}function eo(e,t){let n=e.getBoundingClientRect();return d(\"div\",{key:`multi-${t}`,class:\"cf-multi-box\",style:nn({top:n.top,left:n.left,width:n.width,height:n.height})})}var Jt=[\"#a78bfa\",\"#3ecf8e\",\"#f59e0b\",\"#38bdf8\",\"#f472b6\"];function to(e){let t=e.x/100*window.innerWidth,n=e.y-window.scrollY,o=e.color??(e.kind===\"agent\"?Jt[Math.abs(no(e.id))%Jt.length]:\"#ffffff\");return d(\"div\",{key:`cursor-${e.id}`,class:`cf-cursor cf-cursor-${e.kind}`,style:`top:${n}px;left:${t}px;--cf-cursor:${o};`},[d(\"svg\",{key:\"arrow\",width:\"18\",height:\"18\",viewBox:\"0 0 18 18\",class:\"cf-cursor-arrow\"},d(\"path\",{d:\"M2 2 L2 14 L6 10 L9 16 L11 15 L8 9 L14 9 Z\",fill:o,stroke:\"rgba(0,0,0,0.35)\",\"stroke-width\":\"0.75\"})),d(\"span\",{key:\"label\",class:\"cf-cursor-label\"},`${e.kind===\"agent\"?\"\\u{1F916} \":\"\"}${e.label}`)])}function no(e){let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n);return t}function oo({target:e}){let[t,n]=ee(\"\"),[o,r]=ee(\"change\"),[i,s]=ee(\"important\"),c=()=>{let u=t.trim();u&&(G.addAnnotation({...e,comment:u,intent:o,severity:i,kind:\"feedback\",author:I.value}),$.value=null)},f=()=>{$.value=null},l=e.isMultiSelect?`${e.elementBoundingBoxes?.length??0} elements`:e.selectedText?`\"${so(e.selectedText,40)}\"`:`<${e.element}>`;return d(\"div\",{class:\"cf-popup cf-composer\"},[d(\"div\",{key:\"head\",class:\"cf-popup-head\"},[d(\"span\",{key:\"t\",class:\"cf-popup-target\"},l),d(\"button\",{key:\"x\",class:\"cf-icon-btn\",onClick:f,title:\"Cancel\"},\"\\u2715\")]),d(\"textarea\",{key:\"ta\",class:\"cf-textarea\",placeholder:\"Describe the change\\u2026 (Markdown supported)\",autofocus:!0,value:t,onInput:u=>n(u.target.value),onKeyDown:u=>{(u.metaKey||u.ctrlKey)&&u.key===\"Enter\"&&c()}}),d(\"div\",{key:\"intent\",class:\"cf-field\"},[d(\"span\",{key:\"l\",class:\"cf-field-label\"},\"Intent\"),d(\"div\",{key:\"g\",class:\"cf-chipset\"},Vn.map(u=>Qt(u,o===u,ro,()=>r(u))))]),d(\"div\",{key:\"sev\",class:\"cf-field\"},[d(\"span\",{key:\"l\",class:\"cf-field-label\"},\"Severity\"),d(\"div\",{key:\"g\",class:\"cf-chipset\"},Xn.map(u=>Qt(u,i===u,Qe[u],()=>s(u))))]),d(\"div\",{key:\"actions\",class:\"cf-popup-actions\"},[d(\"button\",{key:\"c\",class:\"cf-btn\",onClick:f},\"Cancel\"),d(\"button\",{key:\"s\",class:\"cf-btn cf-btn-primary\",disabled:!t.trim(),onClick:c},\"Comment\")])])}var ro=\"#8b94a3\";function Qt(e,t,n,o){return d(\"button\",{key:e,class:`cf-chip${t?\" on\":\"\"}`,style:t?`--cf-chip:${n};`:void 0,onClick:o},e)}function io({id:e}){let[t,n]=ee(\"\"),o=x.value.find(i=>i.id===e);if(!o)return null;let r=()=>{let i=t.trim();i&&(G.replyToAnnotation(e,{role:I.value.kind,content:i}),n(\"\"))};return d(\"div\",{class:\"cf-popup cf-thread\"},[d(\"div\",{key:\"head\",class:\"cf-popup-head\"},[d(\"span\",{key:\"t\",class:\"cf-popup-target\"},`<${o.element}>`),o.severity?d(\"span\",{key:\"sev\",class:\"cf-tag\",style:`--cf-tag:${Qe[o.severity]};`},o.severity):null,d(\"button\",{key:\"x\",class:\"cf-icon-btn\",onClick:()=>B.value=null,title:\"Close\"},\"\\u2715\")]),d(\"div\",{key:\"body\",class:\"cf-thread-body\"},[en(o.author?.kind??\"human\",o.author?.displayName??\"You\",o.comment,\"root\"),...(o.thread??[]).map(i=>en(i.role,i.role===\"agent\"?\"Agent\":\"You\",i.content,i.id))]),d(\"div\",{key:\"compose\",class:\"cf-thread-compose\"},[d(\"textarea\",{key:\"ta\",class:\"cf-textarea cf-textarea-sm\",placeholder:\"Reply\\u2026\",value:t,onInput:i=>n(i.target.value),onKeyDown:i=>{(i.metaKey||i.ctrlKey)&&i.key===\"Enter\"&&r()}}),d(\"div\",{key:\"row\",class:\"cf-thread-actions\"},[o.status!==\"resolved\"?d(\"button\",{key:\"resolve\",class:\"cf-btn cf-btn-ghost\",onClick:()=>G.resolveAnnotation(e,I.value.kind)},\"Resolve\"):d(\"span\",{key:\"resolved\",class:\"cf-resolved-tag\"},\"\\u2713 resolved\"),d(\"button\",{key:\"send\",class:\"cf-btn cf-btn-primary\",disabled:!t.trim(),onClick:r},\"Reply\")])])])}function en(e,t,n,o){return d(\"div\",{key:o,class:`cf-msg cf-msg-${e}`},[d(\"div\",{key:\"meta\",class:\"cf-msg-meta\"},[d(\"span\",{key:\"av\",class:`cf-avatar cf-avatar-${e}`},e===\"agent\"?\"\\u{1F916}\":\"\\u{1F9D1}\"),d(\"span\",{key:\"n\",class:\"cf-msg-name\"},t)]),d(\"div\",{key:\"c\",class:\"cf-msg-body\"},n)])}function nn(e){return`top:${e.top}px;left:${e.left}px;width:${e.width}px;height:${e.height}px;`}function ao(e){let t=e.trim(),n=t.indexOf(`\n`);return n>0?t.slice(0,n):t}function so(e,t){return e.length>t?`${e.slice(0,t-1)}\\u2026`:e}var on=!1;function rn(e={}){Ot(e),e.author&&(I.value=e.author),e.mode&&(A.value=e.mode),e.theme&&(W.value=e.theme),an(),Dt.value=!0,console.info(\"[annotations v1] ready on\",location.href)}function an(){if(on||typeof document>\"u\")return;if(!document.documentElement){document.addEventListener(\"DOMContentLoaded\",an,{once:!0});return}on=!0;let{host:e,appRoot:t}=Zt();Yt(e),Vt(),mt(d(tn,{}),t);let n=()=>{Ae.value++};window.addEventListener(\"scroll\",n,{passive:!0,capture:!0}),window.addEventListener(\"resize\",n,{passive:!0})}var lo=Object.assign({__init:rn},G);window.__annotations=lo;rn();})();\n";
|
|
5
|
+
"\"use strict\";(()=>{var Ye=Object.defineProperty;var De=(e,t,n)=>t in e?Ye(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var z=(e,t,n)=>De(e,typeof t!=\"symbol\"?t+\"\":t,n);var re=\"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";function O(e=Date.now()){let t=e,n=\"\";for(let r=0;r<10;r++)n=re[t&31]+n,t=Math.floor(t/32);let o=\"\";for(let r=0;r<16;r++)o+=re[Math.floor(Math.random()*32)];return n+o}var Y=class{constructor(t){z(this,\"_value\");z(this,\"_subs\",new Set);this._value=t}get value(){return this._value}set value(t){if(!Object.is(this._value,t)){this._value=t;for(let n of Array.from(this._subs))n(t)}}peek(){return this._value}subscribe(t){return this._subs.add(t),()=>{this._subs.delete(t)}}};function d(e){return new Y(e)}var l=d([]),u=d(\"view\"),T=d(\"dark\"),_=d(null),$=d(\"\"),ie=d(0),ae=d(!1),y=d({kind:\"human\",id:\"human\",displayName:\"You\"}),p=d(\"element\"),h=d(null),f=d(null),m=d([]),b=d(null),P=d(0),v=d([]);function w(e,t){let n=_.value,o={type:e,timestamp:new Date().toISOString(),sessionId:$.value,sequence:++ie.value,payload:t};if(n)try{fetch(n,{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify(o),keepalive:!0}).catch(r=>console.warn(\"[annotations] webhook emit failed\",r))}catch(r){console.warn(\"[annotations] webhook emit threw synchronously\",r)}}var A={version:\"0.1.0\",schema:\"afs-1.1\",addAnnotation(e){let t=e.id??`ann_${O().slice(-12).toLowerCase()}`,n=Date.now(),o={id:t,comment:e.comment,elementPath:e.elementPath,element:e.element,x:e.x,y:e.y,timestamp:e.timestamp??n,url:e.url,boundingBox:e.boundingBox,reactComponents:e.reactComponents,cssClasses:e.cssClasses,computedStyles:e.computedStyles,accessibility:e.accessibility,nearbyText:e.nearbyText,selectedText:e.selectedText,isFixed:e.isFixed,isMultiSelect:e.isMultiSelect,fullPath:e.fullPath,nearbyElements:e.nearbyElements,elementBoundingBoxes:e.elementBoundingBoxes,intent:e.intent,severity:e.severity,kind:e.kind??\"feedback\",placement:e.placement,rearrange:e.rearrange,status:e.status??\"pending\",thread:[],author:e.author??{kind:\"agent\",id:\"agent\",displayName:\"Agent\"},createdAt:new Date(n).toISOString(),updatedAt:new Date(n).toISOString()};return l.value=[...l.value,o],w(\"annotation.created\",o),t},replyToAnnotation(e,t){if(!l.value.find(r=>r.id===e))return null;let o={id:`msg_${O().slice(-10).toLowerCase()}`,role:t.role,content:t.content,timestamp:Date.now()};return l.value=l.value.map(r=>r.id===e?{...r,thread:[...r.thread??[],o],updatedAt:new Date().toISOString()}:r),w(\"thread.message\",{annotationId:e,message:o}),o.id},updateAnnotation(e,t){let n=!1;return l.value=l.value.map(o=>o.id!==e?o:(n=!0,{...o,...t,updatedAt:new Date().toISOString()})),n&&w(\"annotation.updated\",{id:e,patch:t}),n},acknowledgeAnnotation(e){return this.updateAnnotation(e,{status:\"acknowledged\"})},resolveAnnotation(e,t=\"agent\"){return this.updateAnnotation(e,{status:\"resolved\",resolvedAt:new Date().toISOString(),resolvedBy:t})},dismissAnnotation(e){return this.updateAnnotation(e,{status:\"dismissed\"})},removeAnnotation(e){let t=l.value.length;l.value=l.value.filter(o=>o.id!==e);let n=l.value.length<t;return n&&w(\"annotation.deleted\",{id:e}),n},clearAnnotations(){let e=l.value.length;return l.value=[],b.value=null,w(\"session.updated\",{cleared:e}),e},focusAnnotation(e){let t=l.value.some(n=>n.id===e);return t&&(b.value=e),t},closeThread(){b.value=null},setCursors(e){v.value=e},setCursor(e){let t=v.value.filter(n=>n.id!==e.id);v.value=[...t,e]},removeCursor(e){let t=v.value.length;return v.value=v.value.filter(n=>n.id!==e),v.value.length<t},clearCursors(){v.value=[]},setMode(e){u.value!==e&&(u.value=e,w(\"session.updated\",{mode:e}))},getMode(){return u.value},subscribeMode(e){return u.subscribe(e)},setTheme(e){T.value=e},getAnnotations(){return l.value}};function se(e){e.webhookUrl!==void 0&&(_.value=e.webhookUrl),$.value=e.sessionId??`cf_${O().slice(-12).toLowerCase()}`,w(\"session.created\",{sessionId:$.value,pageUrl:typeof location<\"u\"?location.href:\"\"})}var Fe=[\"display\",\"position\",\"width\",\"height\",\"margin\",\"padding\",\"color\",\"background-color\",\"background\",\"font-family\",\"font-size\",\"font-weight\",\"line-height\",\"border\",\"border-radius\",\"box-shadow\",\"flex-direction\",\"justify-content\",\"align-items\",\"gap\",\"grid-template-columns\",\"z-index\",\"opacity\",\"text-align\"],Ue=[\"role\",\"aria-label\",\"aria-labelledby\",\"aria-describedby\",\"aria-hidden\",\"aria-expanded\",\"aria-checked\",\"aria-selected\",\"alt\",\"title\",\"tabindex\",\"type\",\"name\",\"for\",\"href\"];function N(e){let t=e.getBoundingClientRect(),n=tt(e),o=window.scrollX,r=window.scrollY,s={x:t.left+(n?0:o),y:t.top+(n?0:r),width:t.width,height:t.height};return{element:e.tagName.toLowerCase(),elementPath:Ke(e),fullPath:Ve(e),x:nt((t.left+t.width/2)/window.innerWidth*100),y:n?t.top:t.top+r,url:location.href,boundingBox:s,isFixed:n,cssClasses:We(e),computedStyles:qe(e),accessibility:Ge(e),nearbyText:Xe(e),nearbyElements:Je(e),reactComponents:Qe(e)}}function Ke(e){if(e.id&&le(e.id))return`#${F(e.id)}`;let t=e.getAttribute(\"data-testid\");if(t)return`[data-testid=\"${t}\"]`;let n=e.tagName.toLowerCase(),o=ce(e);return o?`${n}.${F(o)}`:n}function Ve(e){let t=[],n=e;for(;n&&n.nodeType===1&&n.tagName.toLowerCase()!==\"html\";){if(n.id&&le(n.id)){t.unshift(`#${F(n.id)}`);break}let o=n.tagName.toLowerCase(),r=n.parentElement;if(r){let s=Array.from(r.children).filter(a=>a.tagName===n.tagName);s.length>1&&(o+=`:nth-of-type(${s.indexOf(n)+1})`)}t.unshift(o),n=r}return t.join(\" > \")}function U(e){if(!e)return null;try{return document.querySelector(e)}catch{return null}}function le(e){return!(e.length>40||/^[:]?r[a-z0-9]+[:]?$/i.test(e)||/^(radix|headlessui|mui|react-aria)[-:]/i.test(e))}function ce(e){for(let t of Array.from(e.classList))if(!(/^[a-z0-9_-]*[a-f0-9]{6,}$/i.test(t)&&/\\d/.test(t))&&!t.startsWith(\"cf-\"))return t;return e.classList[0]??null}function F(e){return typeof CSS<\"u\"&&typeof CSS.escape==\"function\"?CSS.escape(e):e.replace(/([^\\w-])/g,\"\\\\$1\")}function We(e){let t=Array.from(e.classList).filter(n=>!n.startsWith(\"cf-\"));return t.length?t.join(\" \"):void 0}function qe(e){let t=window.getComputedStyle(e),n=[];for(let o of Fe){let r=t.getPropertyValue(o);r&&r!==\"none\"&&r!==\"normal\"&&r!==\"auto\"&&n.push(`${o}: ${r};`)}return n.length?n.join(`\n`):void 0}function Ge(e){let t=[];for(let o of Ue){let r=e.getAttribute(o);r!==null&&r!==\"\"&&t.push(`${o}=\"${r}\"`)}let n=Ze(e);return n&&t.push(`text=\"${K(n,60)}\"`),t.length?t.join(\" \"):void 0}function Xe(e){let t=(e.textContent??\"\").replace(/\\s+/g,\" \").trim();if(t)return K(t,200)}function Je(e){let t=[];e.parentElement&&t.push(`parent: ${D(e.parentElement)}`);let n=e.previousElementSibling;n&&t.push(`prev: ${D(n)}`);let o=e.nextElementSibling;return o&&t.push(`next: ${D(o)}`),t.length?t.join(\" | \"):void 0}function D(e){let t=e.tagName.toLowerCase(),n=ce(e),o=(e.textContent??\"\").replace(/\\s+/g,\" \").trim().slice(0,30);return`${t}${n?`.${n}`:\"\"}${o?` \"${o}\"`:\"\"}`}function Ze(e){let t=\"\";for(let n of Array.from(e.childNodes))n.nodeType===3&&(t+=n.textContent??\"\");return t.replace(/\\s+/g,\" \").trim()}function Qe(e){let t=Object.keys(e).find(x=>x.startsWith(\"__reactFiber$\")||x.startsWith(\"__reactInternalInstance$\"));if(!t)return;let n=e[t],o=[],r,s=0;for(;n&&s<30;){let x=n.type,k=typeof x==\"function\"?x.displayName??x.name:void 0;if(k&&/^[A-Z]/.test(k)&&!o.includes(k)&&(o.push(k),!r&&n.memoizedProps&&(r=n.memoizedProps),o.length>=3))break;n=n.return,s++}if(!o.length)return;let a=o[0],E=r?et(r):\"\";return E?`${a} (${E})`:a}function et(e){let t=[];for(let[n,o]of Object.entries(e))if(n!==\"children\"&&(typeof o==\"string\"?t.push(`${n}=${JSON.stringify(K(o,40))}`):(typeof o==\"number\"||typeof o==\"boolean\")&&t.push(`${n}=${o}`),t.length>=5))break;return t.join(\", \")}function tt(e){let t=e,n=0;for(;t&&n<20;){if(window.getComputedStyle(t).position===\"fixed\")return!0;t=t.parentElement,n++}return!1}function K(e,t){return e.length>t?`${e.slice(0,t-1)}\\u2026`:e}function nt(e){return Math.max(0,Math.min(100,Math.round(e*10)/10))}var V=null,ue=!1,de=0;function ot(e){let t=Date.now();t-de<120||(de=t,w(\"presence.cursor\",{id:y.value.id??\"human\",label:y.value.displayName??\"You\",kind:y.value.kind,x:e.clientX/window.innerWidth*100,y:e.clientY+window.scrollY}))}function pe(e){V=e}function W(e){return V?e.composedPath().includes(V):!1}function fe(e){return!(e instanceof Element)||e.tagName===\"HTML\"||e.tagName===\"BODY\"?null:e}function rt(e){if(W(e)||ot(e),u.value!==\"feedback\"||f.value){h.value=null;return}if(W(e)){h.value=null;return}if(p.value===\"text\"){h.value=null;return}let t=fe(e.target);if(!t){h.value=null;return}let n=t.getBoundingClientRect();h.value={top:n.top,left:n.left,width:n.width,height:n.height}}function it(e){if(u.value!==\"feedback\"||W(e)||p.value===\"text\"||f.value)return;let t=fe(e.target);if(t){if(e.preventDefault(),e.stopPropagation(),p.value===\"multi\"){lt(t);return}q(N(t))}}function at(){if(u.value!==\"feedback\"||p.value!==\"text\"||f.value)return;let e=window.getSelection(),t=e?.toString().trim();if(!t||!e||e.rangeCount===0)return;let n=e.getRangeAt(0),o=n.commonAncestorContainer.nodeType===1?n.commonAncestorContainer:n.commonAncestorContainer.parentElement;if(!o)return;let r=N(o);q({...r,selectedText:t})}function st(e){if(e.key===\"Escape\"){if(f.value){f.value=null;return}if(m.value.length){m.value=[],h.value=null;return}u.value===\"feedback\"&&(u.value=\"view\",h.value=null)}}function lt(e){let t=m.value;m.value=t.includes(e)?t.filter(n=>n!==e):[...t,e]}function me(){let e=m.value;if(!e.length)return;let t=N(e[0]),n=e.map(r=>{let s=r.getBoundingClientRect();return{x:s.left+window.scrollX,y:s.top+window.scrollY,width:s.width,height:s.height}}),o=e.map(r=>r.tagName.toLowerCase()).join(\", \");q({...t,isMultiSelect:!0,elementBoundingBoxes:n,nearbyElements:`${e.length} elements: ${o}`})}function q(e){m.value=[],h.value=null,f.value=e}function ge(){ue||(ue=!0,document.addEventListener(\"mousemove\",rt,!0),document.addEventListener(\"click\",it,!0),document.addEventListener(\"mouseup\",at,!0),document.addEventListener(\"keydown\",st,!0))}var he=\"annotations-v1-host\",ct=`\n:host {\n all: initial;\n contain: layout style;\n font-family: -apple-system, \"SF Pro Text\", system-ui, sans-serif;\n font-size: 14px;\n line-height: 1.45;\n color: #f4f4f4;\n}\n*, *::before, *::after { box-sizing: border-box; }\nbutton { font: inherit; cursor: pointer; }\n[hidden] { display: none !important; }\n`,I=null;function be(){if(I&&document.contains(I.host))return I;let e=document.getElementById(he);e&&e.remove();let t=document.createElement(\"div\");t.id=he,t.style.cssText=[\"all: initial\",\"position: fixed\",\"inset: 0\",\"pointer-events: none\",\"z-index: 2147483647\"].join(\";\");let n=t.attachShadow({mode:\"closed\"}),o=document.createElement(\"style\");o.textContent=ct,n.appendChild(o);let r=document.createElement(\"div\");return r.id=\"cf-app\",r.style.cssText=\"pointer-events: auto;\",n.appendChild(r),document.documentElement.appendChild(t),I={host:t,shadow:n,appRoot:r},I}function j(e){return`top:${e.top}px;left:${e.left}px;width:${e.width}px;height:${e.height}px;`}function G(e){let t=e.trim(),n=t.indexOf(`\n`);return n>0?t.slice(0,n):t}function ve(e,t){return e.length>t?`${e.slice(0,t-1)}\\u2026`:e}function xe(e){let t=0;for(let n=0;n<e.length;n++)t=(t<<5)-t+e.charCodeAt(n);return t}function ye(e){let t=U(e.fullPath??\"\")??U(e.elementPath??\"\");if(t){let n=t.getBoundingClientRect();return{top:n.top-11,left:n.left-11}}return e.boundingBox?{top:e.boundingBox.y-(e.isFixed?0:window.scrollY)-11,left:e.boundingBox.x-(e.isFixed?0:window.scrollX)-11}:null}var ut=\"http://www.w3.org/2000/svg\";function we(e,t){for(let[n,o]of Object.entries(t))if(o!=null){if(n===\"class\"){e.setAttribute(\"class\",String(o));continue}if(n===\"style\"){e.setAttribute(\"style\",String(o));continue}if(n===\"dataset\"){let r=o;if(e instanceof HTMLElement)for(let[s,a]of Object.entries(r))e.dataset[s]=a;continue}if(n.startsWith(\"on\")&&typeof o==\"function\"){let r=n.slice(2).toLowerCase();e.addEventListener(r,o);continue}if(typeof o==\"boolean\"){o&&e.setAttribute(n,\"\");continue}e.setAttribute(n,String(o))}}function X(e,t){for(let n of t)if(!(n===null||n===!1||n===void 0)){if(Array.isArray(n)){X(e,n);continue}if(n instanceof Node){e.appendChild(n);continue}e.appendChild(document.createTextNode(String(n)))}}function i(e,t,...n){let o=document.createElement(e);return t&&we(o,t),X(o,n),o}function J(e,t,...n){let o=document.createElementNS(ut,e);return t&&we(o,t),X(o,n),o}function dt(e){return e===\"text\"?\"Select text on the page to annotate it.\":e===\"multi\"?\"Click elements to group them, then commit.\":\"Click any element to comment. Esc to exit.\"}function B(e,t,n){return i(\"button\",{class:`cf-seg-btn${t?\" on\":\"\"}`,onClick:n},e)}function ke(){let e=u.value===\"feedback\",t=l.value.length,n=m.value.length;return i(\"div\",{class:\"cf-toolbar\"},i(\"div\",{class:\"cf-toolbar-head\"},i(\"span\",{class:\"cf-logo-dot\"}),i(\"span\",null,\"Annotations\"),i(\"span\",{class:\"cf-count\"},String(t))),i(\"div\",{class:\"cf-seg\"},B(\"View\",u.value===\"view\",()=>{u.value=\"view\",h.value=null,m.value=[]}),B(\"Comment\",e,()=>{u.value=\"feedback\"})),e?i(\"div\",{class:\"cf-seg cf-tools\"},B(\"Element\",p.value===\"element\",()=>{p.value=\"element\",m.value=[]}),B(\"Text\",p.value===\"text\",()=>{p.value=\"text\",m.value=[]}),B(\"Multi\",p.value===\"multi\",()=>{p.value=\"multi\"})):null,e&&p.value===\"multi\"&&n?i(\"button\",{class:\"cf-btn cf-btn-primary cf-commit\",onClick:me},`Comment ${n} element${n===1?\"\":\"s\"}`):null,e?i(\"div\",{class:\"cf-hint\"},dt(p.value)):null)}var L={blocking:\"#ef4444\",important:\"#f59e0b\",suggestion:\"#3ecf8e\"},Te=\"#a78bfa\",Ee=[\"fix\",\"change\",\"question\",\"approve\"],Se=[\"blocking\",\"important\",\"suggestion\"],Ae=\"#8b94a3\",Z=[\"#a78bfa\",\"#3ecf8e\",\"#f59e0b\",\"#38bdf8\",\"#f472b6\"];function Ce(e,t){let n=ye(e);if(!n)return null;let o=e.severity?L[e.severity]:Te,r=e.status===\"resolved\"||e.status===\"dismissed\",s=i(\"button\",{class:`cf-pin${r?\" resolved\":\"\"}${e.author?.kind===\"agent\"?\" agent\":\"\"}`,style:`top:${n.top}px;left:${n.left}px;--cf-pin:${o};`,title:G(e.comment),onClick:()=>{b.value=b.value===e.id?null:e.id}},e.author?.kind===\"agent\"?\"\\u2605\":String(t)),a=null;return s.addEventListener(\"mouseenter\",()=>{a||(a=i(\"div\",{class:\"cf-pin-preview\"},G(e.comment)||e.comment),s.appendChild(a))}),s.addEventListener(\"mouseleave\",()=>{a?.remove(),a=null}),s}function Le(e){let t=e.getBoundingClientRect();return i(\"div\",{class:\"cf-multi-box\",style:j({top:t.top,left:t.left,width:t.width,height:t.height})})}function Me(e){let t=e.x/100*window.innerWidth,n=e.y-window.scrollY,o=e.color??(e.kind===\"agent\"?Z[Math.abs(xe(e.id))%Z.length]:\"#ffffff\"),r=J(\"svg\",{width:\"18\",height:\"18\",viewBox:\"0 0 18 18\",class:\"cf-cursor-arrow\"},J(\"path\",{d:\"M2 2 L2 14 L6 10 L9 16 L11 15 L8 9 L14 9 Z\",fill:o,stroke:\"rgba(0,0,0,0.35)\",\"stroke-width\":\"0.75\"}));return i(\"div\",{class:`cf-cursor cf-cursor-${e.kind}`,style:`top:${n}px;left:${t}px;--cf-cursor:${o};`},r,i(\"span\",{class:\"cf-cursor-label\"},`${e.kind===\"agent\"?\"\\u{1F916} \":\"\"}${e.label}`))}function $e(e){let t=\"change\",n=\"important\",o=i(\"textarea\",{class:\"cf-textarea\",placeholder:\"Describe the change\\u2026 (Markdown supported)\",autofocus:!0,onKeyDown:c=>{(c.metaKey||c.ctrlKey)&&c.key===\"Enter\"&&r()},onInput:()=>g()}),r=()=>{let c=o.value.trim();c&&(A.addAnnotation({...e,comment:c,intent:t,severity:n,kind:\"feedback\",author:y.value}),f.value=null)},s=()=>{f.value=null};function a(c,Q,ee,He){let te=c.map(S=>{let R=ee(S);return i(\"button\",{class:`cf-chip${R?\" on\":\"\"}`,style:R?`--cf-chip:${Q(S)};`:void 0,onClick:()=>{He(S),ne()}},S)}),ze=i(\"div\",{class:\"cf-chipset\"},...te);function ne(){c.forEach((S,R)=>{let H=te[R],oe=ee(S);H.className=`cf-chip${oe?\" on\":\"\"}`,oe?H.setAttribute(\"style\",`--cf-chip:${Q(S)};`):H.removeAttribute(\"style\")})}return{group:ze,refresh:ne}}let E=a(Ee,()=>Ae,c=>t===c,c=>{t=c}),x=a(Se,c=>L[c],c=>n===c,c=>{n=c}),k=e.isMultiSelect?`${e.elementBoundingBoxes?.length??0} elements`:e.selectedText?`\"${ve(e.selectedText,40)}\"`:`<${e.element}>`,M=i(\"button\",{class:\"cf-btn cf-btn-primary\",disabled:!0,onClick:r},\"Comment\");function g(){M.disabled=!o.value.trim()}return i(\"div\",{class:\"cf-popup cf-composer\"},i(\"div\",{class:\"cf-popup-head\"},i(\"span\",{class:\"cf-popup-target\"},k),i(\"button\",{class:\"cf-icon-btn\",onClick:s,title:\"Cancel\"},\"\\u2715\")),o,i(\"div\",{class:\"cf-field\"},i(\"span\",{class:\"cf-field-label\"},\"Intent\"),E.group),i(\"div\",{class:\"cf-field\"},i(\"span\",{class:\"cf-field-label\"},\"Severity\"),x.group),i(\"div\",{class:\"cf-popup-actions\"},i(\"button\",{class:\"cf-btn\",onClick:s},\"Cancel\"),M))}function Pe(e,t,n){return i(\"div\",{class:`cf-msg cf-msg-${e}`},i(\"div\",{class:\"cf-msg-meta\"},i(\"span\",{class:`cf-avatar cf-avatar-${e}`},e===\"agent\"?\"\\u{1F916}\":\"\\u{1F9D1}\"),i(\"span\",{class:\"cf-msg-name\"},t)),i(\"div\",{class:\"cf-msg-body\"},n))}function Ie(e){let t=l.value.find(a=>a.id===e);if(!t)return null;let n=i(\"textarea\",{class:\"cf-textarea cf-textarea-sm\",placeholder:\"Reply\\u2026\",onKeyDown:a=>{(a.metaKey||a.ctrlKey)&&a.key===\"Enter\"&&o()},onInput:()=>s()}),o=()=>{let a=n.value.trim();a&&A.replyToAnnotation(e,{role:y.value.kind,content:a})},r=i(\"button\",{class:\"cf-btn cf-btn-primary\",disabled:!0,onClick:o},\"Reply\");function s(){r.disabled=!n.value.trim()}return i(\"div\",{class:\"cf-popup cf-thread\"},i(\"div\",{class:\"cf-popup-head\"},i(\"span\",{class:\"cf-popup-target\"},`<${t.element}>`),t.severity?i(\"span\",{class:\"cf-tag\",style:`--cf-tag:${L[t.severity]};`},t.severity):null,i(\"button\",{class:\"cf-icon-btn\",onClick:()=>{b.value=null},title:\"Close\"},\"\\u2715\")),i(\"div\",{class:\"cf-thread-body\"},Pe(t.author?.kind??\"human\",t.author?.displayName??\"You\",t.comment),...(t.thread??[]).map(a=>Pe(a.role,a.role===\"agent\"?\"Agent\":\"You\",a.content))),i(\"div\",{class:\"cf-thread-compose\"},n,i(\"div\",{class:\"cf-thread-actions\"},t.status!==\"resolved\"?i(\"button\",{class:\"cf-btn cf-btn-ghost\",onClick:()=>A.resolveAnnotation(e,y.value.kind)},\"Resolve\"):i(\"span\",{class:\"cf-resolved-tag\"},\"\\u2713 resolved\"),r)))}var Be=`\n.cf-overlay {\n position: fixed;\n inset: 0;\n pointer-events: none;\n font-family: -apple-system, \"SF Pro Text\", system-ui, sans-serif;\n font-size: 13px;\n color: #f4f4f5;\n --cf-bg: rgba(18, 18, 22, 0.96);\n --cf-border: rgba(255, 255, 255, 0.1);\n --cf-muted: rgba(255, 255, 255, 0.55);\n --cf-accent: #a78bfa;\n}\n.cf-overlay[data-theme=\"light\"] {\n color: #18181b;\n --cf-bg: rgba(252, 252, 253, 0.97);\n --cf-border: rgba(0, 0, 0, 0.1);\n --cf-muted: rgba(0, 0, 0, 0.5);\n}\n\n/* Hover highlight + multi-select boxes */\n.cf-hover {\n position: fixed;\n pointer-events: none;\n border: 2px solid var(--cf-accent);\n background: rgba(167, 139, 250, 0.1);\n border-radius: 4px;\n box-shadow: 0 0 0 1px rgba(167, 139, 250, 0.4);\n transition: top .06s ease, left .06s ease, width .06s ease, height .06s ease;\n z-index: 1;\n}\n.cf-multi-box {\n position: fixed;\n pointer-events: none;\n border: 2px solid #3ecf8e;\n background: rgba(62, 207, 142, 0.12);\n border-radius: 4px;\n z-index: 1;\n animation: cf-multi-pulse 1.4s ease-in-out infinite;\n}\n@keyframes cf-multi-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(62,207,142,0.0); }\n 50% { box-shadow: 0 0 0 3px rgba(62,207,142,0.25); }\n}\n\n/* Live presence cursors (multi-cursor collaboration) */\n.cf-cursor {\n position: fixed;\n z-index: 6;\n pointer-events: none;\n display: flex;\n align-items: flex-start;\n gap: 4px;\n /* Glide to new positions so multiple actors read as \"live\". */\n transition: top .12s ease, left .12s ease;\n will-change: top, left;\n}\n.cf-cursor-arrow { display: block; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.4)); }\n.cf-cursor-label {\n transform: translateY(2px);\n background: var(--cf-cursor, #a78bfa);\n color: #0b0b0f;\n font: 700 11px -apple-system, system-ui;\n padding: 2px 7px;\n border-radius: 8px;\n white-space: nowrap;\n box-shadow: 0 2px 8px rgba(0,0,0,0.35);\n}\n.cf-cursor-human .cf-cursor-label { color: #18181b; }\n.cf-cursor-agent .cf-cursor-label { color: #0b0b0f; }\n\n/* Pins */\n.cf-pin {\n position: fixed;\n width: 22px; height: 22px;\n border-radius: 50% 50% 50% 2px;\n background: var(--cf-pin, #a78bfa);\n color: #fff;\n border: 2px solid rgba(255,255,255,0.9);\n font: 700 11px -apple-system, system-ui;\n display: flex; align-items: center; justify-content: center;\n cursor: pointer;\n pointer-events: auto;\n box-shadow: 0 2px 8px rgba(0,0,0,0.35);\n z-index: 3;\n transition: transform .12s cubic-bezier(.34,1.56,.64,1);\n padding: 0;\n /* Pop in when a pin first renders so new annotations are obvious. */\n animation: cf-pin-pop .32s cubic-bezier(.34,1.56,.64,1) both;\n}\n.cf-pin:hover { transform: scale(1.2); }\n.cf-pin.resolved { opacity: 0.45; }\n/* Agent-pushed pins pulse a ring so reviewers spot what the agent added. */\n.cf-pin.agent { border-style: dashed; }\n.cf-pin.agent::after {\n content: \"\";\n position: absolute; inset: -4px;\n border-radius: inherit;\n border: 2px solid var(--cf-pin, #a78bfa);\n animation: cf-pin-ring 1.6s ease-out 3;\n pointer-events: none;\n}\n\n/* Hover-to-preview card \\u2014 shown next to a pin on mouseenter. */\n.cf-pin-preview {\n position: absolute;\n top: 26px; left: 0;\n max-width: 240px;\n width: max-content;\n pointer-events: none;\n background: var(--cf-bg);\n border: 1px solid var(--cf-border);\n border-radius: 9px;\n padding: 7px 10px;\n font: 500 12px -apple-system, system-ui;\n line-height: 1.4;\n color: #f4f4f5;\n white-space: normal;\n overflow-wrap: anywhere;\n backdrop-filter: blur(16px) saturate(140%);\n box-shadow: 0 8px 28px rgba(0,0,0,0.5);\n z-index: 7;\n animation: cf-rise .14s cubic-bezier(.16,1,.3,1) both;\n}\n.cf-overlay[data-theme=\"light\"] .cf-pin-preview { color: #18181b; }\n\n@keyframes cf-pin-pop {\n 0% { transform: scale(0); opacity: 0; }\n 60% { transform: scale(1.25); opacity: 1; }\n 100% { transform: scale(1); opacity: 1; }\n}\n@keyframes cf-pin-ring {\n 0% { transform: scale(1); opacity: .7; }\n 100% { transform: scale(2.4); opacity: 0; }\n}\n\n/* Toolbar */\n.cf-toolbar {\n position: fixed;\n left: 16px; bottom: 16px;\n pointer-events: auto;\n background: var(--cf-bg);\n border: 1px solid var(--cf-border);\n border-radius: 14px;\n padding: 10px;\n display: flex; flex-direction: column; gap: 8px;\n backdrop-filter: blur(16px) saturate(140%);\n box-shadow: 0 16px 48px rgba(0,0,0,0.5);\n min-width: 220px;\n z-index: 4;\n}\n.cf-toolbar-head {\n display: flex; align-items: center; gap: 7px;\n font-weight: 700; letter-spacing: 0.02em;\n}\n.cf-logo-dot {\n width: 8px; height: 8px; border-radius: 50%;\n background: var(--cf-accent);\n box-shadow: 0 0 10px var(--cf-accent);\n}\n.cf-count {\n margin-left: auto;\n font: 700 11px -apple-system, system-ui;\n color: var(--cf-muted);\n background: rgba(255,255,255,0.08);\n padding: 1px 7px; border-radius: 8px;\n}\n.cf-overlay[data-theme=\"light\"] .cf-count { background: rgba(0,0,0,0.06); }\n\n.cf-seg {\n display: flex; gap: 2px;\n background: rgba(255,255,255,0.06);\n border-radius: 9px; padding: 2px;\n}\n.cf-overlay[data-theme=\"light\"] .cf-seg { background: rgba(0,0,0,0.05); }\n.cf-seg-btn {\n flex: 1; border: none; background: transparent; color: var(--cf-muted);\n padding: 5px 10px; border-radius: 7px; font: 600 12px -apple-system, system-ui;\n}\n.cf-seg-btn.on {\n background: var(--cf-accent); color: #fff;\n box-shadow: 0 1px 4px rgba(0,0,0,0.3);\n}\n.cf-tools .cf-seg-btn.on { background: rgba(255,255,255,0.16); color: #fff; }\n.cf-overlay[data-theme=\"light\"] .cf-tools .cf-seg-btn.on { background: rgba(0,0,0,0.12); color: #111; }\n.cf-hint { font-size: 11px; color: var(--cf-muted); padding: 0 2px; }\n.cf-commit { width: 100%; }\n\n/* Buttons */\n.cf-btn {\n border: 1px solid var(--cf-border); background: transparent; color: inherit;\n padding: 6px 12px; border-radius: 8px; font: 600 12px -apple-system, system-ui;\n}\n.cf-btn:hover { background: rgba(255,255,255,0.06); }\n.cf-overlay[data-theme=\"light\"] .cf-btn:hover { background: rgba(0,0,0,0.04); }\n.cf-btn-primary {\n background: var(--cf-accent); border-color: var(--cf-accent); color: #fff;\n}\n.cf-btn-primary:hover { background: #9173f0; }\n.cf-btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }\n.cf-btn-ghost { border-color: transparent; color: var(--cf-muted); }\n\n/* Popups (composer + thread) */\n.cf-popup {\n position: fixed;\n left: 16px; bottom: 92px;\n width: 320px;\n pointer-events: auto;\n background: var(--cf-bg);\n border: 1px solid var(--cf-border);\n border-radius: 14px;\n padding: 12px;\n display: flex; flex-direction: column; gap: 10px;\n backdrop-filter: blur(16px) saturate(140%);\n box-shadow: 0 16px 48px rgba(0,0,0,0.55);\n z-index: 5;\n animation: cf-rise .2s cubic-bezier(.16,1,.3,1) both;\n}\n@keyframes cf-rise {\n from { transform: translateY(10px); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n.cf-popup-head {\n display: flex; align-items: center; gap: 8px;\n}\n.cf-popup-target {\n font: 600 12px ui-monospace, \"SF Mono\", monospace;\n color: var(--cf-accent);\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n}\n.cf-icon-btn {\n margin-left: auto; border: none; background: transparent;\n color: var(--cf-muted); font-size: 13px; cursor: pointer;\n width: 22px; height: 22px; border-radius: 6px;\n}\n.cf-icon-btn:hover { background: rgba(255,255,255,0.08); }\n\n.cf-textarea {\n width: 100%; min-height: 72px; resize: vertical;\n background: rgba(255,255,255,0.04);\n border: 1px solid var(--cf-border); border-radius: 9px;\n padding: 8px 10px; color: inherit; font: 400 13px -apple-system, system-ui;\n line-height: 1.45;\n}\n.cf-overlay[data-theme=\"light\"] .cf-textarea { background: rgba(0,0,0,0.03); }\n.cf-textarea:focus { outline: none; border-color: var(--cf-accent); }\n.cf-textarea-sm { min-height: 48px; }\n\n.cf-field { display: flex; flex-direction: column; gap: 5px; }\n.cf-field-label {\n font: 700 10px -apple-system, system-ui; letter-spacing: 0.06em;\n text-transform: uppercase; color: var(--cf-muted);\n}\n.cf-chipset { display: flex; flex-wrap: wrap; gap: 5px; }\n.cf-chip {\n border: 1px solid var(--cf-border); background: transparent; color: var(--cf-muted);\n padding: 4px 10px; border-radius: 20px; font: 600 11px -apple-system, system-ui;\n text-transform: capitalize;\n}\n.cf-chip.on {\n background: var(--cf-chip, var(--cf-accent));\n border-color: var(--cf-chip, var(--cf-accent));\n color: #fff;\n}\n.cf-popup-actions { display: flex; gap: 8px; justify-content: flex-end; }\n\n/* Thread */\n.cf-thread-body {\n display: flex; flex-direction: column; gap: 12px;\n max-height: 280px; overflow-y: auto; padding-right: 2px;\n}\n.cf-msg { display: flex; flex-direction: column; gap: 3px; }\n.cf-msg-meta { display: flex; align-items: center; gap: 6px; }\n.cf-avatar { font-size: 12px; }\n.cf-msg-name {\n font: 700 11px -apple-system, system-ui; color: var(--cf-muted);\n}\n.cf-msg-body {\n font-size: 13px; line-height: 1.5; white-space: pre-wrap; word-break: break-word;\n background: rgba(255,255,255,0.04); border-radius: 9px; padding: 7px 10px;\n}\n.cf-overlay[data-theme=\"light\"] .cf-msg-body { background: rgba(0,0,0,0.03); }\n.cf-msg-agent .cf-msg-body { border-left: 2px solid var(--cf-accent); }\n.cf-thread-compose { display: flex; flex-direction: column; gap: 8px; }\n.cf-thread-actions { display: flex; gap: 8px; align-items: center; }\n.cf-thread-actions .cf-btn-primary { margin-left: auto; }\n.cf-resolved-tag { font: 600 11px -apple-system, system-ui; color: #3ecf8e; }\n.cf-tag {\n font: 700 9px -apple-system, system-ui; text-transform: uppercase;\n letter-spacing: 0.05em; padding: 2px 6px; border-radius: 5px;\n background: var(--cf-tag, var(--cf-accent)); color: #fff;\n}\n\n/* Respect reduced-motion: keep the UI usable, drop the motion. */\n@media (prefers-reduced-motion: reduce) {\n .cf-pin, .cf-popup, .cf-multi-box { animation: none !important; }\n .cf-pin.agent::after { display: none; }\n}\n`;function C(e,t,n){let o=()=>{e.replaceChildren();let r=n();r!==null&&(Array.isArray(r)?e.append(...r):e.append(r))};o();for(let r of t)r.subscribe(o)}function Re(e,t={}){let n=i(\"div\",{class:\"cf-overlay\"}),o=()=>{n.setAttribute(\"data-theme\",T.value===\"auto\"?\"dark\":T.value)};o(),T.subscribe(o);let r=document.createElement(\"style\");r.textContent=Be,n.appendChild(r);let s=i(\"div\",{class:\"cf-layer-hover\"});C(s,[h,f],()=>{let g=h.value;return!g||f.value?null:i(\"div\",{class:\"cf-hover\",style:j(g)})}),n.appendChild(s);let a=i(\"div\",{class:\"cf-layer-multi\"});C(a,[m,P],()=>m.value.map(g=>Le(g))),n.appendChild(a);let E=i(\"div\",{class:\"cf-layer-pins\"});C(E,[l,P],()=>l.value.map((g,c)=>Ce(g,c+1)).filter(g=>g!==null)),n.appendChild(E);let x=i(\"div\",{class:\"cf-layer-cursors\"});if(C(x,[v],()=>v.value.map(g=>Me(g))),n.appendChild(x),!t.headless){let g=i(\"div\",{class:\"cf-layer-toolbar\"});C(g,[u,p,l,m],()=>ke()),n.appendChild(g)}let k=i(\"div\",{class:\"cf-layer-composer\"});C(k,[f],()=>f.value?$e(f.value):null),n.appendChild(k);let M=i(\"div\",{class:\"cf-layer-thread\"});C(M,[b,l],()=>b.value?Ie(b.value):null),n.appendChild(M),e.appendChild(n)}var Oe=!1,_e=!1;function Ne(e={}){se(e),e.author&&(y.value=e.author),e.mode&&(u.value=e.mode),e.theme&&(T.value=e.theme),e.headless&&(_e=!0),je(),ae.value=!0,console.info(\"[annotations v1] ready on\",location.href)}function je(){if(Oe||typeof document>\"u\")return;if(!document.documentElement){document.addEventListener(\"DOMContentLoaded\",je,{once:!0});return}Oe=!0;let{host:e,appRoot:t}=be();pe(e),ge(),Re(t,{headless:_e});let n=()=>{P.value++};window.addEventListener(\"scroll\",n,{passive:!0,capture:!0}),window.addEventListener(\"resize\",n,{passive:!0})}var pt=Object.assign({__init:Ne},A);window.__annotations=pt;Ne();})();\n";
|
package/src/signal.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny vanilla reactive primitive — a drop-in for the `@preact/signals`
|
|
3
|
+
* `signal()` we used previously, with no dependencies.
|
|
4
|
+
*
|
|
5
|
+
* A `Signal<T>` holds a value behind a `.value` getter/setter. Writing a
|
|
6
|
+
* value that differs (per `Object.is`) from the current one notifies all
|
|
7
|
+
* subscribers. `.peek()` reads without implying a subscription, and
|
|
8
|
+
* `.subscribe(fn)` registers a listener and returns an unsubscribe fn.
|
|
9
|
+
*
|
|
10
|
+
* This is intentionally minimal: no computed/effect graph, no batching.
|
|
11
|
+
* The overlay only needs per-signal subscriptions, which is all the
|
|
12
|
+
* store + UI layers consume.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export interface Signal<T> {
|
|
16
|
+
value: T;
|
|
17
|
+
/** Read the current value without subscribing. */
|
|
18
|
+
peek(): T;
|
|
19
|
+
/** Subscribe to changes. Returns an unsubscribe function. */
|
|
20
|
+
subscribe(fn: (value: T) => void): () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class SignalImpl<T> implements Signal<T> {
|
|
24
|
+
private _value: T;
|
|
25
|
+
private readonly _subs = new Set<(value: T) => void>();
|
|
26
|
+
|
|
27
|
+
constructor(initial: T) {
|
|
28
|
+
this._value = initial;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get value(): T {
|
|
32
|
+
return this._value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
set value(next: T) {
|
|
36
|
+
if (Object.is(this._value, next)) return;
|
|
37
|
+
this._value = next;
|
|
38
|
+
// Snapshot so an unsubscribe during notification can't skip listeners.
|
|
39
|
+
for (const fn of Array.from(this._subs)) fn(next);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
peek(): T {
|
|
43
|
+
return this._value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
subscribe(fn: (value: T) => void): () => void {
|
|
47
|
+
this._subs.add(fn);
|
|
48
|
+
return () => {
|
|
49
|
+
this._subs.delete(fn);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function signal<T>(initial: T): Signal<T> {
|
|
55
|
+
return new SignalImpl<T>(initial);
|
|
56
|
+
}
|
package/src/store.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Reactive signals for the v1 library state.
|
|
3
3
|
*
|
|
4
4
|
* Single in-memory source of truth — there's no persistence inside
|
|
5
5
|
* the library; the host's webhook handler is the durable log. On
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* re-hydrate via `addAnnotation` if it wants to.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { signal } from "
|
|
10
|
+
import { signal } from "./signal.js";
|
|
11
11
|
import type { CapturedTarget } from "./capture.js";
|
|
12
12
|
import type { Annotation, Mode, Theme } from "./types.js";
|
|
13
13
|
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composer popup — the comment + intent/severity form shown when a
|
|
3
|
+
* target is captured. Vanilla DOM.
|
|
4
|
+
*
|
|
5
|
+
* Local form state (comment/intent/severity) lives in plain closure
|
|
6
|
+
* variables, NOT in a re-rendering hook. The comment is read from the
|
|
7
|
+
* textarea's `.value` at submit time. Selecting an intent/severity chip
|
|
8
|
+
* toggles the `.on` class on the chips in place — the composer is never
|
|
9
|
+
* rebuilt on a chip click, so the textarea keeps its focus + value.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { api } from "../api.js";
|
|
13
|
+
import type { CapturedTarget } from "../capture.js";
|
|
14
|
+
import { author, draft } from "../store.js";
|
|
15
|
+
import type {
|
|
16
|
+
AnnotationIntent,
|
|
17
|
+
AnnotationKind,
|
|
18
|
+
AnnotationSeverity,
|
|
19
|
+
} from "../types.js";
|
|
20
|
+
import {
|
|
21
|
+
INTENTS,
|
|
22
|
+
SEVERITIES,
|
|
23
|
+
SEVERITY_COLOR,
|
|
24
|
+
SEVERITY_NEUTRAL,
|
|
25
|
+
} from "./constants.js";
|
|
26
|
+
import { truncate } from "./helpers.js";
|
|
27
|
+
import { el } from "./dom.js";
|
|
28
|
+
|
|
29
|
+
export function renderComposer(target: CapturedTarget): HTMLElement {
|
|
30
|
+
// Local form state — closure vars, not hooks. Chip selections update
|
|
31
|
+
// these + toggle classes in place; the comment is read from the DOM.
|
|
32
|
+
let intent: AnnotationIntent = "change";
|
|
33
|
+
let severity: AnnotationSeverity = "important";
|
|
34
|
+
|
|
35
|
+
const textarea = el("textarea", {
|
|
36
|
+
class: "cf-textarea",
|
|
37
|
+
placeholder: "Describe the change… (Markdown supported)",
|
|
38
|
+
autofocus: true,
|
|
39
|
+
onKeyDown: (e: KeyboardEvent) => {
|
|
40
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") submit();
|
|
41
|
+
},
|
|
42
|
+
onInput: () => syncSubmitState(),
|
|
43
|
+
}) as HTMLTextAreaElement;
|
|
44
|
+
|
|
45
|
+
const submit = (): void => {
|
|
46
|
+
const text = textarea.value.trim();
|
|
47
|
+
if (!text) return;
|
|
48
|
+
api.addAnnotation({
|
|
49
|
+
...target,
|
|
50
|
+
comment: text,
|
|
51
|
+
intent,
|
|
52
|
+
severity,
|
|
53
|
+
kind: "feedback" satisfies AnnotationKind,
|
|
54
|
+
author: author.value,
|
|
55
|
+
});
|
|
56
|
+
draft.value = null;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const cancel = (): void => {
|
|
60
|
+
draft.value = null;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Build a chip group whose selection toggles `.on` in place. `onSelect`
|
|
64
|
+
// updates the closure state; we never rebuild the composer.
|
|
65
|
+
function chipGroup(
|
|
66
|
+
labels: readonly string[],
|
|
67
|
+
color: (label: string) => string,
|
|
68
|
+
isOn: (label: string) => boolean,
|
|
69
|
+
onSelect: (label: string) => void,
|
|
70
|
+
): { group: HTMLElement; refresh: () => void } {
|
|
71
|
+
const chips = labels.map((label) => {
|
|
72
|
+
const on = isOn(label);
|
|
73
|
+
return el(
|
|
74
|
+
"button",
|
|
75
|
+
{
|
|
76
|
+
class: `cf-chip${on ? " on" : ""}`,
|
|
77
|
+
style: on ? `--cf-chip:${color(label)};` : undefined,
|
|
78
|
+
onClick: () => {
|
|
79
|
+
onSelect(label);
|
|
80
|
+
refresh();
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
label,
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
const group = el("div", { class: "cf-chipset" }, ...chips);
|
|
87
|
+
function refresh(): void {
|
|
88
|
+
labels.forEach((label, i) => {
|
|
89
|
+
const chip = chips[i]!;
|
|
90
|
+
const on = isOn(label);
|
|
91
|
+
chip.className = `cf-chip${on ? " on" : ""}`;
|
|
92
|
+
if (on) chip.setAttribute("style", `--cf-chip:${color(label)};`);
|
|
93
|
+
else chip.removeAttribute("style");
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return { group, refresh };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const intentGroup = chipGroup(
|
|
100
|
+
INTENTS,
|
|
101
|
+
() => SEVERITY_NEUTRAL,
|
|
102
|
+
(label) => intent === label,
|
|
103
|
+
(label) => {
|
|
104
|
+
intent = label as AnnotationIntent;
|
|
105
|
+
},
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const severityGroup = chipGroup(
|
|
109
|
+
SEVERITIES,
|
|
110
|
+
(label) => SEVERITY_COLOR[label as AnnotationSeverity],
|
|
111
|
+
(label) => severity === label,
|
|
112
|
+
(label) => {
|
|
113
|
+
severity = label as AnnotationSeverity;
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const label = target.isMultiSelect
|
|
118
|
+
? `${target.elementBoundingBoxes?.length ?? 0} elements`
|
|
119
|
+
: target.selectedText
|
|
120
|
+
? `"${truncate(target.selectedText, 40)}"`
|
|
121
|
+
: `<${target.element}>`;
|
|
122
|
+
|
|
123
|
+
const submitBtn = el(
|
|
124
|
+
"button",
|
|
125
|
+
{
|
|
126
|
+
class: "cf-btn cf-btn-primary",
|
|
127
|
+
disabled: true,
|
|
128
|
+
onClick: submit,
|
|
129
|
+
},
|
|
130
|
+
"Comment",
|
|
131
|
+
) as HTMLButtonElement;
|
|
132
|
+
|
|
133
|
+
function syncSubmitState(): void {
|
|
134
|
+
submitBtn.disabled = !textarea.value.trim();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return el(
|
|
138
|
+
"div",
|
|
139
|
+
{ class: "cf-popup cf-composer" },
|
|
140
|
+
el(
|
|
141
|
+
"div",
|
|
142
|
+
{ class: "cf-popup-head" },
|
|
143
|
+
el("span", { class: "cf-popup-target" }, label),
|
|
144
|
+
el("button", { class: "cf-icon-btn", onClick: cancel, title: "Cancel" }, "✕"),
|
|
145
|
+
),
|
|
146
|
+
textarea,
|
|
147
|
+
el(
|
|
148
|
+
"div",
|
|
149
|
+
{ class: "cf-field" },
|
|
150
|
+
el("span", { class: "cf-field-label" }, "Intent"),
|
|
151
|
+
intentGroup.group,
|
|
152
|
+
),
|
|
153
|
+
el(
|
|
154
|
+
"div",
|
|
155
|
+
{ class: "cf-field" },
|
|
156
|
+
el("span", { class: "cf-field-label" }, "Severity"),
|
|
157
|
+
severityGroup.group,
|
|
158
|
+
),
|
|
159
|
+
el(
|
|
160
|
+
"div",
|
|
161
|
+
{ class: "cf-popup-actions" },
|
|
162
|
+
el("button", { class: "cf-btn", onClick: cancel }, "Cancel"),
|
|
163
|
+
submitBtn,
|
|
164
|
+
),
|
|
165
|
+
);
|
|
166
|
+
}
|