review-lens-react 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
- (function(L,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],r):(L=typeof globalThis<"u"?globalThis:L||self,r(L.ReviewLensReact={},L.jsxRuntime,L.React))})(this,(function(L,r,c){"use strict";const ue=["https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email"],Ze="https://www.googleapis.com/auth/gmail.send",Re="https://www.googleapis.com/oauth2/v3/userinfo",et="https://gmail.googleapis.com/gmail/v1/users/me/messages/send";function pe(e){const t=e.feedbackSheetName??"Feedback",n=e.messagesSheetName??"Messages",s=e.usersSheetName??"Users",a=e.enableEmailNotifications?[...ue,Ze].join(" "):ue.join(" ");let d,h;async function w(){return d??(d=ct(e.googleClientId,a)),d}async function f(g,m,p){const S=await w(),E=await fetch(`https://sheets.googleapis.com/v4/spreadsheets/${g}${m}`,{...p,headers:{Authorization:`Bearer ${S}`,"Content-Type":"application/json",...p==null?void 0:p.headers}});if(!E.ok)throw new Error(`Google Sheets request failed with ${E.status}`);return E.json()}async function b(g,m){return(await f(g,`/values/${encodeURIComponent(m)}`)).values??[]}return{async getCurrentUser(){if(!h){const g=await w(),m=await fetch(Re,{headers:{Authorization:`Bearer ${g}`}});if(!m.ok)throw new Error(`Google userinfo request failed with ${m.status}`);h=(await m.json()).email}if(!h)throw new Error("Google account did not return an email address");return{email:h}},async getPermissions(g){const[{email:m},p]=await Promise.all([this.getCurrentUser(),b(e.usersSpreadsheetId,s)]),S=re(p),E=m.toLowerCase(),N=S.find(o=>{var A;return((A=o.email)==null?void 0:A.toLowerCase())===E&&o.active!=="false"&&(!o.projectKey||o.projectKey===g)});return st((N==null?void 0:N.role)??"designer")},async listFeedback(g){return re(await b(e.contentSpreadsheetId,t)).map(we).filter(p=>p!==null).filter(p=>p.projectKey===g.projectKey&&p.contentId===g.contentId&&p.normalizedPath===g.normalizedPath).sort((p,S)=>S.createdAt.localeCompare(p.createdAt))},async createFeedback(g){const m=new Date().toISOString(),p={...g,id:crypto.randomUUID(),attachments:[],createdAt:m,updatedAt:m};return await f(e.contentSpreadsheetId,`/values/${encodeURIComponent(t)}:append?valueInputOption=RAW`,{method:"POST",body:JSON.stringify({values:[ge(p)]})}),p},async updateFeedback(g,m){const p=await b(e.contentSpreadsheetId,t),S=p[0]??fe,E=S.indexOf("id");if(E===-1)throw new Error(`Sheet ${t} is missing an id column`);const N=p.findIndex((C,F)=>F>0&&C[E]===g);if(N<1)throw new Error(`Feedback ${g} was not found`);const o=new Date().toISOString(),A=we(me(S,p[N]));if(!A)throw new Error(`Feedback ${g} could not be parsed before updating`);const v={...A,...m,updatedAt:o},y=ge(v);return await f(e.contentSpreadsheetId,`/values/${encodeURIComponent(t)}!A${N+1}:${dt(fe.length)}${N+1}?valueInputOption=RAW`,{method:"PUT",body:JSON.stringify({values:[y]})}),v},async listMessages(g){return re(await b(e.contentSpreadsheetId,n)).map(rt).filter(p=>p!==null).filter(p=>p.feedbackId===g).sort((p,S)=>p.createdAt.localeCompare(S.createdAt))},async createMessage(g){const m={...g,id:crypto.randomUUID(),createdAt:new Date().toISOString()};return await f(e.contentSpreadsheetId,`/values/${encodeURIComponent(n)}:append?valueInputOption=RAW`,{method:"POST",body:JSON.stringify({values:[nt(m)]})}),m},async sendEmail(g){if(!e.enableEmailNotifications||g.to.length===0)return;const m=await w(),p=await this.getCurrentUser(),S=await fetch(et,{method:"POST",headers:{Authorization:`Bearer ${m}`,"Content-Type":"application/json"},body:JSON.stringify({raw:ut({from:p.email,to:g.to,subject:g.subject,text:g.text})})});if(!S.ok)throw new Error(`Gmail send request failed with ${S.status}`)}}}const fe=["id","projectKey","contentId","normalizedPath","originalUrl","selector","selectorStrategy","elementFingerprintJson","createdCssSnapshotJson","comment","status","severity","category","assigneeEmail","viewportWidth","viewportHeight","viewportPreset","screenshotUrl","screenshotThumbnailUrl","attachmentJson","authorEmail","createdAt","updatedAt","fixedCssSnapshotJson","fixedAt","fixedBy","resolvedAt","resolvedBy"],tt=["id","feedbackId","body","authorEmail","createdAt"];function ge(e){return[e.id,e.projectKey,e.contentId,e.normalizedPath,e.originalUrl,e.selector,e.selectorStrategy,JSON.stringify(e.elementFingerprint),JSON.stringify(e.createdCssSnapshot),e.comment,e.status,e.severity,e.category,e.assigneeEmail??"",String(e.viewportWidth),String(e.viewportHeight),e.viewportPreset,e.screenshotUrl??"",e.screenshotThumbnailUrl??"",JSON.stringify(e.attachments),e.authorEmail,e.createdAt,e.updatedAt,e.fixedCssSnapshot?JSON.stringify(e.fixedCssSnapshot):"",e.fixedAt??"",e.fixedBy??"",e.resolvedAt??"",e.resolvedBy??""]}function nt(e){return tt.map(t=>e[t])}function re(e){const[t,...n]=e;return t?n.map(s=>me(t,s)):[]}function me(e,t){return Object.fromEntries(e.map((n,s)=>[n,t[s]??""]))}function we(e){return e.id?{id:e.id,projectKey:e.projectKey,contentId:e.contentId,normalizedPath:e.normalizedPath,originalUrl:e.originalUrl,selector:e.selector,selectorStrategy:e.selectorStrategy==="stable-attribute"?"stable-attribute":"css-path",elementFingerprint:se(e.elementFingerprintJson,{tagName:"",width:0,height:0}),createdCssSnapshot:be(e.createdCssSnapshotJson),fixedCssSnapshot:e.fixedCssSnapshotJson?be(e.fixedCssSnapshotJson):void 0,comment:e.comment,status:it(e.status),severity:at(e.severity),category:ot(e.category),assigneeEmail:e.assigneeEmail||void 0,viewportWidth:Number(e.viewportWidth)||0,viewportHeight:Number(e.viewportHeight)||0,viewportPreset:lt(e.viewportPreset),screenshotUrl:e.screenshotUrl||void 0,screenshotThumbnailUrl:e.screenshotThumbnailUrl||void 0,attachments:se(e.attachmentJson,[]),authorEmail:e.authorEmail,createdAt:e.createdAt,updatedAt:e.updatedAt,fixedAt:e.fixedAt||void 0,fixedBy:e.fixedBy||void 0,resolvedAt:e.resolvedAt||void 0,resolvedBy:e.resolvedBy||void 0}:null}function rt(e){return!e.id||!e.feedbackId?null:{id:e.id,feedbackId:e.feedbackId,body:e.body,authorEmail:e.authorEmail,createdAt:e.createdAt}}function se(e,t){try{return e?JSON.parse(e):t}catch{return t}}function be(e){const t=se(e,{});return{margin:t.margin??"",marginTop:t.marginTop??"",marginRight:t.marginRight??"",marginBottom:t.marginBottom??"",marginLeft:t.marginLeft??"",padding:t.padding??"",paddingTop:t.paddingTop??"",paddingRight:t.paddingRight??"",paddingBottom:t.paddingBottom??"",paddingLeft:t.paddingLeft??"",border:t.border??"",borderTopWidth:t.borderTopWidth??"",borderRightWidth:t.borderRightWidth??"",borderBottomWidth:t.borderBottomWidth??"",borderLeftWidth:t.borderLeftWidth??"",fontFamily:t.fontFamily??"",fontSize:t.fontSize??"",lineHeight:t.lineHeight??"",color:t.color??"",backgroundColor:t.backgroundColor??"",borderRadius:t.borderRadius??"",width:t.width??0,height:t.height??0}}function st(e){return e==="admin"?["create","read","reply","update","assign"]:e==="developer"?["read","reply","update","assign"]:["create","read","reply"]}function it(e){return e==="in_progress"||e==="needs_clarification"||e==="fixed"||e==="wontfix"||e==="resolved"?e:"open"}function at(e){return e==="low"||e==="high"?e:"medium"}function ot(e){return e==="visual"||e==="copy"||e==="accessibility"||e==="responsive"?e:"bug"}function lt(e){return e==="mobile"||e==="tablet"||e==="desktop"?e:"custom"}function dt(e){let t=e,n="";for(;t>0;){const s=(t-1)%26;n=String.fromCharCode(65+s)+n,t=Math.floor((t-s)/26)}return n}async function ct(e,t){return await ht(),new Promise((n,s)=>{var d;const a=(d=window.google)==null?void 0:d.accounts.oauth2.initTokenClient({client_id:e,scope:t,callback:h=>{if(h.error||!h.access_token){s(new Error(h.error??"Google OAuth did not return an access token"));return}n(h.access_token)}});a==null||a.requestAccessToken({prompt:""})})}function ht(){var e;return(e=window.google)!=null&&e.accounts.oauth2?Promise.resolve():new Promise((t,n)=>{const s=document.querySelector('script[src="https://accounts.google.com/gsi/client"]');if(s){s.addEventListener("load",()=>t(),{once:!0}),s.addEventListener("error",()=>n(new Error("Google Identity failed to load")),{once:!0});return}const a=document.createElement("script");a.src="https://accounts.google.com/gsi/client",a.async=!0,a.defer=!0,a.onload=()=>t(),a.onerror=()=>n(new Error("Google Identity failed to load")),document.head.append(a)})}function ut(e){const t=[`From: ${e.from}`,`To: ${e.to.join(", ")}`,`Subject: ${e.subject}`,"Content-Type: text/plain; charset=UTF-8","",e.text].join(`\r
2
- `);return pt(t)}function pt(e){const t=new TextEncoder().encode(e);let n="";return t.forEach(s=>{n+=String.fromCharCode(s)}),btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function ve(e){return new URL(e,window.location.href).pathname.replace(/\/+$/,"")||"/"}const ye=c.createContext(null);function ft({config:e,children:t}){const n=c.useMemo(()=>e.adapter?e.adapter:pe({googleClientId:ie(e.googleClientId,"googleClientId"),contentSpreadsheetId:ie(e.contentSpreadsheetId,"contentSpreadsheetId"),usersSpreadsheetId:ie(e.usersSpreadsheetId,"usersSpreadsheetId"),feedbackSheetName:e.sheetName??"Feedback",enableEmailNotifications:ke(e)}),[e.adapter,e.contentSpreadsheetId,e.emailNotifications,e.googleClientId,e.sheetName,e.usersSpreadsheetId]),s=e.currentUrl??window.location.href,a=(e.normalizeUrl??ve)(s),[d,h]=c.useState(),[w,f]=c.useState([]),[b,g]=c.useState([]),m=c.useCallback(async()=>{const v=await n.listFeedback({projectKey:e.projectKey,contentId:e.contentId,normalizedPath:a});g(v)},[n,e.contentId,e.projectKey,a]);c.useEffect(()=>{let v=!0;async function y(){const[C,F]=await Promise.all([n.getCurrentUser(),n.getPermissions(e.projectKey)]);v&&(h(C),f(F),await m())}return y(),()=>{v=!1}},[n,e.projectKey,m]);const p=c.useCallback(async v=>{const y=await n.createFeedback(v);return g(C=>[y,...C]),ae(e,n,{actorEmail:(d==null?void 0:d.email)??v.authorEmail,item:y,kind:"created"}),y},[n,e,d==null?void 0:d.email]),S=c.useCallback(async(v,y)=>{const C=b.find(j=>j.id===v),F=await n.updateFeedback(v,y);return g(j=>j.map(q=>q.id===v?F:q)),ae(e,n,{actorEmail:d==null?void 0:d.email,item:F,kind:gt(y),previousItem:C}),F},[n,e,d==null?void 0:d.email,b]),E=c.useCallback(v=>n.listMessages(v),[n]),N=c.useCallback(async v=>{const y=await n.createMessage(v),C=b.find(F=>F.id===v.feedbackId);return C&&ae(e,n,{actorEmail:v.authorEmail,item:C,kind:"reply",replyBody:v.body}),y},[n,e,b]),o=c.useCallback(async(v,y)=>{const C=e.uploadAttachment??n.uploadAttachment;if(!C)throw new Error("Review Lens attachment upload is not configured");return C(v,y)},[n,e]),A=c.useMemo(()=>({config:e,adapter:n,currentUser:d,permissions:w,feedback:b,normalizedPath:a,refreshFeedback:m,createFeedback:p,updateFeedback:S,listMessages:E,createMessage:N,uploadAttachment:o}),[n,e,p,d,b,a,w,m,S,E,N,o]);return r.jsx(ye.Provider,{value:A,children:t})}function Se(){const e=c.useContext(ye);if(!e)throw new Error("useReviewLens must be used inside ReviewLensProvider");return e}function ie(e,t){if(!e)throw new Error(`review-lens-react requires config.${t} when no adapter is provided`);return e}function ke(e){return typeof e.emailNotifications=="object"?e.emailNotifications.enabled!==!1:!!e.emailNotifications}function gt(e){return e.status==="resolved"?"resolved":e.status==="fixed"||e.fixedAt||e.fixedBy?"fixed":e.status?"status":"assigneeEmail"in e?"assigned":"updated"}async function ae(e,t,n){if(!ke(e)||!t.sendEmail)return;const s=mt(n);if(s.length!==0)try{await t.sendEmail({to:s,subject:wt(e,n),text:bt(n)})}catch(a){console.warn("Review Lens email notification failed",a)}}function mt(e){var n;const t=new Set;return t.add(e.item.authorEmail),(n=e.previousItem)!=null&&n.assigneeEmail&&t.add(e.previousItem.assigneeEmail),e.item.assigneeEmail&&t.add(e.item.assigneeEmail),[...t].filter(s=>{var a;return s?s.toLowerCase()!==((a=e.actorEmail)==null?void 0:a.toLowerCase()):!1})}function wt(e,t){return`${(typeof e.emailNotifications=="object"?e.emailNotifications:{}).subjectPrefix??"Review Lens"}: ${Ce(t)}`}function bt(e){const t=["[Review Lens]",Ce(e),vt(e),"",`Review: ${e.item.comment}`,`Status: ${Ee(e.item.status)}`,`Author: ${e.item.authorEmail}`,`Assignee: ${e.item.assigneeEmail??"Unassigned"}`,`Link: ${yt(e.item)}`];return e.replyBody&&t.splice(2,0,`Reply: ${e.replyBody}`,""),t.join(`
3
- `)}function vt(e){return e.actorEmail?`Sent by Review Lens on behalf of ${e.actorEmail}.`:"Sent by Review Lens on behalf of the signed-in Google user."}function Ce(e){return e.kind==="created"?"New review feedback":e.kind==="assigned"?`Review assignment changed to ${e.item.assigneeEmail??"unassigned"}`:e.kind==="status"?`Review status changed to ${Ee(e.item.status)}`:e.kind==="fixed"?"Review marked fixed":e.kind==="resolved"?"Review resolved":e.kind==="reply"?"New review reply":"Review updated"}function yt(e){try{const t=new URL(e.originalUrl);return t.searchParams.set("reviewLensFeedback",e.id),t.toString()}catch{return e.originalUrl}}function Ee(e){return e.replace(/_/g," ")}const St=["data-review-id","data-testid","data-test-id","aria-label","name"];function W(e){const t=e.getBoundingClientRect(),n=kt(e);return{selector:n.selector,selectorStrategy:n.strategy,fingerprint:Et(e,t),cssSnapshot:Nt(e,t),rect:t}}function kt(e){for(const t of St){const n=e.getAttribute(t);if(n)return{selector:`[${t}="${Ne(n)}"]`,strategy:"stable-attribute"}}return e.id?{selector:`#${Ne(e.id)}`,strategy:"stable-attribute"}:{selector:Ct(e),strategy:"css-path"}}function Ct(e){const t=[];let n=e;for(;n&&n.nodeType===Node.ELEMENT_NODE&&n!==document.body;){const s=n.parentElement,a=n.tagName.toLowerCase();if(!s){t.unshift(a);break}const d=n.tagName,h=Array.from(s.children).filter(f=>f.tagName===d),w=h.indexOf(n)+1;t.unshift(h.length>1?`${a}:nth-of-type(${w})`:a),n=s}return t.join(" > ")}function Et(e,t){var n;return{tagName:e.tagName.toLowerCase(),id:e.id||void 0,className:e.getAttribute("class")||void 0,textSnippet:((n=e.textContent)==null?void 0:n.trim().slice(0,80))||void 0,ariaLabel:e.getAttribute("aria-label")||void 0,width:Math.round(t.width),height:Math.round(t.height)}}function Nt(e,t){const n=window.getComputedStyle(e);return{margin:oe(n.marginTop,n.marginRight,n.marginBottom,n.marginLeft),marginTop:n.marginTop,marginRight:n.marginRight,marginBottom:n.marginBottom,marginLeft:n.marginLeft,padding:oe(n.paddingTop,n.paddingRight,n.paddingBottom,n.paddingLeft),paddingTop:n.paddingTop,paddingRight:n.paddingRight,paddingBottom:n.paddingBottom,paddingLeft:n.paddingLeft,border:oe(n.borderTopWidth,n.borderRightWidth,n.borderBottomWidth,n.borderLeftWidth),borderTopWidth:n.borderTopWidth,borderRightWidth:n.borderRightWidth,borderBottomWidth:n.borderBottomWidth,borderLeftWidth:n.borderLeftWidth,fontFamily:n.fontFamily,fontSize:n.fontSize,lineHeight:n.lineHeight,color:n.color,backgroundColor:n.backgroundColor,borderRadius:n.borderRadius,width:Math.round(t.width),height:Math.round(t.height)}}function oe(e,t,n,s){return e===t&&t===n&&n===s?e:`${e} ${t} ${n} ${s}`}function Ne(e){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(e):e.replace(/["\\]/g,"\\$&")}function xe({className:e,title:t="Review Lens logo"}){return r.jsxs("svg",{className:e,role:"img","aria-label":t,viewBox:"0 0 40 40",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[r.jsx("rect",{x:"4",y:"6",width:"28",height:"28",rx:"8",fill:"#171717"}),r.jsx("path",{d:"M13 15.5C14.5 13.4 17.1 12 20 12C23.9 12 27.3 14.5 28.7 18C27.3 21.5 23.9 24 20 24C17.1 24 14.5 22.6 13 20.5",stroke:"#FFFFFF",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round"}),r.jsx("circle",{cx:"20",cy:"18",r:"3.4",fill:"#F97316"}),r.jsx("path",{d:"M28.5 26.5L34.5 32.5",stroke:"#2563EB",strokeWidth:"4",strokeLinecap:"round"}),r.jsx("circle",{cx:"31.8",cy:"29.8",r:"2.1",fill:"#FACC15",stroke:"#171717",strokeWidth:"1.4"})]})}const xt=[{label:"Desktop",value:"desktop"},{label:"Tablet",value:"tablet"},{label:"Mobile",value:"mobile"}],Le=["open","in_progress","needs_clarification","fixed","wontfix","resolved"],Fe=["low","medium","high"],Ae=["bug","visual","copy","accessibility","responsive"],R={open:"Open",in_progress:"In progress",needs_clarification:"Needs clarification",fixed:"Fixed",wontfix:"Won't fix",resolved:"Resolved"},H={low:"Low",medium:"Medium",high:"High"},O={bug:"Bug",visual:"Visual",copy:"Copy",accessibility:"Accessibility",responsive:"Responsive"};function Lt({open:e,onOpenChange:t,placement:n="top-right",showResolved:s=!1,syncSelectionToUrl:a=!1,responsivePresets:d=xt}){var Qe;const{adapter:h,config:w,currentUser:f,feedback:b,normalizedPath:g,permissions:m,createFeedback:p,updateFeedback:S,listMessages:E,createMessage:N,uploadAttachment:o}=Se(),[A,v]=c.useState(),[y,C]=c.useState(),[F,j]=c.useState(""),[q,Vt]=c.useState("medium"),[Be,Yt]=c.useState("visual"),[Pe,_e]=c.useState(""),[je,Xt]=c.useState(((Qe=d[0])==null?void 0:Qe.value)??"desktop"),[k,G]=c.useState(),[T,P]=c.useState("review"),[Qt,Ue]=c.useState(!1),[V,We]=c.useState("all"),[Y,De]=c.useState("all"),[X,ze]=c.useState("all"),[Q,He]=c.useState("all"),[Z,Oe]=c.useState("all"),[Zt,Rt]=c.useState(!1),[en,Ke]=c.useState({}),[le,de]=c.useState(""),te=c.useRef(null),Je=c.useRef(e),ce=c.useRef(a?new URL(window.location.href).searchParams.get("reviewLensFeedback"):null),$=!!f,B=m.includes("create"),qe=m.includes("reply"),Ge=m.includes("update"),tn=m.includes("assign"),U=A??y,nn=!!y,rn=!!(w.captureScreenshot&&(w.uploadAttachment||h.uploadAttachment)),sn=c.useMemo(()=>{const i=b.map(u=>u.assigneeEmail).filter(u=>!!u);return f!=null&&f.email&&i.push(f.email),Array.from(new Set(i)).sort((u,l)=>u.localeCompare(l))},[f==null?void 0:f.email,b]),M=c.useMemo(()=>b.filter(i=>s||i.status!=="resolved").filter(i=>V==="all"||i.status===V).filter(i=>Y==="all"||i.severity===Y).filter(i=>X==="all"||i.category===X).filter(i=>Q==="all"||i.assigneeEmail===Q).filter(i=>Z==="all"||i.viewportPreset===Z),[Q,X,b,Y,s,V,Z]),an=[V,Y,X,Q,Z].filter(i=>i!=="all").length;c.useEffect(()=>{if(e){Je.current=!0;return}if(v(void 0),C(void 0),j(""),de(""),P("review"),a&&Je.current){const i=new URL(window.location.href);i.searchParams.has("reviewLensFeedback")&&(i.searchParams.delete("reviewLensFeedback"),window.history.replaceState({},"",i))}},[e,a]),c.useEffect(()=>{$||(v(void 0),C(void 0))},[$]),c.useEffect(()=>{!y||T!=="review"||window.requestAnimationFrame(()=>{var i,u,l;(u=(i=te.current)==null?void 0:i.scrollIntoView)==null||u.call(i,{block:"nearest"}),(l=te.current)==null||l.focus()})},[y,T]),c.useEffect(()=>{if(!k)return;let i=!0;return E(k.id).then(u=>{i&&Ke(l=>({...l,[k.id]:u}))}),()=>{i=!1}},[E,k]),c.useEffect(()=>{if(!a||!ce.current||b.length===0)return;const i=b.find(u=>u.id===ce.current);i&&(ce.current=null,t==null||t(!0),z(i,{syncUrl:!1}))},[b,a]),c.useEffect(()=>{if(!e||!a||k||b.length===0)return;const i=new URL(window.location.href).searchParams.get("reviewLensFeedback"),u=b.find(l=>l.id===i);u&&z(u,{syncUrl:!1})},[b,e,k,a]),c.useEffect(()=>{if(!e)return;function i(l){var x;if(l.key==="Shift"&&Ue(!0),l.key==="Escape"){l.preventDefault(),t==null||t(!1);return}Kt(l.target)||((l.key==="n"||l.key==="ArrowDown")&&(l.preventDefault(),Ve(1)),(l.key==="p"||l.key==="ArrowUp")&&(l.preventDefault(),Ve(-1)),l.key==="c"&&(l.preventDefault(),P("review"),(x=te.current)==null||x.focus()),l.key==="f"&&k&&Ge&&(l.preventDefault(),Xe(k)))}function u(l){l.key==="Shift"&&Ue(!1)}return window.addEventListener("keydown",i),window.addEventListener("keyup",u),()=>{window.removeEventListener("keydown",i),window.removeEventListener("keyup",u)}});const he=c.useCallback(i=>{const u=i.target instanceof Element?i.target:null;if(u)return u.closest("[data-review-lens-ui]")?null:u;const l=document.elementFromPoint(i.clientX,i.clientY);return!l||l.closest("[data-review-lens-ui]")?null:l},[]);if(c.useEffect(()=>{if(!e||!$)return;function i(l){const x=he(l);v(x?W(x):void 0)}function u(l){const x=he(l);x&&(l.preventDefault(),l.stopPropagation(),C(W(x)),P("review"))}return window.addEventListener("mousemove",i,!0),window.addEventListener("click",u,!0),()=>{window.removeEventListener("mousemove",i,!0),window.removeEventListener("click",u,!0)}},[$,he,e]),!e)return null;function z(i,u={syncUrl:!0}){var x;if(G(i),C(void 0),P("feedback"),a&&u.syncUrl!==!1){const ne=new URL(window.location.href);ne.searchParams.set("reviewLensFeedback",i.id),window.history.replaceState({},"",ne)}const l=D(i.selector);if(!l){v(void 0);return}(x=l.scrollIntoView)==null||x.call(l,{behavior:"smooth",block:"center",inline:"center"}),window.requestAnimationFrame(()=>{v(W(l))})}function Ve(i){if(M.length===0)return;const u=k?M.findIndex(x=>x.id===k.id):-1,l=u<0?i>0?0:M.length-1:(u+i+M.length)%M.length;z(M[l])}async function Ye(){if(!y||!F.trim()||!f||!B)return;let i=await p({projectKey:w.projectKey,contentId:w.contentId,normalizedPath:g,originalUrl:w.currentUrl??window.location.href,selector:y.selector,selectorStrategy:y.selectorStrategy,elementFingerprint:y.fingerprint,createdCssSnapshot:y.cssSnapshot,comment:F.trim(),status:"open",severity:q,category:Be,assigneeEmail:Pe.trim()||void 0,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,viewportPreset:je,screenshotUrl:void 0,screenshotThumbnailUrl:void 0,authorEmail:f.email});if(w.captureScreenshot)try{const u=await w.captureScreenshot(y),l=await o(i.id,{type:"screenshot",data:u,createdBy:f.email});i=await S(i.id,{attachments:[l],screenshotUrl:l.url,screenshotThumbnailUrl:l.thumbnailUrl})}catch{}if(j(""),_e(""),C(void 0),v(void 0),P("feedback"),G(i),a){const u=new URL(window.location.href);u.searchParams.set("reviewLensFeedback",i.id),window.history.replaceState({},"",u)}}async function on(i,u){const l=new Date().toISOString(),x=u==="resolved"?{status:u,resolvedAt:l,resolvedBy:f==null?void 0:f.email}:{status:u},ne=await S(i.id,x);G(ne)}async function Xe(i){const u=D(i.selector);if(!u||!f)return;const l=W(u),x=await S(i.id,{status:"fixed",fixedCssSnapshot:l.cssSnapshot,fixedAt:new Date().toISOString(),fixedBy:f.email});G(x)}async function ln(i){if(!le.trim()||!f||!qe)return;const u=await N({feedbackId:i.id,body:le.trim(),authorEmail:f.email});Ke(l=>({...l,[i.id]:[...l[i.id]??[],u]})),de("")}return r.jsxs("div",{className:"review-lens-root","data-review-lens-ui":!0,children:[$&&U?r.jsx($t,{target:U,locked:!!y}):null,$&&y&&A&&Qt?r.jsx(Bt,{from:y,to:A}):null,$?r.jsxs(r.Fragment,{children:[r.jsx(Pt,{feedback:M,selectedFeedback:k,onSelect:z}),r.jsx(jt,{feedback:M,selectedFeedback:k,onSelect:z})]}):null,r.jsxs("aside",{className:`review-lens-panel review-lens-panel--${n}`,"data-review-lens-ui":!0,children:[r.jsxs("header",{className:"review-lens-panel__header",children:[r.jsxs("div",{className:"review-lens-brand",children:[r.jsx(xe,{className:"review-lens-brand__mark"}),r.jsxs("div",{children:[r.jsx("p",{className:"review-lens-kicker",children:"Review Lens"}),r.jsx("h2",{children:T==="summary"?"Summary":T==="feedback"?"Feedback":y?"Element locked":"Inspecting"})]})]}),r.jsx("button",{type:"button",onClick:()=>t==null?void 0:t(!1),children:"Close"})]}),r.jsxs("div",{className:"review-lens-panel__body",children:[r.jsxs("div",{className:"review-lens-mode-switch",role:"tablist","aria-label":"Review Lens mode",children:[r.jsx("button",{type:"button",role:"tab","aria-selected":T==="review",onClick:()=>P("review"),children:"Review"}),r.jsxs("button",{type:"button",role:"tab","aria-selected":T==="feedback",onClick:()=>P("feedback"),children:["Feedback ",r.jsx("span",{children:M.length})]}),r.jsx("button",{type:"button",role:"tab","aria-selected":T==="summary",onClick:()=>P("summary"),children:"Summary"})]}),T==="review"?r.jsxs("div",{className:"review-lens-review-pane",role:"tabpanel",children:[r.jsxs("div",{className:"review-lens-inspection",children:[$?null:r.jsx("p",{children:"Authenticate with Google to inspect this page."}),$&&U?r.jsxs(r.Fragment,{children:[r.jsx(Ut,{target:U}),r.jsx(Ie,{title:"Accessibility",items:Wt(U)}),r.jsx(Ie,{title:"Design tokens",items:Dt(U.cssSnapshot,w.designTokens)})]}):null,$&&!U?r.jsx("p",{children:"Move over the app to inspect."}):null]}),nn?r.jsx("div",{className:"review-lens-composer-panel",children:r.jsxs("form",{className:"review-lens-feedback-form",onSubmit:i=>{i.preventDefault(),Ye()},children:[r.jsx("label",{htmlFor:"review-lens-comment",children:"New feedback"}),r.jsx("textarea",{ref:te,id:"review-lens-comment",value:F,disabled:!B,onChange:i=>j(i.target.value),onKeyDown:i=>{i.key==="Enter"&&i.metaKey&&(i.preventDefault(),Ye())},placeholder:B?"Describe the UX issue...":"You do not have permission to comment."}),r.jsxs("div",{className:"review-lens-form-grid",children:[r.jsxs("label",{children:["Severity",r.jsx("select",{value:q,onChange:i=>Vt(i.target.value),disabled:!B,children:Fe.map(i=>r.jsx("option",{value:i,children:H[i]},i))})]}),r.jsxs("label",{children:["Type",r.jsx("select",{value:Be,onChange:i=>Yt(i.target.value),disabled:!B,children:Ae.map(i=>r.jsx("option",{value:i,children:O[i]},i))})]}),r.jsxs("label",{children:["Assignee",r.jsx("input",{value:Pe,onChange:i=>_e(i.target.value),disabled:!B,placeholder:"optional@email.com"})]}),r.jsxs("label",{children:["Viewport",r.jsx("select",{value:je,onChange:i=>Xt(i.target.value),disabled:!B,children:d.map(i=>r.jsx("option",{value:i.value,children:i.label},i.value))})]})]}),B?r.jsxs("p",{className:"review-lens-feedback-form__hint",children:["Press ",r.jsx("kbd",{children:"Command"})," + ",r.jsx("kbd",{children:"Enter"})," to submit.",rn?" Screenshot capture runs after save.":""]}):null,r.jsx("div",{className:"review-lens-actions",children:r.jsx("button",{type:"submit",disabled:!F.trim()||!B,children:"Save feedback"})})]})}):null]}):null,T==="feedback"?r.jsxs("div",{className:"review-lens-comments",children:[r.jsx(Ft,{open:Zt,activeCount:an,statusFilter:V,severityFilter:Y,categoryFilter:X,assigneeFilter:Q,viewportFilter:Z,assignees:sn,responsivePresets:d,onStatusChange:We,onSeverityChange:De,onCategoryChange:ze,onAssigneeChange:He,onViewportChange:Oe,onToggle:()=>Rt(i=>!i),onClear:()=>{We("all"),De("all"),ze("all"),He("all"),Oe("all")}}),r.jsxs("div",{className:"review-lens-list-panel",children:[r.jsxs("div",{className:"review-lens-comments__header",children:[r.jsx("h3",{children:"All feedback"}),r.jsx("span",{children:M.length})]}),r.jsxs("div",{className:"review-lens-comments__list",children:[M.length===0?r.jsx("p",{children:"No feedback for this view."}):null,M.map(i=>r.jsx(At,{item:i,selected:(k==null?void 0:k.id)===i.id,onSelect:z},i.id))]})]}),k?r.jsxs("div",{className:"review-lens-selected-panel",children:[r.jsx("div",{className:"review-lens-selected-panel__label",children:"Selected feedback"}),r.jsx(It,{item:k,messages:en[k.id]??[],messageDraft:le,canReply:qe,canUpdate:Ge,canAssign:tn,syncSelectionToUrl:a,onMessageDraftChange:de,onSubmitMessage:()=>void ln(k),onStatusChange:i=>void on(k,i),onAssigneeChange:i=>void S(k.id,{assigneeEmail:i.trim()||void 0}).then(G),onMarkFixed:()=>void Xe(k)},k.id)]}):r.jsxs("div",{className:"review-lens-selected-panel review-lens-selected-panel--empty",children:[r.jsx("div",{className:"review-lens-selected-panel__label",children:"Selected feedback"}),r.jsx("p",{children:"Select a feedback item above to review status, assignment, drift, and replies."})]})]}):null,T==="summary"?r.jsx(Tt,{feedback:b}):null]})]})]})}function Ft({open:e,activeCount:t,statusFilter:n,severityFilter:s,categoryFilter:a,assigneeFilter:d,viewportFilter:h,assignees:w,responsivePresets:f,onStatusChange:b,onSeverityChange:g,onCategoryChange:m,onAssigneeChange:p,onViewportChange:S,onToggle:E,onClear:N}){return r.jsxs("div",{className:"review-lens-filter-shell",children:[r.jsxs("div",{className:"review-lens-filter-bar",children:[r.jsxs("button",{type:"button","aria-expanded":e,onClick:E,children:["Filters",t>0?r.jsx("span",{children:t}):null]}),t>0?r.jsx("button",{type:"button",onClick:N,children:"Clear"}):null]}),e?r.jsxs("div",{className:"review-lens-filters",children:[r.jsxs("label",{children:["Status",r.jsxs("select",{"aria-label":"Filter status",value:n,onChange:o=>b(o.target.value),children:[r.jsx("option",{value:"all",children:"All statuses"}),Le.map(o=>r.jsx("option",{value:o,children:R[o]},o))]})]}),r.jsxs("label",{children:["Priority",r.jsxs("select",{"aria-label":"Filter severity",value:s,onChange:o=>g(o.target.value),children:[r.jsx("option",{value:"all",children:"All priorities"}),Fe.map(o=>r.jsx("option",{value:o,children:H[o]},o))]})]}),r.jsxs("label",{children:["Type",r.jsxs("select",{"aria-label":"Filter type",value:a,onChange:o=>m(o.target.value),children:[r.jsx("option",{value:"all",children:"All types"}),Ae.map(o=>r.jsx("option",{value:o,children:O[o]},o))]})]}),r.jsxs("label",{children:["Assignee",r.jsxs("select",{"aria-label":"Filter assignee",value:d,onChange:o=>p(o.target.value),children:[r.jsx("option",{value:"all",children:"All assignees"}),w.map(o=>r.jsx("option",{value:o,children:o},o))]})]}),r.jsxs("label",{children:["Viewport",r.jsxs("select",{"aria-label":"Filter viewport",value:h,onChange:o=>S(o.target.value),children:[r.jsx("option",{value:"all",children:"All viewports"}),f.map(o=>r.jsx("option",{value:o.value,children:o.label},o.value))]})]})]}):null]})}function At({item:e,selected:t,onSelect:n}){const s=Me(e);return r.jsxs("article",{tabIndex:0,className:["review-lens-comment",`review-lens-comment--${e.severity}`,t?"review-lens-comment--selected":""].filter(Boolean).join(" "),onClick:()=>n(e),onKeyDown:a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),n(e))},children:[r.jsxs("div",{className:"review-lens-comment__header",children:[r.jsx("span",{children:R[e.status]}),r.jsx("strong",{children:H[e.severity]})]}),r.jsxs("div",{className:"review-lens-comment__content",children:[r.jsx("p",{children:e.comment}),r.jsxs("span",{children:[e.authorEmail,e.assigneeEmail?` -> ${e.assigneeEmail}`:""]})]}),r.jsxs("div",{className:"review-lens-tags",children:[r.jsx("span",{children:O[e.category]}),r.jsx("span",{children:e.viewportPreset}),r.jsx("span",{children:s.label})]})]})}function It({item:e,messages:t,messageDraft:n,canReply:s,canUpdate:a,canAssign:d,syncSelectionToUrl:h,onMessageDraftChange:w,onSubmitMessage:f,onStatusChange:b,onAssigneeChange:g,onMarkFixed:m}){const[p,S]=c.useState(!1),E=Me(e);function N(){const o=new URL(window.location.href);o.searchParams.set("reviewLensFeedback",e.id),Mt(o.toString()).then(A=>{A&&(S(!0),setTimeout(()=>S(!1),2e3))})}return r.jsxs("section",{className:"review-lens-detail","aria-label":"Selected feedback detail",children:[r.jsxs("div",{className:"review-lens-detail__header",children:[r.jsxs("h3",{children:[O[e.category]," feedback"]}),r.jsxs("div",{className:"review-lens-detail__header-actions",children:[h?r.jsx("button",{type:"button",className:"review-lens-copy-link",onClick:N,"aria-label":"Copy link to this feedback",children:p?"Copied!":"Copy link"}):null,r.jsx("strong",{children:H[e.severity]})]})]}),r.jsx("blockquote",{children:e.comment}),r.jsxs("dl",{className:"review-lens-detail-meta",children:[r.jsxs("div",{children:[r.jsx("dt",{children:"Target"}),r.jsx("dd",{children:E.label})]}),r.jsxs("div",{children:[r.jsx("dt",{children:"Viewport"}),r.jsx("dd",{children:e.viewportPreset})]}),e.screenshotUrl?r.jsxs("div",{children:[r.jsx("dt",{children:"Evidence"}),r.jsx("dd",{children:r.jsx("a",{href:e.screenshotUrl,target:"_blank",rel:"noreferrer",children:"Screenshot"})})]}):null]}),r.jsxs("div",{className:"review-lens-form-grid",children:[r.jsxs("label",{children:["Status",r.jsx("select",{value:e.status,disabled:!a,onChange:o=>b(o.target.value),children:Le.map(o=>r.jsx("option",{value:o,children:R[o]},o))})]}),r.jsxs("label",{children:["Assignee",r.jsx("input",{defaultValue:e.assigneeEmail??"",disabled:!d,onBlur:o=>g(o.target.value),placeholder:"optional@email.com"})]})]}),r.jsxs("div",{className:"review-lens-status-actions",children:[r.jsx("button",{type:"button",className:"review-lens-button-secondary",disabled:!a,onClick:m,children:"Mark fixed"}),r.jsx("button",{type:"button",className:"review-lens-button-primary",disabled:!a,onClick:()=>b("resolved"),children:"Resolve"})]}),r.jsxs("div",{className:"review-lens-thread",children:[r.jsxs("div",{className:"review-lens-thread__header",children:[r.jsx("h3",{children:"Thread"}),r.jsx("span",{children:t.length})]}),t.length===0?r.jsx("p",{children:"No replies yet."}):null,t.map(o=>r.jsxs("div",{className:"review-lens-thread__message",children:[r.jsx("p",{children:o.body}),r.jsx("span",{children:o.authorEmail})]},o.id)),r.jsx("textarea",{"aria-label":"Reply",value:n,disabled:!s,onChange:o=>w(o.target.value),placeholder:s?"Reply...":"You do not have permission to reply."}),r.jsx("div",{className:"review-lens-actions",children:r.jsx("button",{type:"button",disabled:!n.trim()||!s,onClick:f,children:"Reply"})})]})]})}async function Mt(e){var n;if((n=navigator.clipboard)!=null&&n.writeText)return await navigator.clipboard.writeText(e),!0;const t=document.createElement("textarea");t.value=e,t.setAttribute("readonly",""),t.style.position="fixed",t.style.opacity="0",document.body.append(t),t.select();try{return document.execCommand("copy")}finally{t.remove()}}function Tt({feedback:e}){return r.jsxs("div",{className:"review-lens-summary",role:"tabpanel",children:[r.jsx(K,{title:"Status",values:J(e,t=>R[t.status])}),r.jsx(K,{title:"Severity",values:J(e,t=>H[t.severity])}),r.jsx(K,{title:"Type",values:J(e,t=>O[t.category])}),r.jsx(K,{title:"Assignee",values:J(e,t=>t.assigneeEmail??"Unassigned")}),r.jsx(K,{title:"Viewport",values:J(e,t=>t.viewportPreset)})]})}function K({title:e,values:t}){return r.jsxs("section",{children:[r.jsx("h3",{children:e}),r.jsx("dl",{children:t.map(([n,s])=>r.jsxs("div",{children:[r.jsx("dt",{children:n}),r.jsx("dd",{children:s})]},n))})]})}function $t({target:e,locked:t}){const n=Gt(e),s=Ht(e.fingerprint);return r.jsxs("div",{className:t?"review-lens-highlight review-lens-highlight--locked":"review-lens-highlight",style:{top:n.margin.top,left:n.margin.left,width:n.margin.width,height:n.margin.height},children:[r.jsx("div",{className:"review-lens-highlight__border",style:{top:n.border.top-n.margin.top,left:n.border.left-n.margin.left,width:n.border.width,height:n.border.height}}),r.jsx("div",{className:"review-lens-highlight__padding",style:{top:n.padding.top-n.margin.top,left:n.padding.left-n.margin.left,width:n.padding.width,height:n.padding.height}}),r.jsx("div",{className:"review-lens-highlight__content",style:{top:n.content.top-n.margin.top,left:n.content.left-n.margin.left,width:n.content.width,height:n.content.height}}),r.jsxs("div",{className:"review-lens-highlight__label",children:[r.jsx("strong",{children:s}),r.jsxs("span",{children:[Math.round(e.rect.width)," x ",Math.round(e.rect.height)]})]})]})}function Bt({from:e,to:t}){const n=Ot(e.rect,t.rect);return n.length===0?null:r.jsx(r.Fragment,{children:n.map(s=>r.jsx("div",{className:`review-lens-distance review-lens-distance--${s.axis}`,style:{top:s.top,left:s.left,width:s.width,height:s.height},children:r.jsx("span",{children:s.label})},s.key))})}function Pt({feedback:e,selectedFeedback:t,onSelect:n}){return r.jsx(r.Fragment,{children:e.map(s=>r.jsx(_t,{feedback:s,selected:(t==null?void 0:t.id)===s.id,onSelect:n},s.id))})}function _t({feedback:e,selected:t,onSelect:n}){const s=c.useRef(null);return c.useLayoutEffect(()=>{let a=0;const d=()=>{a=0;const w=s.current,f=D(e.selector),b=f==null?void 0:f.getBoundingClientRect();!w||!b||(w.style.top=`${b.top}px`,w.style.left=`${b.right}px`,w.hidden=b.bottom<0||b.top>window.innerHeight)},h=()=>{a||(a=window.requestAnimationFrame(d))};return d(),window.addEventListener("scroll",h,!0),window.addEventListener("resize",h),()=>{a&&window.cancelAnimationFrame(a),window.removeEventListener("scroll",h,!0),window.removeEventListener("resize",h)}},[e.selector]),r.jsx("button",{ref:s,type:"button",className:t?"review-lens-marker review-lens-marker--selected":"review-lens-marker",onClick:()=>n(e),"aria-label":`Open feedback from ${e.authorEmail}`})}function jt({feedback:e,selectedFeedback:t,onSelect:n}){const s=e.map(a=>{const d=D(a.selector),h=d==null?void 0:d.getBoundingClientRect(),w=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight,window.innerHeight);return!h||w<=0?null:{item:a,top:Math.min(100,Math.max(0,(h.top+window.scrollY)/w*100))}}).filter(a=>a!==null);return s.length===0?null:r.jsx("div",{className:"review-lens-minimap","data-review-lens-ui":!0,"aria-label":"Feedback map",children:s.map(a=>r.jsx("button",{type:"button",className:(t==null?void 0:t.id)===a.item.id?"review-lens-minimap__point review-lens-minimap__point--selected":"review-lens-minimap__point",style:{top:`${a.top}%`},onClick:()=>n(a.item),"aria-label":`Jump to feedback from ${a.item.authorEmail}`},a.item.id))})}function Ut({target:e}){const t=[["Selector",e.selector],["Size",`${e.cssSnapshot.width} x ${e.cssSnapshot.height}`],["Margin",e.cssSnapshot.margin],["Padding",e.cssSnapshot.padding],["Border",e.cssSnapshot.border],["Radius",e.cssSnapshot.borderRadius],["Font",`${e.cssSnapshot.fontSize} / ${e.cssSnapshot.lineHeight}`],["Family",e.cssSnapshot.fontFamily],["Color",e.cssSnapshot.color],["Background",e.cssSnapshot.backgroundColor]];return r.jsx("dl",{className:"review-lens-metrics",children:t.map(([n,s])=>r.jsxs("div",{children:[r.jsx("dt",{children:n}),r.jsx("dd",{children:s})]},n))})}function Ie({title:e,items:t}){return r.jsxs("section",{className:"review-lens-insights",children:[r.jsx("h3",{children:e}),t.length===0?r.jsx("p",{children:"No issues detected."}):null,t.length>0?r.jsx("ul",{children:t.map(n=>r.jsx("li",{children:n},n))}):null]})}function D(e){try{return document.querySelector(e)}catch{return null}}function Me(e){const t=D(e.selector);if(!t)return{label:"Target missing",level:"warning"};const n=W(t);return n.fingerprint.tagName!==e.elementFingerprint.tagName?{label:"Element changed",level:"warning"}:Math.abs(n.fingerprint.width-e.elementFingerprint.width)>2||Math.abs(n.fingerprint.height-e.elementFingerprint.height)>2?{label:"Size changed",level:"warning"}:n.cssSnapshot.fontSize!==e.createdCssSnapshot.fontSize||n.cssSnapshot.color!==e.createdCssSnapshot.color||n.cssSnapshot.padding!==e.createdCssSnapshot.padding?{label:"Style changed",level:"warning"}:{label:"Target unchanged",level:"ok"}}function Wt(e){var f;const t=D(e.selector);if(!t)return["Selected element is no longer available."];const n=[],s=t.tagName.toLowerCase(),a=t.getAttribute("role"),d=["button","a","input","select","textarea"].includes(s)||a==="button"||a==="link",h=t.getAttribute("aria-label")||t.getAttribute("title")||((f=t.textContent)==null?void 0:f.trim());d&&!h&&n.push("Interactive element has no accessible name."),d&&(e.rect.width<44||e.rect.height<44)&&n.push("Tap target is smaller than 44 x 44."),s==="img"&&!t.getAttribute("alt")&&n.push("Image is missing alt text.");const w=/^h[1-6]$/.test(s)?Number(s.slice(1)):0;return w>1&&!document.querySelector(`h${w-1}`)&&n.push("Heading may skip the previous level."),Jt(e.cssSnapshot.color,e.cssSnapshot.backgroundColor)&&n.push("Text contrast may be low."),n}function Dt(e,t={}){const n=[];return _("Padding",e.padding,t.spacing,n,{allowComposite:!0}),_("Margin",e.margin,t.spacing,n,{allowComposite:!0}),_("Font size",e.fontSize,t.fontSize,n),_("Line height",e.lineHeight,t.lineHeight,n),_("Text color",e.color,t.color,n),_("Background",e.backgroundColor,t.color,n),_("Radius",e.borderRadius,t.radius,n,{allowComposite:!0}),n}function _(e,t,n,s,a={}){!n||n.length===0||!t||zt(t,n,a)||s.push(`${e} ${t} is outside configured tokens.`)}function zt(e,t,n={}){if(t.includes(e))return!0;if(!n.allowComposite)return!1;const s=e.trim().split(/\s+/);return s.length>1&&s.every(a=>t.includes(a))}function Ht(e){const t=e.id?`#${e.id}`:"",n=e.className?`.${e.className.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"",s=e.ariaLabel?`[aria-label="${e.ariaLabel}"]`:"";return`${e.tagName}${t}${n}${s}`||e.tagName}function Ot(e,t){const n=[],s=(Math.max(e.left,t.left)+Math.min(e.right,t.right))/2,a=(Math.max(e.top,t.top)+Math.min(e.bottom,t.bottom))/2;if(e.right<=t.left||t.right<=e.left){const d=e.right<=t.left?e.right:t.right,h=e.right<=t.left?t.left:e.left;n.push({key:"horizontal",axis:"horizontal",top:Te(a,0,window.innerHeight),left:d,width:Math.max(h-d,1),height:1,label:`${Math.round(h-d)}px`})}if(e.bottom<=t.top||t.bottom<=e.top){const d=e.bottom<=t.top?e.bottom:t.bottom,h=e.bottom<=t.top?t.top:e.top;n.push({key:"vertical",axis:"vertical",top:d,left:Te(s,0,window.innerWidth),width:1,height:Math.max(h-d,1),label:`${Math.round(h-d)}px`})}return n}function Te(e,t,n){return Math.min(Math.max(e,t),n)}function J(e,t){const n=new Map;for(const s of e){const a=t(s);n.set(a,(n.get(a)??0)+1)}return Array.from(n.entries()).sort((s,a)=>a[1]-s[1]||s[0].localeCompare(a[0]))}function Kt(e){return e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement||e instanceof HTMLElement&&e.isContentEditable}function Jt(e,t){const n=$e(e),s=$e(t);return!n||!s||s.alpha===0?!1:qt(n,s)<4.5}function $e(e){const t=e.match(/rgba?\(([^)]+)\)/);if(!t)return null;const[n,s,a,d="1"]=t[1].split(",").map(h=>h.trim());return{red:Number(n),green:Number(s),blue:Number(a),alpha:Number(d)}}function qt(e,t){const n=Math.max(ee(e),ee(t)),s=Math.min(ee(e),ee(t));return(n+.05)/(s+.05)}function ee(e){const t=[e.red,e.green,e.blue].map(n=>{const s=n/255;return s<=.03928?s/12.92:((s+.055)/1.055)**2.4});return t[0]*.2126+t[1]*.7152+t[2]*.0722}function Gt(e){const t={top:I(e.cssSnapshot.marginTop),right:I(e.cssSnapshot.marginRight),bottom:I(e.cssSnapshot.marginBottom),left:I(e.cssSnapshot.marginLeft)},n={top:I(e.cssSnapshot.borderTopWidth),right:I(e.cssSnapshot.borderRightWidth),bottom:I(e.cssSnapshot.borderBottomWidth),left:I(e.cssSnapshot.borderLeftWidth)},s={top:I(e.cssSnapshot.paddingTop),right:I(e.cssSnapshot.paddingRight),bottom:I(e.cssSnapshot.paddingBottom),left:I(e.cssSnapshot.paddingLeft)},a={top:e.rect.top,left:e.rect.left,width:Math.max(e.rect.width,0),height:Math.max(e.rect.height,0)},d={top:a.top-t.top,left:a.left-t.left,width:a.width+t.left+t.right,height:a.height+t.top+t.bottom},h={top:a.top+n.top,left:a.left+n.left,width:Math.max(a.width-n.left-n.right,0),height:Math.max(a.height-n.top-n.bottom,0)},w={top:h.top+s.top,left:h.left+s.left,width:Math.max(h.width-s.left-s.right,0),height:Math.max(h.height-s.top-s.bottom,0)};return{margin:d,border:a,padding:h,content:w}}function I(e){const t=Number.parseFloat(e);return Number.isFinite(t)?t:0}L.ReviewLensLogo=xe,L.ReviewLensOverlay=Lt,L.ReviewLensProvider=ft,L.buildElementTarget=W,L.createGoogleSheetsAdapter=pe,L.normalizeReviewUrl=ve,L.useReviewLens=Se,Object.defineProperty(L,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(L,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],n):(L=typeof globalThis<"u"?globalThis:L||self,n(L.ReviewLensReact={},L.jsxRuntime,L.React))})(this,(function(L,n,h){"use strict";const ue=["https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email"],et="https://www.googleapis.com/auth/gmail.send",pe="https://www.googleapis.com/oauth2/v3/userinfo",tt="https://gmail.googleapis.com/gmail/v1/users/me/messages/send",rt="review-lens-google-token";function fe(e){const t=e.feedbackSheetName??"Feedback",r=e.messagesSheetName??"Messages",s=e.usersSheetName??"Users",a=e.enableEmailNotifications?[...ue,et].join(" "):ue.join(" "),l=pt(e.googleClientId,a);let u,m;async function g(){const f=ft(l);if(f)return f.accessToken;u??(u=ut(e.googleClientId,a).then(c=>(gt(l,c),c)));const v=await u;return Date.now()>=v.expiresAt?(u=void 0,g()):v.accessToken}async function b(f,v,c){const S=await g(),o=await fetch(`https://sheets.googleapis.com/v4/spreadsheets/${f}${v}`,{...c,headers:{Authorization:`Bearer ${S}`,"Content-Type":"application/json",...c==null?void 0:c.headers}});if(o.status===401){ye(l),u=void 0;const C=await g(),w=await fetch(`https://sheets.googleapis.com/v4/spreadsheets/${f}${v}`,{...c,headers:{Authorization:`Bearer ${C}`,"Content-Type":"application/json",...c==null?void 0:c.headers}});if(!w.ok)throw new Error(`Google Sheets request failed with ${w.status}`);return w.json()}if(!o.ok)throw new Error(`Google Sheets request failed with ${o.status}`);return o.json()}async function A(f,v){return(await b(f,`/values/${encodeURIComponent(v)}`)).values??[]}return{async getCurrentUser(){if(m||(m=await x()),!m)throw new Error("Google account did not return an email address");return{email:m}},async getPermissions(f){const[{email:v},c]=await Promise.all([this.getCurrentUser(),A(e.usersSpreadsheetId,s)]),S=ne(c),o=v.toLowerCase(),C=S.find(w=>{var y;return((y=w.email)==null?void 0:y.toLowerCase())===o&&w.active!=="false"&&(!w.projectKey||w.projectKey===f)});return at((C==null?void 0:C.role)??"designer")},async listFeedback(f){return ne(await A(e.contentSpreadsheetId,t)).map(ve).filter(c=>c!==null).filter(c=>c.projectKey===f.projectKey&&c.contentId===f.contentId&&c.normalizedPath===f.normalizedPath).sort((c,S)=>S.createdAt.localeCompare(c.createdAt))},async createFeedback(f){const v=new Date().toISOString(),c={...f,id:crypto.randomUUID(),attachments:[],createdAt:v,updatedAt:v};return await b(e.contentSpreadsheetId,`/values/${encodeURIComponent(t)}:append?valueInputOption=RAW`,{method:"POST",body:JSON.stringify({values:[we(c)]})}),c},async updateFeedback(f,v){const c=await A(e.contentSpreadsheetId,t),S=c[0]??ge,o=S.indexOf("id");if(o===-1)throw new Error(`Sheet ${t} is missing an id column`);const C=c.findIndex((B,U)=>U>0&&B[o]===f);if(C<1)throw new Error(`Feedback ${f} was not found`);const w=new Date().toISOString(),y=ve(me(S,c[C]));if(!y)throw new Error(`Feedback ${f} could not be parsed before updating`);const E={...y,...v,updatedAt:w},F=we(E);return await b(e.contentSpreadsheetId,`/values/${encodeURIComponent(t)}!A${C+1}:${ht(ge.length)}${C+1}?valueInputOption=RAW`,{method:"PUT",body:JSON.stringify({values:[F]})}),E},async listMessages(f){return ne(await A(e.contentSpreadsheetId,r)).map(it).filter(c=>c!==null).filter(c=>c.feedbackId===f).sort((c,S)=>c.createdAt.localeCompare(S.createdAt))},async createMessage(f){const v={...f,id:crypto.randomUUID(),createdAt:new Date().toISOString()};return await b(e.contentSpreadsheetId,`/values/${encodeURIComponent(r)}:append?valueInputOption=RAW`,{method:"POST",body:JSON.stringify({values:[st(v)]})}),v},async sendEmail(f){if(!e.enableEmailNotifications||f.to.length===0)return;const v=await g(),c=await this.getCurrentUser(),S=await fetch(tt,{method:"POST",headers:{Authorization:`Bearer ${v}`,"Content-Type":"application/json"},body:JSON.stringify({raw:mt({from:c.email,to:f.to,subject:f.subject,text:f.text})})});if(!S.ok)throw new Error(`Gmail send request failed with ${S.status}`)}};async function x(){const f=await fetch(pe,{headers:{Authorization:`Bearer ${await g()}`}});if(f.status===401){ye(l),u=void 0;const c=await fetch(pe,{headers:{Authorization:`Bearer ${await g()}`}});if(!c.ok)throw new Error(`Google userinfo request failed with ${c.status}`);return(await c.json()).email}if(!f.ok)throw new Error(`Google userinfo request failed with ${f.status}`);return(await f.json()).email}}const ge=["id","projectKey","contentId","normalizedPath","originalUrl","selector","selectorStrategy","elementFingerprintJson","createdCssSnapshotJson","comment","status","severity","category","assigneeEmail","viewportWidth","viewportHeight","viewportPreset","screenshotUrl","screenshotThumbnailUrl","attachmentJson","authorEmail","createdAt","updatedAt","fixedCssSnapshotJson","fixedAt","fixedBy","resolvedAt","resolvedBy"],nt=["id","feedbackId","body","authorEmail","createdAt"];function we(e){return[e.id,e.projectKey,e.contentId,e.normalizedPath,e.originalUrl,e.selector,e.selectorStrategy,JSON.stringify(e.elementFingerprint),JSON.stringify(e.createdCssSnapshot),e.comment,e.status,e.severity,e.category,e.assigneeEmail??"",String(e.viewportWidth),String(e.viewportHeight),e.viewportPreset,e.screenshotUrl??"",e.screenshotThumbnailUrl??"",JSON.stringify(e.attachments),e.authorEmail,e.createdAt,e.updatedAt,e.fixedCssSnapshot?JSON.stringify(e.fixedCssSnapshot):"",e.fixedAt??"",e.fixedBy??"",e.resolvedAt??"",e.resolvedBy??""]}function st(e){return nt.map(t=>e[t])}function ne(e){const[t,...r]=e;return t?r.map(s=>me(t,s)):[]}function me(e,t){return Object.fromEntries(e.map((r,s)=>[r,t[s]??""]))}function ve(e){return e.id?{id:e.id,projectKey:e.projectKey,contentId:e.contentId,normalizedPath:e.normalizedPath,originalUrl:e.originalUrl,selector:e.selector,selectorStrategy:e.selectorStrategy==="stable-attribute"?"stable-attribute":"css-path",elementFingerprint:se(e.elementFingerprintJson,{tagName:"",width:0,height:0}),createdCssSnapshot:be(e.createdCssSnapshotJson),fixedCssSnapshot:e.fixedCssSnapshotJson?be(e.fixedCssSnapshotJson):void 0,comment:e.comment,status:ot(e.status),severity:lt(e.severity),category:dt(e.category),assigneeEmail:e.assigneeEmail||void 0,viewportWidth:Number(e.viewportWidth)||0,viewportHeight:Number(e.viewportHeight)||0,viewportPreset:ct(e.viewportPreset),screenshotUrl:e.screenshotUrl||void 0,screenshotThumbnailUrl:e.screenshotThumbnailUrl||void 0,attachments:se(e.attachmentJson,[]),authorEmail:e.authorEmail,createdAt:e.createdAt,updatedAt:e.updatedAt,fixedAt:e.fixedAt||void 0,fixedBy:e.fixedBy||void 0,resolvedAt:e.resolvedAt||void 0,resolvedBy:e.resolvedBy||void 0}:null}function it(e){return!e.id||!e.feedbackId?null:{id:e.id,feedbackId:e.feedbackId,body:e.body,authorEmail:e.authorEmail,createdAt:e.createdAt}}function se(e,t){try{return e?JSON.parse(e):t}catch{return t}}function be(e){const t=se(e,{});return{margin:t.margin??"",marginTop:t.marginTop??"",marginRight:t.marginRight??"",marginBottom:t.marginBottom??"",marginLeft:t.marginLeft??"",padding:t.padding??"",paddingTop:t.paddingTop??"",paddingRight:t.paddingRight??"",paddingBottom:t.paddingBottom??"",paddingLeft:t.paddingLeft??"",border:t.border??"",borderTopWidth:t.borderTopWidth??"",borderRightWidth:t.borderRightWidth??"",borderBottomWidth:t.borderBottomWidth??"",borderLeftWidth:t.borderLeftWidth??"",fontFamily:t.fontFamily??"",fontSize:t.fontSize??"",lineHeight:t.lineHeight??"",color:t.color??"",backgroundColor:t.backgroundColor??"",borderRadius:t.borderRadius??"",width:t.width??0,height:t.height??0}}function at(e){return e==="admin"?["create","read","reply","update","assign"]:e==="developer"?["read","reply","update","assign"]:["create","read","reply"]}function ot(e){return e==="in_progress"||e==="needs_clarification"||e==="fixed"||e==="wontfix"||e==="resolved"?e:"open"}function lt(e){return e==="low"||e==="high"?e:"medium"}function dt(e){return e==="visual"||e==="copy"||e==="accessibility"||e==="responsive"?e:"bug"}function ct(e){return e==="mobile"||e==="tablet"||e==="desktop"?e:"custom"}function ht(e){let t=e,r="";for(;t>0;){const s=(t-1)%26;r=String.fromCharCode(65+s)+r,t=Math.floor((t-s)/26)}return r}async function ut(e,t){return await wt(),new Promise((r,s)=>{var l;const a=(l=window.google)==null?void 0:l.accounts.oauth2.initTokenClient({client_id:e,scope:t,callback:u=>{if(u.error||!u.access_token){s(new Error(u.error??"Google OAuth did not return an access token"));return}const m=u.expires_in??3600;r({accessToken:u.access_token,expiresAt:Date.now()+m*1e3})}});a==null||a.requestAccessToken({prompt:""})})}function pt(e,t){return`${rt}:${e}:${t}`}function ft(e){try{const t=window.localStorage.getItem(e);if(!t)return;const r=JSON.parse(t);if(typeof r.accessToken!="string"||typeof r.expiresAt!="number"||Date.now()>=r.expiresAt-6e4){window.localStorage.removeItem(e);return}return r}catch{return}}function gt(e,t){try{window.localStorage.setItem(e,JSON.stringify(t))}catch{}}function ye(e){try{window.localStorage.removeItem(e)}catch{}}function wt(){var e;return(e=window.google)!=null&&e.accounts.oauth2?Promise.resolve():new Promise((t,r)=>{const s=document.querySelector('script[src="https://accounts.google.com/gsi/client"]');if(s){s.addEventListener("load",()=>t(),{once:!0}),s.addEventListener("error",()=>r(new Error("Google Identity failed to load")),{once:!0});return}const a=document.createElement("script");a.src="https://accounts.google.com/gsi/client",a.async=!0,a.defer=!0,a.onload=()=>t(),a.onerror=()=>r(new Error("Google Identity failed to load")),document.head.append(a)})}function mt(e){const t=[`From: ${e.from}`,`To: ${e.to.join(", ")}`,`Subject: ${e.subject}`,"Content-Type: text/plain; charset=UTF-8","",e.text].join(`\r
2
+ `);return vt(t)}function vt(e){const t=new TextEncoder().encode(e);let r="";return t.forEach(s=>{r+=String.fromCharCode(s)}),btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function Se(e){return new URL(e,window.location.href).pathname.replace(/\/+$/,"")||"/"}const ke=h.createContext(null);function bt({config:e,children:t}){const r=h.useMemo(()=>e.adapter?e.adapter:fe({googleClientId:ie(e.googleClientId,"googleClientId"),contentSpreadsheetId:ie(e.contentSpreadsheetId,"contentSpreadsheetId"),usersSpreadsheetId:ie(e.usersSpreadsheetId,"usersSpreadsheetId"),feedbackSheetName:e.sheetName??"Feedback",enableEmailNotifications:Ce(e)}),[e.adapter,e.contentSpreadsheetId,e.emailNotifications,e.googleClientId,e.sheetName,e.usersSpreadsheetId]),s=e.currentUrl??window.location.href,a=(e.normalizeUrl??Se)(s),[l,u]=h.useState(),[m,g]=h.useState([]),[b,A]=h.useState([]),x=h.useCallback(async()=>{const w=await r.listFeedback({projectKey:e.projectKey,contentId:e.contentId,normalizedPath:a});A(w)},[r,e.contentId,e.projectKey,a]);h.useEffect(()=>{let w=!0;async function y(){const[E,F]=await Promise.all([r.getCurrentUser(),r.getPermissions(e.projectKey)]);w&&(u(E),g(F),await x())}return y(),()=>{w=!1}},[r,e.projectKey,x]);const f=h.useCallback(async w=>{const y=await r.createFeedback(w);return A(E=>[y,...E]),ae(e,r,{actorEmail:(l==null?void 0:l.email)??w.authorEmail,item:y,kind:"created"}),y},[r,e,l==null?void 0:l.email]),v=h.useCallback(async(w,y)=>{const E=b.find(B=>B.id===w),F=await r.updateFeedback(w,y);return A(B=>B.map(U=>U.id===w?F:U)),ae(e,r,{actorEmail:l==null?void 0:l.email,item:F,kind:yt(y),previousItem:E}),F},[r,e,l==null?void 0:l.email,b]),c=h.useCallback(w=>r.listMessages(w),[r]),S=h.useCallback(async w=>{const y=await r.createMessage(w),E=b.find(F=>F.id===w.feedbackId);return E&&ae(e,r,{actorEmail:w.authorEmail,item:E,kind:"reply",replyBody:w.body}),y},[r,e,b]),o=h.useCallback(async(w,y)=>{const E=e.uploadAttachment??r.uploadAttachment;if(!E)throw new Error("Review Lens attachment upload is not configured");return E(w,y)},[r,e]),C=h.useMemo(()=>({config:e,adapter:r,currentUser:l,permissions:m,feedback:b,normalizedPath:a,refreshFeedback:x,createFeedback:f,updateFeedback:v,listMessages:c,createMessage:S,uploadAttachment:o}),[r,e,f,l,b,a,m,x,v,c,S,o]);return n.jsx(ke.Provider,{value:C,children:t})}function Ee(){const e=h.useContext(ke);if(!e)throw new Error("useReviewLens must be used inside ReviewLensProvider");return e}function ie(e,t){if(!e)throw new Error(`review-lens-react requires config.${t} when no adapter is provided`);return e}function Ce(e){return typeof e.emailNotifications=="object"?e.emailNotifications.enabled!==!1:!!e.emailNotifications}function yt(e){return e.status==="resolved"?"resolved":e.status==="fixed"||e.fixedAt||e.fixedBy?"fixed":e.status?"status":"assigneeEmail"in e?"assigned":"updated"}async function ae(e,t,r){if(!Ce(e)||!t.sendEmail)return;const s=St(r);if(s.length!==0)try{await t.sendEmail({to:s,subject:kt(e,r),text:Et(r)})}catch(a){console.warn("Review Lens email notification failed",a)}}function St(e){var r;const t=new Set;return t.add(e.item.authorEmail),(r=e.previousItem)!=null&&r.assigneeEmail&&t.add(e.previousItem.assigneeEmail),e.item.assigneeEmail&&t.add(e.item.assigneeEmail),[...t].filter(s=>{var a;return s?s.toLowerCase()!==((a=e.actorEmail)==null?void 0:a.toLowerCase()):!1})}function kt(e,t){return`${(typeof e.emailNotifications=="object"?e.emailNotifications:{}).subjectPrefix??"Review Lens"}: ${Ne(t)}`}function Et(e){const t=["[Review Lens]",Ne(e),Ct(e),"",`Review: ${e.item.comment}`,`Status: ${xe(e.item.status)}`,`Author: ${e.item.authorEmail}`,`Assignee: ${e.item.assigneeEmail??"Unassigned"}`,`Link: ${Nt(e.item)}`];return e.replyBody&&t.splice(2,0,`Reply: ${e.replyBody}`,""),t.join(`
3
+ `)}function Ct(e){return e.actorEmail?`Sent by Review Lens on behalf of ${e.actorEmail}.`:"Sent by Review Lens on behalf of the signed-in Google user."}function Ne(e){return e.kind==="created"?"New review feedback":e.kind==="assigned"?`Review assignment changed to ${e.item.assigneeEmail??"unassigned"}`:e.kind==="status"?`Review status changed to ${xe(e.item.status)}`:e.kind==="fixed"?"Review marked fixed":e.kind==="resolved"?"Review resolved":e.kind==="reply"?"New review reply":"Review updated"}function Nt(e){try{const t=new URL(e.originalUrl);return t.searchParams.set("reviewLensFeedback",e.id),t.toString()}catch{return e.originalUrl}}function xe(e){return e.replace(/_/g," ")}const xt=["data-review-id","data-testid","data-test-id","aria-label","name"];function W(e){const t=e.getBoundingClientRect(),r=Lt(e);return{selector:r.selector,selectorStrategy:r.strategy,fingerprint:Ft(e,t),cssSnapshot:It(e,t),rect:t}}function Lt(e){for(const t of xt){const r=e.getAttribute(t);if(r)return{selector:`[${t}="${Le(r)}"]`,strategy:"stable-attribute"}}return e.id?{selector:`#${Le(e.id)}`,strategy:"stable-attribute"}:{selector:At(e),strategy:"css-path"}}function At(e){const t=[];let r=e;for(;r&&r.nodeType===Node.ELEMENT_NODE&&r!==document.body;){const s=r.parentElement,a=r.tagName.toLowerCase();if(!s){t.unshift(a);break}const l=r.tagName,u=Array.from(s.children).filter(g=>g.tagName===l),m=u.indexOf(r)+1;t.unshift(u.length>1?`${a}:nth-of-type(${m})`:a),r=s}return t.join(" > ")}function Ft(e,t){var r;return{tagName:e.tagName.toLowerCase(),id:e.id||void 0,className:e.getAttribute("class")||void 0,textSnippet:((r=e.textContent)==null?void 0:r.trim().slice(0,80))||void 0,ariaLabel:e.getAttribute("aria-label")||void 0,width:Math.round(t.width),height:Math.round(t.height)}}function It(e,t){const r=window.getComputedStyle(e);return{margin:oe(r.marginTop,r.marginRight,r.marginBottom,r.marginLeft),marginTop:r.marginTop,marginRight:r.marginRight,marginBottom:r.marginBottom,marginLeft:r.marginLeft,padding:oe(r.paddingTop,r.paddingRight,r.paddingBottom,r.paddingLeft),paddingTop:r.paddingTop,paddingRight:r.paddingRight,paddingBottom:r.paddingBottom,paddingLeft:r.paddingLeft,border:oe(r.borderTopWidth,r.borderRightWidth,r.borderBottomWidth,r.borderLeftWidth),borderTopWidth:r.borderTopWidth,borderRightWidth:r.borderRightWidth,borderBottomWidth:r.borderBottomWidth,borderLeftWidth:r.borderLeftWidth,fontFamily:r.fontFamily,fontSize:r.fontSize,lineHeight:r.lineHeight,color:r.color,backgroundColor:r.backgroundColor,borderRadius:r.borderRadius,width:Math.round(t.width),height:Math.round(t.height)}}function oe(e,t,r,s){return e===t&&t===r&&r===s?e:`${e} ${t} ${r} ${s}`}function Le(e){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(e):e.replace(/["\\]/g,"\\$&")}function Ae({className:e,title:t="Review Lens logo"}){return n.jsxs("svg",{className:e,role:"img","aria-label":t,viewBox:"0 0 40 40",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[n.jsx("rect",{x:"5",y:"5",width:"30",height:"30",rx:"9",fill:"#111827"}),n.jsx("path",{d:"M11.5 20C14.2 15.7 17.4 13.6 20 13.6C22.6 13.6 25.8 15.7 28.5 20C25.8 24.3 22.6 26.4 20 26.4C17.4 26.4 14.2 24.3 11.5 20Z",stroke:"#F8FAFC",strokeWidth:"2.4",strokeLinecap:"round",strokeLinejoin:"round"}),n.jsx("path",{d:"M24.7 24.7L31.5 31.5",stroke:"#22D3EE",strokeWidth:"3.6",strokeLinecap:"round"}),n.jsx("circle",{cx:"20",cy:"20",r:"4.6",fill:"#F8FAFC"}),n.jsx("circle",{cx:"20",cy:"20",r:"2.2",fill:"#2563EB"}),n.jsx("path",{d:"M14.2 11.6L17 11.6M11.6 14.2L11.6 17M28.4 14.2L28.4 17",stroke:"#A7F3D0",strokeWidth:"2",strokeLinecap:"round"})]})}const Tt=[{label:"Desktop",value:"desktop"},{label:"Tablet",value:"tablet"},{label:"Mobile",value:"mobile"}],Fe=["open","in_progress","needs_clarification","fixed","wontfix","resolved"],Ie=["low","medium","high"],Te=["bug","visual","copy","accessibility","responsive"],R={open:"Open",in_progress:"In progress",needs_clarification:"Needs clarification",fixed:"Fixed",wontfix:"Won't fix",resolved:"Resolved"},O={low:"Low",medium:"Medium",high:"High"},K={bug:"Bug",visual:"Visual",copy:"Copy",accessibility:"Accessibility",responsive:"Responsive"};function Mt({open:e,onOpenChange:t,placement:r="top-right",showResolved:s=!1,syncSelectionToUrl:a=!1,responsivePresets:l=Tt}){var Re;const{adapter:u,config:m,currentUser:g,feedback:b,normalizedPath:A,permissions:x,createFeedback:f,updateFeedback:v,listMessages:c,createMessage:S,uploadAttachment:o}=Ee(),[C,w]=h.useState(),[y,E]=h.useState(),[F,B]=h.useState(""),[U,Rt]=h.useState("medium"),[_e,er]=h.useState("visual"),[je,Ue]=h.useState(""),[De,tr]=h.useState(((Re=l[0])==null?void 0:Re.value)??"desktop"),[k,q]=h.useState(),[M,_]=h.useState("review"),[rr,We]=h.useState(!1),[V,ze]=h.useState("all"),[Y,He]=h.useState("all"),[X,Oe]=h.useState("all"),[Q,Ke]=h.useState("all"),[Z,Je]=h.useState("all"),[nr,sr]=h.useState(!1),[ir,Ge]=h.useState({}),[le,de]=h.useState(""),te=h.useRef(null),qe=h.useRef(e),ce=h.useRef(a?new URL(window.location.href).searchParams.get("reviewLensFeedback"):null),$=!!g,P=x.includes("create"),Ve=x.includes("reply"),Ye=x.includes("update"),ar=x.includes("assign"),D=C??y,or=!!y,lr=!!(m.captureScreenshot&&(m.uploadAttachment||u.uploadAttachment)),dr=h.useMemo(()=>{const i=b.map(p=>p.assigneeEmail).filter(p=>!!p);return g!=null&&g.email&&i.push(g.email),Array.from(new Set(i)).sort((p,d)=>p.localeCompare(d))},[g==null?void 0:g.email,b]),T=h.useMemo(()=>b.filter(i=>s||i.status!=="resolved").filter(i=>V==="all"||i.status===V).filter(i=>Y==="all"||i.severity===Y).filter(i=>X==="all"||i.category===X).filter(i=>Q==="all"||i.assigneeEmail===Q).filter(i=>Z==="all"||i.viewportPreset===Z),[Q,X,b,Y,s,V,Z]),cr=[V,Y,X,Q,Z].filter(i=>i!=="all").length;h.useEffect(()=>{if(e){qe.current=!0;return}if(w(void 0),E(void 0),B(""),de(""),_("review"),a&&qe.current){const i=new URL(window.location.href);i.searchParams.has("reviewLensFeedback")&&(i.searchParams.delete("reviewLensFeedback"),window.history.replaceState({},"",i))}},[e,a]),h.useEffect(()=>{$||(w(void 0),E(void 0))},[$]),h.useEffect(()=>{!y||M!=="review"||window.requestAnimationFrame(()=>{var i,p,d;(p=(i=te.current)==null?void 0:i.scrollIntoView)==null||p.call(i,{block:"nearest"}),(d=te.current)==null||d.focus()})},[y,M]),h.useEffect(()=>{if(!k)return;let i=!0;return c(k.id).then(p=>{i&&Ge(d=>({...d,[k.id]:p}))}),()=>{i=!1}},[c,k]),h.useEffect(()=>{if(!a||!ce.current||b.length===0)return;const i=b.find(p=>p.id===ce.current);i&&(ce.current=null,t==null||t(!0),H(i,{syncUrl:!1}))},[b,a]),h.useEffect(()=>{if(!e||!a||k||b.length===0)return;const i=new URL(window.location.href).searchParams.get("reviewLensFeedback"),p=b.find(d=>d.id===i);p&&H(p,{syncUrl:!1})},[b,e,k,a]),h.useEffect(()=>{if(!e)return;function i(d){var N;if(d.key==="Shift"&&We(!0),d.key==="Escape"){d.preventDefault(),t==null||t(!1);return}Yt(d.target)||((d.key==="n"||d.key==="ArrowDown")&&(d.preventDefault(),Xe(1)),(d.key==="p"||d.key==="ArrowUp")&&(d.preventDefault(),Xe(-1)),d.key==="c"&&(d.preventDefault(),_("review"),(N=te.current)==null||N.focus()),d.key==="f"&&k&&Ye&&(d.preventDefault(),Ze(k)))}function p(d){d.key==="Shift"&&We(!1)}return window.addEventListener("keydown",i),window.addEventListener("keyup",p),()=>{window.removeEventListener("keydown",i),window.removeEventListener("keyup",p)}});const he=h.useCallback(i=>{const p=i.target instanceof Element?i.target:null;if(p)return p.closest("[data-review-lens-ui]")?null:p;const d=document.elementFromPoint(i.clientX,i.clientY);return!d||d.closest("[data-review-lens-ui]")?null:d},[]);if(h.useEffect(()=>{if(!e||!$)return;function i(d){const N=he(d);w(N?W(N):void 0)}function p(d){const N=he(d);N&&(d.preventDefault(),d.stopPropagation(),E(W(N)),_("review"))}return window.addEventListener("mousemove",i,!0),window.addEventListener("click",p,!0),()=>{window.removeEventListener("mousemove",i,!0),window.removeEventListener("click",p,!0)}},[$,he,e]),!e)return null;function H(i,p={syncUrl:!0}){var N;if(q(i),E(void 0),_("feedback"),a&&p.syncUrl!==!1){const re=new URL(window.location.href);re.searchParams.set("reviewLensFeedback",i.id),window.history.replaceState({},"",re)}const d=z(i.selector);if(!d){w(void 0);return}(N=d.scrollIntoView)==null||N.call(d,{behavior:"smooth",block:"center",inline:"center"}),window.requestAnimationFrame(()=>{w(W(d))})}function Xe(i){if(T.length===0)return;const p=k?T.findIndex(N=>N.id===k.id):-1,d=p<0?i>0?0:T.length-1:(p+i+T.length)%T.length;H(T[d])}async function Qe(){if(!y||!F.trim()||!g||!P)return;let i=await f({projectKey:m.projectKey,contentId:m.contentId,normalizedPath:A,originalUrl:m.currentUrl??window.location.href,selector:y.selector,selectorStrategy:y.selectorStrategy,elementFingerprint:y.fingerprint,createdCssSnapshot:y.cssSnapshot,comment:F.trim(),status:"open",severity:U,category:_e,assigneeEmail:je.trim()||void 0,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,viewportPreset:De,screenshotUrl:void 0,screenshotThumbnailUrl:void 0,authorEmail:g.email});if(m.captureScreenshot)try{const p=await m.captureScreenshot(y),d=await o(i.id,{type:"screenshot",data:p,createdBy:g.email});i=await v(i.id,{attachments:[d],screenshotUrl:d.url,screenshotThumbnailUrl:d.thumbnailUrl})}catch{}if(B(""),Ue(""),E(void 0),w(void 0),_("feedback"),q(i),a){const p=new URL(window.location.href);p.searchParams.set("reviewLensFeedback",i.id),window.history.replaceState({},"",p)}}async function hr(i,p){const d=new Date().toISOString(),N=p==="resolved"?{status:p,resolvedAt:d,resolvedBy:g==null?void 0:g.email}:{status:p},re=await v(i.id,N);q(re)}async function Ze(i){const p=z(i.selector);if(!p||!g)return;const d=W(p),N=await v(i.id,{status:"fixed",fixedCssSnapshot:d.cssSnapshot,fixedAt:new Date().toISOString(),fixedBy:g.email});q(N)}async function ur(i){if(!le.trim()||!g||!Ve)return;const p=await S({feedbackId:i.id,body:le.trim(),authorEmail:g.email});Ge(d=>({...d,[i.id]:[...d[i.id]??[],p]})),de("")}return n.jsxs("div",{className:"review-lens-root","data-review-lens-ui":!0,children:[$&&D?n.jsx(Ut,{target:D,locked:!!y}):null,$&&y&&C&&rr?n.jsx(Dt,{from:y,to:C}):null,$?n.jsxs(n.Fragment,{children:[n.jsx(Wt,{feedback:T,selectedFeedback:k,onSelect:H}),n.jsx(Ht,{feedback:T,selectedFeedback:k,onSelect:H})]}):null,n.jsxs("aside",{className:`review-lens-panel review-lens-panel--${r}`,"data-review-lens-ui":!0,children:[n.jsxs("header",{className:"review-lens-panel__header",children:[n.jsxs("div",{className:"review-lens-brand",children:[n.jsx(Ae,{className:"review-lens-brand__mark"}),n.jsxs("div",{children:[n.jsx("p",{className:"review-lens-kicker",children:"Review Lens"}),n.jsx("h2",{children:M==="summary"?"Summary":M==="feedback"?"Feedback":y?"Element locked":"Inspecting"})]})]}),n.jsx("button",{type:"button",onClick:()=>t==null?void 0:t(!1),children:"Close"})]}),n.jsxs("div",{className:"review-lens-panel__body",children:[n.jsxs("div",{className:"review-lens-mode-switch",role:"tablist","aria-label":"Review Lens mode",children:[n.jsx("button",{type:"button",role:"tab","aria-selected":M==="review",onClick:()=>_("review"),children:"Review"}),n.jsxs("button",{type:"button",role:"tab","aria-selected":M==="feedback",onClick:()=>_("feedback"),children:["Feedback ",n.jsx("span",{children:T.length})]}),n.jsx("button",{type:"button",role:"tab","aria-selected":M==="summary",onClick:()=>_("summary"),children:"Summary"})]}),M==="review"?n.jsxs("div",{className:"review-lens-review-pane",role:"tabpanel",children:[n.jsxs("div",{className:"review-lens-inspection",children:[$?null:n.jsx("p",{children:"Authenticate with Google to inspect this page."}),$&&D?n.jsxs(n.Fragment,{children:[n.jsx(Ot,{target:D}),n.jsx(Me,{title:"Accessibility",items:Kt(D)}),n.jsx(Me,{title:"Design tokens",items:Jt(D.cssSnapshot,m.designTokens)})]}):null,$&&!D?n.jsx("p",{children:"Move over the app to inspect."}):null]}),or?n.jsx("div",{className:"review-lens-composer-panel",children:n.jsxs("form",{className:"review-lens-feedback-form",onSubmit:i=>{i.preventDefault(),Qe()},children:[n.jsx("label",{htmlFor:"review-lens-comment",children:"New feedback"}),n.jsx("textarea",{ref:te,id:"review-lens-comment",value:F,disabled:!P,onChange:i=>B(i.target.value),onKeyDown:i=>{i.key==="Enter"&&i.metaKey&&(i.preventDefault(),Qe())},placeholder:P?"Describe the UX issue...":"You do not have permission to comment."}),n.jsxs("div",{className:"review-lens-form-grid",children:[n.jsxs("label",{children:["Severity",n.jsx("select",{value:U,onChange:i=>Rt(i.target.value),disabled:!P,children:Ie.map(i=>n.jsx("option",{value:i,children:O[i]},i))})]}),n.jsxs("label",{children:["Type",n.jsx("select",{value:_e,onChange:i=>er(i.target.value),disabled:!P,children:Te.map(i=>n.jsx("option",{value:i,children:K[i]},i))})]}),n.jsxs("label",{children:["Assignee",n.jsx("input",{value:je,onChange:i=>Ue(i.target.value),disabled:!P,placeholder:"optional@email.com"})]}),n.jsxs("label",{children:["Viewport",n.jsx("select",{value:De,onChange:i=>tr(i.target.value),disabled:!P,children:l.map(i=>n.jsx("option",{value:i.value,children:i.label},i.value))})]})]}),P?n.jsxs("p",{className:"review-lens-feedback-form__hint",children:["Press ",n.jsx("kbd",{children:"Command"})," + ",n.jsx("kbd",{children:"Enter"})," to submit.",lr?" Screenshot capture runs after save.":""]}):null,n.jsx("div",{className:"review-lens-actions",children:n.jsx("button",{type:"submit",disabled:!F.trim()||!P,children:"Save feedback"})})]})}):null]}):null,M==="feedback"?n.jsxs("div",{className:"review-lens-comments",children:[n.jsx($t,{open:nr,activeCount:cr,statusFilter:V,severityFilter:Y,categoryFilter:X,assigneeFilter:Q,viewportFilter:Z,assignees:dr,responsivePresets:l,onStatusChange:ze,onSeverityChange:He,onCategoryChange:Oe,onAssigneeChange:Ke,onViewportChange:Je,onToggle:()=>sr(i=>!i),onClear:()=>{ze("all"),He("all"),Oe("all"),Ke("all"),Je("all")}}),n.jsxs("div",{className:"review-lens-list-panel",children:[n.jsxs("div",{className:"review-lens-comments__header",children:[n.jsx("h3",{children:"All feedback"}),n.jsx("span",{children:T.length})]}),n.jsxs("div",{className:"review-lens-comments__list",children:[T.length===0?n.jsx("p",{children:"No feedback for this view."}):null,T.map(i=>n.jsx(Bt,{item:i,selected:(k==null?void 0:k.id)===i.id,onSelect:H},i.id))]})]}),k?n.jsxs("div",{className:"review-lens-selected-panel",children:[n.jsx("div",{className:"review-lens-selected-panel__label",children:"Selected feedback"}),n.jsx(Pt,{item:k,messages:ir[k.id]??[],messageDraft:le,canReply:Ve,canUpdate:Ye,canAssign:ar,syncSelectionToUrl:a,onMessageDraftChange:de,onSubmitMessage:()=>void ur(k),onStatusChange:i=>void hr(k,i),onAssigneeChange:i=>void v(k.id,{assigneeEmail:i.trim()||void 0}).then(q),onMarkFixed:()=>void Ze(k)},k.id)]}):n.jsxs("div",{className:"review-lens-selected-panel review-lens-selected-panel--empty",children:[n.jsx("div",{className:"review-lens-selected-panel__label",children:"Selected feedback"}),n.jsx("p",{children:"Select a feedback item above to review status, assignment, drift, and replies."})]})]}):null,M==="summary"?n.jsx(jt,{feedback:b}):null]})]})]})}function $t({open:e,activeCount:t,statusFilter:r,severityFilter:s,categoryFilter:a,assigneeFilter:l,viewportFilter:u,assignees:m,responsivePresets:g,onStatusChange:b,onSeverityChange:A,onCategoryChange:x,onAssigneeChange:f,onViewportChange:v,onToggle:c,onClear:S}){return n.jsxs("div",{className:"review-lens-filter-shell",children:[n.jsxs("div",{className:"review-lens-filter-bar",children:[n.jsxs("button",{type:"button","aria-expanded":e,onClick:c,children:["Filters",t>0?n.jsx("span",{children:t}):null]}),t>0?n.jsx("button",{type:"button",onClick:S,children:"Clear"}):null]}),e?n.jsxs("div",{className:"review-lens-filters",children:[n.jsxs("label",{children:["Status",n.jsxs("select",{"aria-label":"Filter status",value:r,onChange:o=>b(o.target.value),children:[n.jsx("option",{value:"all",children:"All statuses"}),Fe.map(o=>n.jsx("option",{value:o,children:R[o]},o))]})]}),n.jsxs("label",{children:["Priority",n.jsxs("select",{"aria-label":"Filter severity",value:s,onChange:o=>A(o.target.value),children:[n.jsx("option",{value:"all",children:"All priorities"}),Ie.map(o=>n.jsx("option",{value:o,children:O[o]},o))]})]}),n.jsxs("label",{children:["Type",n.jsxs("select",{"aria-label":"Filter type",value:a,onChange:o=>x(o.target.value),children:[n.jsx("option",{value:"all",children:"All types"}),Te.map(o=>n.jsx("option",{value:o,children:K[o]},o))]})]}),n.jsxs("label",{children:["Assignee",n.jsxs("select",{"aria-label":"Filter assignee",value:l,onChange:o=>f(o.target.value),children:[n.jsx("option",{value:"all",children:"All assignees"}),m.map(o=>n.jsx("option",{value:o,children:o},o))]})]}),n.jsxs("label",{children:["Viewport",n.jsxs("select",{"aria-label":"Filter viewport",value:u,onChange:o=>v(o.target.value),children:[n.jsx("option",{value:"all",children:"All viewports"}),g.map(o=>n.jsx("option",{value:o.value,children:o.label},o.value))]})]})]}):null]})}function Bt({item:e,selected:t,onSelect:r}){const s=$e(e);return n.jsxs("article",{tabIndex:0,className:["review-lens-comment",`review-lens-comment--${e.severity}`,t?"review-lens-comment--selected":""].filter(Boolean).join(" "),onClick:()=>r(e),onKeyDown:a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),r(e))},children:[n.jsxs("div",{className:"review-lens-comment__header",children:[n.jsx("span",{children:R[e.status]}),n.jsx("strong",{children:O[e.severity]})]}),n.jsxs("div",{className:"review-lens-comment__content",children:[n.jsx("p",{children:e.comment}),n.jsxs("span",{children:[e.authorEmail,e.assigneeEmail?` -> ${e.assigneeEmail}`:""]})]}),n.jsxs("div",{className:"review-lens-tags",children:[n.jsx("span",{children:K[e.category]}),n.jsx("span",{children:e.viewportPreset}),n.jsx("span",{children:s.label})]})]})}function Pt({item:e,messages:t,messageDraft:r,canReply:s,canUpdate:a,canAssign:l,syncSelectionToUrl:u,onMessageDraftChange:m,onSubmitMessage:g,onStatusChange:b,onAssigneeChange:A,onMarkFixed:x}){const[f,v]=h.useState(!1),c=$e(e);function S(){const o=new URL(window.location.href);o.searchParams.set("reviewLensFeedback",e.id),_t(o.toString()).then(C=>{C&&(v(!0),setTimeout(()=>v(!1),2e3))})}return n.jsxs("section",{className:"review-lens-detail","aria-label":"Selected feedback detail",children:[n.jsxs("div",{className:"review-lens-detail__header",children:[n.jsxs("h3",{children:[K[e.category]," feedback"]}),n.jsxs("div",{className:"review-lens-detail__header-actions",children:[u?n.jsx("button",{type:"button",className:"review-lens-copy-link",onClick:S,"aria-label":"Copy link to this feedback",children:f?"Copied!":"Copy link"}):null,n.jsx("strong",{children:O[e.severity]})]})]}),n.jsx("blockquote",{children:e.comment}),n.jsxs("dl",{className:"review-lens-detail-meta",children:[n.jsxs("div",{children:[n.jsx("dt",{children:"Target"}),n.jsx("dd",{children:c.label})]}),n.jsxs("div",{children:[n.jsx("dt",{children:"Viewport"}),n.jsx("dd",{children:e.viewportPreset})]}),e.screenshotUrl?n.jsxs("div",{children:[n.jsx("dt",{children:"Evidence"}),n.jsx("dd",{children:n.jsx("a",{href:e.screenshotUrl,target:"_blank",rel:"noreferrer",children:"Screenshot"})})]}):null]}),n.jsxs("div",{className:"review-lens-form-grid",children:[n.jsxs("label",{children:["Status",n.jsx("select",{value:e.status,disabled:!a,onChange:o=>b(o.target.value),children:Fe.map(o=>n.jsx("option",{value:o,children:R[o]},o))})]}),n.jsxs("label",{children:["Assignee",n.jsx("input",{defaultValue:e.assigneeEmail??"",disabled:!l,onBlur:o=>A(o.target.value),placeholder:"optional@email.com"})]})]}),n.jsxs("div",{className:"review-lens-status-actions",children:[n.jsx("button",{type:"button",className:"review-lens-button-secondary",disabled:!a,onClick:x,children:"Mark fixed"}),n.jsx("button",{type:"button",className:"review-lens-button-primary",disabled:!a,onClick:()=>b("resolved"),children:"Resolve"})]}),n.jsxs("div",{className:"review-lens-thread",children:[n.jsxs("div",{className:"review-lens-thread__header",children:[n.jsx("h3",{children:"Thread"}),n.jsx("span",{children:t.length})]}),t.length===0?n.jsx("p",{children:"No replies yet."}):null,t.map(o=>n.jsxs("div",{className:"review-lens-thread__message",children:[n.jsx("p",{children:o.body}),n.jsx("span",{children:o.authorEmail})]},o.id)),n.jsx("textarea",{"aria-label":"Reply",value:r,disabled:!s,onChange:o=>m(o.target.value),placeholder:s?"Reply...":"You do not have permission to reply."}),n.jsx("div",{className:"review-lens-actions",children:n.jsx("button",{type:"button",disabled:!r.trim()||!s,onClick:g,children:"Reply"})})]})]})}async function _t(e){var r;if((r=navigator.clipboard)!=null&&r.writeText)return await navigator.clipboard.writeText(e),!0;const t=document.createElement("textarea");t.value=e,t.setAttribute("readonly",""),t.style.position="fixed",t.style.opacity="0",document.body.append(t),t.select();try{return document.execCommand("copy")}finally{t.remove()}}function jt({feedback:e}){return n.jsxs("div",{className:"review-lens-summary",role:"tabpanel",children:[n.jsx(J,{title:"Status",values:G(e,t=>R[t.status])}),n.jsx(J,{title:"Severity",values:G(e,t=>O[t.severity])}),n.jsx(J,{title:"Type",values:G(e,t=>K[t.category])}),n.jsx(J,{title:"Assignee",values:G(e,t=>t.assigneeEmail??"Unassigned")}),n.jsx(J,{title:"Viewport",values:G(e,t=>t.viewportPreset)})]})}function J({title:e,values:t}){return n.jsxs("section",{children:[n.jsx("h3",{children:e}),n.jsx("dl",{children:t.map(([r,s])=>n.jsxs("div",{children:[n.jsx("dt",{children:r}),n.jsx("dd",{children:s})]},r))})]})}function Ut({target:e,locked:t}){const r=Zt(e),s=qt(e.fingerprint);return n.jsxs("div",{className:t?"review-lens-highlight review-lens-highlight--locked":"review-lens-highlight",style:{top:r.margin.top,left:r.margin.left,width:r.margin.width,height:r.margin.height},children:[n.jsx("div",{className:"review-lens-highlight__border",style:{top:r.border.top-r.margin.top,left:r.border.left-r.margin.left,width:r.border.width,height:r.border.height}}),n.jsx("div",{className:"review-lens-highlight__padding",style:{top:r.padding.top-r.margin.top,left:r.padding.left-r.margin.left,width:r.padding.width,height:r.padding.height}}),n.jsx("div",{className:"review-lens-highlight__content",style:{top:r.content.top-r.margin.top,left:r.content.left-r.margin.left,width:r.content.width,height:r.content.height}}),n.jsxs("div",{className:"review-lens-highlight__label",children:[n.jsx("strong",{children:s}),n.jsxs("span",{children:[Math.round(e.rect.width)," x ",Math.round(e.rect.height)]})]})]})}function Dt({from:e,to:t}){const r=Vt(e.rect,t.rect);return r.length===0?null:n.jsx(n.Fragment,{children:r.map(s=>n.jsx("div",{className:`review-lens-distance review-lens-distance--${s.axis}`,style:{top:s.top,left:s.left,width:s.width,height:s.height},children:n.jsx("span",{children:s.label})},s.key))})}function Wt({feedback:e,selectedFeedback:t,onSelect:r}){return n.jsx(n.Fragment,{children:e.map(s=>n.jsx(zt,{feedback:s,selected:(t==null?void 0:t.id)===s.id,onSelect:r},s.id))})}function zt({feedback:e,selected:t,onSelect:r}){const s=h.useRef(null);return h.useLayoutEffect(()=>{let a=0;const l=()=>{a=0;const m=s.current,g=z(e.selector),b=g==null?void 0:g.getBoundingClientRect();!m||!b||(m.style.top=`${b.top}px`,m.style.left=`${b.right}px`,m.hidden=b.bottom<0||b.top>window.innerHeight)},u=()=>{a||(a=window.requestAnimationFrame(l))};return l(),window.addEventListener("scroll",u,!0),window.addEventListener("resize",u),()=>{a&&window.cancelAnimationFrame(a),window.removeEventListener("scroll",u,!0),window.removeEventListener("resize",u)}},[e.selector]),n.jsx("button",{ref:s,type:"button",className:t?"review-lens-marker review-lens-marker--selected":"review-lens-marker",onClick:()=>r(e),"aria-label":`Open feedback from ${e.authorEmail}`})}function Ht({feedback:e,selectedFeedback:t,onSelect:r}){const s=e.map(a=>{const l=z(a.selector),u=l==null?void 0:l.getBoundingClientRect(),m=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight,window.innerHeight);return!u||m<=0?null:{item:a,top:Math.min(100,Math.max(0,(u.top+window.scrollY)/m*100))}}).filter(a=>a!==null);return s.length===0?null:n.jsx("div",{className:"review-lens-minimap","data-review-lens-ui":!0,"aria-label":"Feedback map",children:s.map(a=>n.jsx("button",{type:"button",className:(t==null?void 0:t.id)===a.item.id?"review-lens-minimap__point review-lens-minimap__point--selected":"review-lens-minimap__point",style:{top:`${a.top}%`},onClick:()=>r(a.item),"aria-label":`Jump to feedback from ${a.item.authorEmail}`},a.item.id))})}function Ot({target:e}){const t=[["Selector",e.selector],["Size",`${e.cssSnapshot.width} x ${e.cssSnapshot.height}`],["Margin",e.cssSnapshot.margin],["Padding",e.cssSnapshot.padding],["Border",e.cssSnapshot.border],["Radius",e.cssSnapshot.borderRadius],["Font",`${e.cssSnapshot.fontSize} / ${e.cssSnapshot.lineHeight}`],["Family",e.cssSnapshot.fontFamily],["Color",e.cssSnapshot.color],["Background",e.cssSnapshot.backgroundColor]];return n.jsx("dl",{className:"review-lens-metrics",children:t.map(([r,s])=>n.jsxs("div",{children:[n.jsx("dt",{children:r}),n.jsx("dd",{children:s})]},r))})}function Me({title:e,items:t}){return n.jsxs("section",{className:"review-lens-insights",children:[n.jsx("h3",{children:e}),t.length===0?n.jsx("p",{children:"No issues detected."}):null,t.length>0?n.jsx("ul",{children:t.map(r=>n.jsx("li",{children:r},r))}):null]})}function z(e){try{return document.querySelector(e)}catch{return null}}function $e(e){const t=z(e.selector);if(!t)return{label:"Target missing",level:"warning"};const r=W(t);return r.fingerprint.tagName!==e.elementFingerprint.tagName?{label:"Element changed",level:"warning"}:Math.abs(r.fingerprint.width-e.elementFingerprint.width)>2||Math.abs(r.fingerprint.height-e.elementFingerprint.height)>2?{label:"Size changed",level:"warning"}:r.cssSnapshot.fontSize!==e.createdCssSnapshot.fontSize||r.cssSnapshot.color!==e.createdCssSnapshot.color||r.cssSnapshot.padding!==e.createdCssSnapshot.padding?{label:"Style changed",level:"warning"}:{label:"Target unchanged",level:"ok"}}function Kt(e){var g;const t=z(e.selector);if(!t)return["Selected element is no longer available."];const r=[],s=t.tagName.toLowerCase(),a=t.getAttribute("role"),l=["button","a","input","select","textarea"].includes(s)||a==="button"||a==="link",u=t.getAttribute("aria-label")||t.getAttribute("title")||((g=t.textContent)==null?void 0:g.trim());l&&!u&&r.push("Interactive element has no accessible name."),l&&(e.rect.width<44||e.rect.height<44)&&r.push("Tap target is smaller than 44 x 44."),s==="img"&&!t.getAttribute("alt")&&r.push("Image is missing alt text.");const m=/^h[1-6]$/.test(s)?Number(s.slice(1)):0;return m>1&&!document.querySelector(`h${m-1}`)&&r.push("Heading may skip the previous level."),Xt(e.cssSnapshot.color,e.cssSnapshot.backgroundColor)&&r.push("Text contrast may be low."),r}function Jt(e,t={}){const r=[];return j("Padding",e.padding,t.spacing,r,{allowComposite:!0}),j("Margin",e.margin,t.spacing,r,{allowComposite:!0}),j("Font size",e.fontSize,t.fontSize,r),j("Line height",e.lineHeight,t.lineHeight,r),j("Text color",e.color,t.color,r),j("Background",e.backgroundColor,t.color,r),j("Radius",e.borderRadius,t.radius,r,{allowComposite:!0}),r}function j(e,t,r,s,a={}){!r||r.length===0||!t||Gt(t,r,a)||s.push(`${e} ${t} is outside configured tokens.`)}function Gt(e,t,r={}){if(t.includes(e))return!0;if(!r.allowComposite)return!1;const s=e.trim().split(/\s+/);return s.length>1&&s.every(a=>t.includes(a))}function qt(e){const t=e.id?`#${e.id}`:"",r=e.className?`.${e.className.split(/\s+/).filter(Boolean).slice(0,2).join(".")}`:"",s=e.ariaLabel?`[aria-label="${e.ariaLabel}"]`:"";return`${e.tagName}${t}${r}${s}`||e.tagName}function Vt(e,t){const r=[],s=(Math.max(e.left,t.left)+Math.min(e.right,t.right))/2,a=(Math.max(e.top,t.top)+Math.min(e.bottom,t.bottom))/2;if(e.right<=t.left||t.right<=e.left){const l=e.right<=t.left?e.right:t.right,u=e.right<=t.left?t.left:e.left;r.push({key:"horizontal",axis:"horizontal",top:Be(a,0,window.innerHeight),left:l,width:Math.max(u-l,1),height:1,label:`${Math.round(u-l)}px`})}if(e.bottom<=t.top||t.bottom<=e.top){const l=e.bottom<=t.top?e.bottom:t.bottom,u=e.bottom<=t.top?t.top:e.top;r.push({key:"vertical",axis:"vertical",top:l,left:Be(s,0,window.innerWidth),width:1,height:Math.max(u-l,1),label:`${Math.round(u-l)}px`})}return r}function Be(e,t,r){return Math.min(Math.max(e,t),r)}function G(e,t){const r=new Map;for(const s of e){const a=t(s);r.set(a,(r.get(a)??0)+1)}return Array.from(r.entries()).sort((s,a)=>a[1]-s[1]||s[0].localeCompare(a[0]))}function Yt(e){return e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement||e instanceof HTMLElement&&e.isContentEditable}function Xt(e,t){const r=Pe(e),s=Pe(t);return!r||!s||s.alpha===0?!1:Qt(r,s)<4.5}function Pe(e){const t=e.match(/rgba?\(([^)]+)\)/);if(!t)return null;const[r,s,a,l="1"]=t[1].split(",").map(u=>u.trim());return{red:Number(r),green:Number(s),blue:Number(a),alpha:Number(l)}}function Qt(e,t){const r=Math.max(ee(e),ee(t)),s=Math.min(ee(e),ee(t));return(r+.05)/(s+.05)}function ee(e){const t=[e.red,e.green,e.blue].map(r=>{const s=r/255;return s<=.03928?s/12.92:((s+.055)/1.055)**2.4});return t[0]*.2126+t[1]*.7152+t[2]*.0722}function Zt(e){const t={top:I(e.cssSnapshot.marginTop),right:I(e.cssSnapshot.marginRight),bottom:I(e.cssSnapshot.marginBottom),left:I(e.cssSnapshot.marginLeft)},r={top:I(e.cssSnapshot.borderTopWidth),right:I(e.cssSnapshot.borderRightWidth),bottom:I(e.cssSnapshot.borderBottomWidth),left:I(e.cssSnapshot.borderLeftWidth)},s={top:I(e.cssSnapshot.paddingTop),right:I(e.cssSnapshot.paddingRight),bottom:I(e.cssSnapshot.paddingBottom),left:I(e.cssSnapshot.paddingLeft)},a={top:e.rect.top,left:e.rect.left,width:Math.max(e.rect.width,0),height:Math.max(e.rect.height,0)},l={top:a.top-t.top,left:a.left-t.left,width:a.width+t.left+t.right,height:a.height+t.top+t.bottom},u={top:a.top+r.top,left:a.left+r.left,width:Math.max(a.width-r.left-r.right,0),height:Math.max(a.height-r.top-r.bottom,0)},m={top:u.top+s.top,left:u.left+s.left,width:Math.max(u.width-s.left-s.right,0),height:Math.max(u.height-s.top-s.bottom,0)};return{margin:l,border:a,padding:u,content:m}}function I(e){const t=Number.parseFloat(e);return Number.isFinite(t)?t:0}L.ReviewLensLogo=Ae,L.ReviewLensOverlay=Mt,L.ReviewLensProvider=bt,L.buildElementTarget=W,L.createGoogleSheetsAdapter=fe,L.normalizeReviewUrl=Se,L.useReviewLens=Ee,Object.defineProperty(L,Symbol.toStringTag,{value:"Module"})}));
@@ -24,6 +24,7 @@ declare global {
24
24
  scope: string;
25
25
  callback: (response: {
26
26
  access_token?: string;
27
+ expires_in?: number;
27
28
  error?: string;
28
29
  }) => void;
29
30
  }): TokenClient;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "review-lens-react",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "React overlay for UX review feedback backed by Google Sheets.",
5
5
  "repository": {
6
6
  "type": "git",