review-lens-react 1.0.0 → 1.0.1

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 +1,3 @@
1
- (function(x,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):(x=typeof globalThis<"u"?globalThis:x||self,r(x.ReviewLensReact={},x.jsxRuntime,x.React))})(this,(function(x,r,l){"use strict";const Ke=["https://www.googleapis.com/auth/spreadsheets","https://www.googleapis.com/auth/userinfo.email"].join(" "),Je="https://www.googleapis.com/oauth2/v3/userinfo";function de(e){const t=e.feedbackSheetName??"Feedback",n=e.messagesSheetName??"Messages",s=e.usersSheetName??"Users";let i,d;async function f(){return i??(i=tt(e.googleClientId)),i}async function b(c,w,h){const v=await f(),k=await fetch(`https://sheets.googleapis.com/v4/spreadsheets/${c}${w}`,{...h,headers:{Authorization:`Bearer ${v}`,"Content-Type":"application/json",...h==null?void 0:h.headers}});if(!k.ok)throw new Error(`Google Sheets request failed with ${k.status}`);return k.json()}async function u(c,w){return(await b(c,`/values/${encodeURIComponent(w)}`)).values??[]}return{async getCurrentUser(){if(!d){const c=await f(),w=await fetch(Je,{headers:{Authorization:`Bearer ${c}`}});if(!w.ok)throw new Error(`Google userinfo request failed with ${w.status}`);d=(await w.json()).email}if(!d)throw new Error("Google account did not return an email address");return{email:d}},async getPermissions(c){const[{email:w},h]=await Promise.all([this.getCurrentUser(),u(e.usersSpreadsheetId,s)]),v=ne(h),k=w.toLowerCase(),E=v.find(A=>{var p;return((p=A.email)==null?void 0:p.toLowerCase())===k&&A.active!=="false"&&(!A.projectKey||A.projectKey===c)});return Ye((E==null?void 0:E.role)??"designer")},async listFeedback(c){return ne(await u(e.contentSpreadsheetId,t)).map(ue).filter(h=>h!==null).filter(h=>h.projectKey===c.projectKey&&h.contentId===c.contentId&&h.normalizedPath===c.normalizedPath).sort((h,v)=>v.createdAt.localeCompare(h.createdAt))},async createFeedback(c){const w=new Date().toISOString(),h={...c,id:crypto.randomUUID(),attachments:[],createdAt:w,updatedAt:w};return await b(e.contentSpreadsheetId,`/values/${encodeURIComponent(t)}:append?valueInputOption=RAW`,{method:"POST",body:JSON.stringify({values:[he(h)]})}),h},async updateFeedback(c,w){const h=await u(e.contentSpreadsheetId,t),v=h[0]??ce,k=v.indexOf("id");if(k===-1)throw new Error(`Sheet ${t} is missing an id column`);const E=h.findIndex((m,C)=>C>0&&m[k]===c);if(E<1)throw new Error(`Feedback ${c} was not found`);const A=new Date().toISOString(),p=ue(pe(v,h[E]));if(!p)throw new Error(`Feedback ${c} could not be parsed before updating`);const B={...p,...w,updatedAt:A},y=he(B);return await b(e.contentSpreadsheetId,`/values/${encodeURIComponent(t)}!A${E+1}:${et(ce.length)}${E+1}?valueInputOption=RAW`,{method:"PUT",body:JSON.stringify({values:[y]})}),B},async listMessages(c){return ne(await u(e.contentSpreadsheetId,n)).map(Ge).filter(h=>h!==null).filter(h=>h.feedbackId===c).sort((h,v)=>h.createdAt.localeCompare(v.createdAt))},async createMessage(c){const w={...c,id:crypto.randomUUID(),createdAt:new Date().toISOString()};return await b(e.contentSpreadsheetId,`/values/${encodeURIComponent(n)}:append?valueInputOption=RAW`,{method:"POST",body:JSON.stringify({values:[Ve(w)]})}),w}}}const ce=["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"],qe=["id","feedbackId","body","authorEmail","createdAt"];function he(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 Ve(e){return qe.map(t=>e[t])}function ne(e){const[t,...n]=e;return t?n.map(s=>pe(t,s)):[]}function pe(e,t){return Object.fromEntries(e.map((n,s)=>[n,t[s]??""]))}function ue(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:re(e.elementFingerprintJson,{tagName:"",width:0,height:0}),createdCssSnapshot:ge(e.createdCssSnapshotJson),fixedCssSnapshot:e.fixedCssSnapshotJson?ge(e.fixedCssSnapshotJson):void 0,comment:e.comment,status:Xe(e.status),severity:Qe(e.severity),category:Ze(e.category),assigneeEmail:e.assigneeEmail||void 0,viewportWidth:Number(e.viewportWidth)||0,viewportHeight:Number(e.viewportHeight)||0,viewportPreset:Re(e.viewportPreset),screenshotUrl:e.screenshotUrl||void 0,screenshotThumbnailUrl:e.screenshotThumbnailUrl||void 0,attachments:re(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 Ge(e){return!e.id||!e.feedbackId?null:{id:e.id,feedbackId:e.feedbackId,body:e.body,authorEmail:e.authorEmail,createdAt:e.createdAt}}function re(e,t){try{return e?JSON.parse(e):t}catch{return t}}function ge(e){const t=re(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 Ye(e){return e==="admin"?["create","read","reply","update","assign"]:e==="developer"?["read","reply","update","assign"]:["create","read","reply"]}function Xe(e){return e==="in_progress"||e==="needs_clarification"||e==="fixed"||e==="wontfix"||e==="resolved"?e:"open"}function Qe(e){return e==="low"||e==="high"?e:"medium"}function Ze(e){return e==="visual"||e==="copy"||e==="accessibility"||e==="responsive"?e:"bug"}function Re(e){return e==="mobile"||e==="tablet"||e==="desktop"?e:"custom"}function et(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 tt(e){return await nt(),new Promise((t,n)=>{var i;const s=(i=window.google)==null?void 0:i.accounts.oauth2.initTokenClient({client_id:e,scope:Ke,callback:d=>{if(d.error||!d.access_token){n(new Error(d.error??"Google OAuth did not return an access token"));return}t(d.access_token)}});s==null||s.requestAccessToken({prompt:""})})}function nt(){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 i=document.createElement("script");i.src="https://accounts.google.com/gsi/client",i.async=!0,i.defer=!0,i.onload=()=>t(),i.onerror=()=>n(new Error("Google Identity failed to load")),document.head.append(i)})}function fe(e){return new URL(e,window.location.href).pathname.replace(/\/+$/,"")||"/"}const be=l.createContext(null);function rt({config:e,children:t}){const n=l.useMemo(()=>e.adapter?e.adapter:de({googleClientId:se(e.googleClientId,"googleClientId"),contentSpreadsheetId:se(e.contentSpreadsheetId,"contentSpreadsheetId"),usersSpreadsheetId:se(e.usersSpreadsheetId,"usersSpreadsheetId"),feedbackSheetName:e.sheetName??"Feedback"}),[e.adapter,e.contentSpreadsheetId,e.googleClientId,e.sheetName,e.usersSpreadsheetId]),s=e.currentUrl??window.location.href,i=(e.normalizeUrl??fe)(s),[d,f]=l.useState(),[b,u]=l.useState([]),[c,w]=l.useState([]),h=l.useCallback(async()=>{const y=await n.listFeedback({projectKey:e.projectKey,contentId:e.contentId,normalizedPath:i});w(y)},[n,e.contentId,e.projectKey,i]);l.useEffect(()=>{let y=!0;async function m(){const[C,$]=await Promise.all([n.getCurrentUser(),n.getPermissions(e.projectKey)]);y&&(f(C),u($),await h())}return m(),()=>{y=!1}},[n,e.projectKey,h]);const v=l.useCallback(async y=>{const m=await n.createFeedback(y);return w(C=>[m,...C]),m},[n]),k=l.useCallback(async(y,m)=>{const C=await n.updateFeedback(y,m);return w($=>$.map(z=>z.id===y?C:z)),C},[n]),E=l.useCallback(y=>n.listMessages(y),[n]),A=l.useCallback(y=>n.createMessage(y),[n]),p=l.useCallback(async(y,m)=>{const C=e.uploadAttachment??n.uploadAttachment;if(!C)throw new Error("Review Lens attachment upload is not configured");return C(y,m)},[n,e]),B=l.useMemo(()=>({config:e,adapter:n,currentUser:d,permissions:b,feedback:c,normalizedPath:i,refreshFeedback:h,createFeedback:v,updateFeedback:k,listMessages:E,createMessage:A,uploadAttachment:p}),[n,e,v,d,c,i,b,h,k,E,A,p]);return r.jsx(be.Provider,{value:B,children:t})}function ve(){const e=l.useContext(be);if(!e)throw new Error("useReviewLens must be used inside ReviewLensProvider");return e}function se(e,t){if(!e)throw new Error(`review-lens-react requires config.${t} when no adapter is provided`);return e}const st=["data-review-id","data-testid","data-test-id","aria-label","name"];function W(e){const t=e.getBoundingClientRect(),n=at(e);return{selector:n.selector,selectorStrategy:n.strategy,fingerprint:ot(e,t),cssSnapshot:lt(e,t),rect:t}}function at(e){for(const t of st){const n=e.getAttribute(t);if(n)return{selector:`[${t}="${we(n)}"]`,strategy:"stable-attribute"}}return e.id?{selector:`#${we(e.id)}`,strategy:"stable-attribute"}:{selector:it(e),strategy:"css-path"}}function it(e){const t=[];let n=e;for(;n&&n.nodeType===Node.ELEMENT_NODE&&n!==document.body;){const s=n.parentElement,i=n.tagName.toLowerCase();if(!s){t.unshift(i);break}const d=n.tagName,f=Array.from(s.children).filter(u=>u.tagName===d),b=f.indexOf(n)+1;t.unshift(f.length>1?`${i}:nth-of-type(${b})`:i),n=s}return t.join(" > ")}function ot(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 lt(e,t){const n=window.getComputedStyle(e);return{margin:ae(n.marginTop,n.marginRight,n.marginBottom,n.marginLeft),marginTop:n.marginTop,marginRight:n.marginRight,marginBottom:n.marginBottom,marginLeft:n.marginLeft,padding:ae(n.paddingTop,n.paddingRight,n.paddingBottom,n.paddingLeft),paddingTop:n.paddingTop,paddingRight:n.paddingRight,paddingBottom:n.paddingBottom,paddingLeft:n.paddingLeft,border:ae(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 ae(e,t,n,s){return e===t&&t===n&&n===s?e:`${e} ${t} ${n} ${s}`}function we(e){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(e):e.replace(/["\\]/g,"\\$&")}const dt=[{label:"Desktop",value:"desktop"},{label:"Tablet",value:"tablet"},{label:"Mobile",value:"mobile"}],me=["open","in_progress","needs_clarification","fixed","wontfix","resolved"],ye=["low","medium","high"],Se=["bug","visual","copy","accessibility","responsive"],Z={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"},j={bug:"Bug",visual:"Visual",copy:"Copy",accessibility:"Accessibility",responsive:"Responsive"};function ct({open:e,onOpenChange:t,placement:n="top-right",showResolved:s=!1,syncSelectionToUrl:i=!1,responsivePresets:d=dt}){var Oe;const{adapter:f,config:b,currentUser:u,feedback:c,normalizedPath:w,permissions:h,createFeedback:v,updateFeedback:k,listMessages:E,createMessage:A,uploadAttachment:p}=ve(),[B,y]=l.useState(),[m,C]=l.useState(),[$,z]=l.useState(""),[xe,Mt]=l.useState("medium"),[Ae,It]=l.useState("visual"),[Le,Fe]=l.useState(""),[Me,Tt]=l.useState(((Oe=d[0])==null?void 0:Oe.value)??"desktop"),[S,J]=l.useState(),[M,P]=l.useState("review"),[Bt,Ie]=l.useState(!1),[q,Te]=l.useState("all"),[V,Be]=l.useState("all"),[G,$e]=l.useState("all"),[Y,Pe]=l.useState("all"),[X,_e]=l.useState("all"),[$t,Pt]=l.useState(!1),[_t,Ue]=l.useState({}),[ie,oe]=l.useState(""),ee=l.useRef(null),I=!!u,T=h.includes("create"),We=h.includes("reply"),De=h.includes("update"),Ut=h.includes("assign"),U=B??m,Wt=!!m,Dt=!!(b.captureScreenshot&&(b.uploadAttachment||f.uploadAttachment)),zt=l.useMemo(()=>{const a=c.map(g=>g.assigneeEmail).filter(g=>!!g);return u!=null&&u.email&&a.push(u.email),Array.from(new Set(a)).sort((g,o)=>g.localeCompare(o))},[u==null?void 0:u.email,c]),F=l.useMemo(()=>c.filter(a=>s||a.status!=="resolved").filter(a=>q==="all"||a.status===q).filter(a=>V==="all"||a.severity===V).filter(a=>G==="all"||a.category===G).filter(a=>Y==="all"||a.assigneeEmail===Y).filter(a=>X==="all"||a.viewportPreset===X),[Y,G,c,V,s,q,X]),Ht=[q,V,G,Y,X].filter(a=>a!=="all").length;l.useEffect(()=>{e||(y(void 0),C(void 0),z(""),oe(""),P("review"))},[e]),l.useEffect(()=>{I||(y(void 0),C(void 0))},[I]),l.useEffect(()=>{!m||M!=="review"||window.requestAnimationFrame(()=>{var a,g,o;(g=(a=ee.current)==null?void 0:a.scrollIntoView)==null||g.call(a,{block:"nearest"}),(o=ee.current)==null||o.focus()})},[m,M]),l.useEffect(()=>{if(!S)return;let a=!0;return E(S.id).then(g=>{a&&Ue(o=>({...o,[S.id]:g}))}),()=>{a=!1}},[E,S]),l.useEffect(()=>{if(!e||!i||S||c.length===0)return;const a=new URL(window.location.href).searchParams.get("reviewLensFeedback"),g=c.find(o=>o.id===a);g&&Q(g,{syncUrl:!1})},[c,e,S,i]),l.useEffect(()=>{if(!e)return;function a(o){var N;if(o.key==="Shift"&&Ie(!0),o.key==="Escape"){o.preventDefault(),t==null||t(!1);return}xt(o.target)||((o.key==="n"||o.key==="ArrowDown")&&(o.preventDefault(),ze(1)),(o.key==="p"||o.key==="ArrowUp")&&(o.preventDefault(),ze(-1)),o.key==="c"&&(o.preventDefault(),P("review"),(N=ee.current)==null||N.focus()),o.key==="f"&&S&&De&&(o.preventDefault(),je(S)))}function g(o){o.key==="Shift"&&Ie(!1)}return window.addEventListener("keydown",a),window.addEventListener("keyup",g),()=>{window.removeEventListener("keydown",a),window.removeEventListener("keyup",g)}});const le=l.useCallback(a=>{const g=a.target instanceof Element?a.target:null;if(g)return g.closest("[data-review-lens-ui]")?null:g;const o=document.elementFromPoint(a.clientX,a.clientY);return!o||o.closest("[data-review-lens-ui]")?null:o},[]);if(l.useEffect(()=>{if(!e||!I)return;function a(o){const N=le(o);y(N?W(N):void 0)}function g(o){const N=le(o);N&&(o.preventDefault(),o.stopPropagation(),C(W(N)),P("review"))}return window.addEventListener("mousemove",a,!0),window.addEventListener("click",g,!0),()=>{window.removeEventListener("mousemove",a,!0),window.removeEventListener("click",g,!0)}},[I,le,e]),!e)return null;function Q(a,g={syncUrl:!0}){var N;if(J(a),C(void 0),P("feedback"),i&&g.syncUrl!==!1){const te=new URL(window.location.href);te.searchParams.set("reviewLensFeedback",a.id),window.history.replaceState({},"",te)}const o=D(a.selector);if(!o){y(void 0);return}(N=o.scrollIntoView)==null||N.call(o,{behavior:"smooth",block:"center",inline:"center"}),window.requestAnimationFrame(()=>{y(W(o))})}function ze(a){if(F.length===0)return;const g=S?F.findIndex(N=>N.id===S.id):-1,o=g<0?a>0?0:F.length-1:(g+a+F.length)%F.length;Q(F[o])}async function He(){if(!m||!$.trim()||!u||!T)return;let a=await v({projectKey:b.projectKey,contentId:b.contentId,normalizedPath:w,originalUrl:b.currentUrl??window.location.href,selector:m.selector,selectorStrategy:m.selectorStrategy,elementFingerprint:m.fingerprint,createdCssSnapshot:m.cssSnapshot,comment:$.trim(),status:"open",severity:xe,category:Ae,assigneeEmail:Le.trim()||void 0,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight,viewportPreset:Me,screenshotUrl:void 0,screenshotThumbnailUrl:void 0,authorEmail:u.email});if(b.captureScreenshot)try{const g=await b.captureScreenshot(m),o=await p(a.id,{type:"screenshot",data:g,createdBy:u.email});a=await k(a.id,{attachments:[o],screenshotUrl:o.url,screenshotThumbnailUrl:o.thumbnailUrl})}catch{}z(""),Fe(""),C(void 0),y(void 0),P("feedback"),J(a)}async function jt(a,g){const o=new Date().toISOString(),N=g==="resolved"?{status:g,resolvedAt:o,resolvedBy:u==null?void 0:u.email}:{status:g},te=await k(a.id,N);J(te)}async function je(a){const g=D(a.selector);if(!g||!u)return;const o=W(g),N=await k(a.id,{status:"fixed",fixedCssSnapshot:o.cssSnapshot,fixedAt:new Date().toISOString(),fixedBy:u.email});J(N)}async function Ot(a){if(!ie.trim()||!u||!We)return;const g=await A({feedbackId:a.id,body:ie.trim(),authorEmail:u.email});Ue(o=>({...o,[a.id]:[...o[a.id]??[],g]})),oe("")}return r.jsxs("div",{className:"review-lens-root","data-review-lens-ui":!0,children:[I&&U?r.jsx(ft,{target:U,locked:!!m}):null,I&&m&&B&&Bt?r.jsx(bt,{from:m,to:B}):null,I?r.jsxs(r.Fragment,{children:[r.jsx(vt,{feedback:F,selectedFeedback:S,onSelect:Q}),r.jsx(mt,{feedback:F,selectedFeedback:S,onSelect:Q})]}):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",{children:[r.jsx("p",{className:"review-lens-kicker",children:"Review Lens"}),r.jsx("h2",{children:M==="summary"?"Summary":M==="feedback"?"Feedback":m?"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":M==="review",onClick:()=>P("review"),children:"Review"}),r.jsxs("button",{type:"button",role:"tab","aria-selected":M==="feedback",onClick:()=>P("feedback"),children:["Feedback ",r.jsx("span",{children:F.length})]}),r.jsx("button",{type:"button",role:"tab","aria-selected":M==="summary",onClick:()=>P("summary"),children:"Summary"})]}),M==="review"?r.jsxs("div",{className:"review-lens-review-pane",role:"tabpanel",children:[r.jsxs("div",{className:"review-lens-inspection",children:[I?null:r.jsx("p",{children:"Authenticate with Google to inspect this page."}),I&&U?r.jsxs(r.Fragment,{children:[r.jsx(yt,{target:U}),r.jsx(ke,{title:"Accessibility",items:St(U)}),r.jsx(ke,{title:"Design tokens",items:kt(U.cssSnapshot,b.designTokens)})]}):null,I&&!U?r.jsx("p",{children:"Move over the app to inspect."}):null]}),Wt?r.jsx("div",{className:"review-lens-composer-panel",children:r.jsxs("form",{className:"review-lens-feedback-form",onSubmit:a=>{a.preventDefault(),He()},children:[r.jsx("label",{htmlFor:"review-lens-comment",children:"New feedback"}),r.jsx("textarea",{ref:ee,id:"review-lens-comment",value:$,disabled:!T,onChange:a=>z(a.target.value),onKeyDown:a=>{a.key==="Enter"&&a.metaKey&&(a.preventDefault(),He())},placeholder:T?"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:xe,onChange:a=>Mt(a.target.value),disabled:!T,children:ye.map(a=>r.jsx("option",{value:a,children:H[a]},a))})]}),r.jsxs("label",{children:["Type",r.jsx("select",{value:Ae,onChange:a=>It(a.target.value),disabled:!T,children:Se.map(a=>r.jsx("option",{value:a,children:j[a]},a))})]}),r.jsxs("label",{children:["Assignee",r.jsx("input",{value:Le,onChange:a=>Fe(a.target.value),disabled:!T,placeholder:"optional@email.com"})]}),r.jsxs("label",{children:["Viewport",r.jsx("select",{value:Me,onChange:a=>Tt(a.target.value),disabled:!T,children:d.map(a=>r.jsx("option",{value:a.value,children:a.label},a.value))})]})]}),T?r.jsxs("p",{className:"review-lens-feedback-form__hint",children:["Press ",r.jsx("kbd",{children:"Command"})," + ",r.jsx("kbd",{children:"Enter"})," to submit.",Dt?" Screenshot capture runs after save.":""]}):null,r.jsx("div",{className:"review-lens-actions",children:r.jsx("button",{type:"submit",disabled:!$.trim()||!T,children:"Save feedback"})})]})}):null]}):null,M==="feedback"?r.jsxs("div",{className:"review-lens-comments",children:[r.jsx(ht,{open:$t,activeCount:Ht,statusFilter:q,severityFilter:V,categoryFilter:G,assigneeFilter:Y,viewportFilter:X,assignees:zt,responsivePresets:d,onStatusChange:Te,onSeverityChange:Be,onCategoryChange:$e,onAssigneeChange:Pe,onViewportChange:_e,onToggle:()=>Pt(a=>!a),onClear:()=>{Te("all"),Be("all"),$e("all"),Pe("all"),_e("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:F.length})]}),r.jsxs("div",{className:"review-lens-comments__list",children:[F.length===0?r.jsx("p",{children:"No feedback for this view."}):null,F.map(a=>r.jsx(pt,{item:a,selected:(S==null?void 0:S.id)===a.id,onSelect:Q},a.id))]})]}),S?r.jsxs("div",{className:"review-lens-selected-panel",children:[r.jsx("div",{className:"review-lens-selected-panel__label",children:"Selected feedback"}),r.jsx(ut,{item:S,messages:_t[S.id]??[],messageDraft:ie,canReply:We,canUpdate:De,canAssign:Ut,onMessageDraftChange:oe,onSubmitMessage:()=>void Ot(S),onStatusChange:a=>void jt(S,a),onAssigneeChange:a=>void k(S.id,{assigneeEmail:a.trim()||void 0}).then(J),onMarkFixed:()=>void je(S)},S.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,M==="summary"?r.jsx(gt,{feedback:c}):null]})]})]})}function ht({open:e,activeCount:t,statusFilter:n,severityFilter:s,categoryFilter:i,assigneeFilter:d,viewportFilter:f,assignees:b,responsivePresets:u,onStatusChange:c,onSeverityChange:w,onCategoryChange:h,onAssigneeChange:v,onViewportChange:k,onToggle:E,onClear:A}){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:A,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:p=>c(p.target.value),children:[r.jsx("option",{value:"all",children:"All statuses"}),me.map(p=>r.jsx("option",{value:p,children:Z[p]},p))]})]}),r.jsxs("label",{children:["Priority",r.jsxs("select",{"aria-label":"Filter severity",value:s,onChange:p=>w(p.target.value),children:[r.jsx("option",{value:"all",children:"All priorities"}),ye.map(p=>r.jsx("option",{value:p,children:H[p]},p))]})]}),r.jsxs("label",{children:["Type",r.jsxs("select",{"aria-label":"Filter type",value:i,onChange:p=>h(p.target.value),children:[r.jsx("option",{value:"all",children:"All types"}),Se.map(p=>r.jsx("option",{value:p,children:j[p]},p))]})]}),r.jsxs("label",{children:["Assignee",r.jsxs("select",{"aria-label":"Filter assignee",value:d,onChange:p=>v(p.target.value),children:[r.jsx("option",{value:"all",children:"All assignees"}),b.map(p=>r.jsx("option",{value:p,children:p},p))]})]}),r.jsxs("label",{children:["Viewport",r.jsxs("select",{"aria-label":"Filter viewport",value:f,onChange:p=>k(p.target.value),children:[r.jsx("option",{value:"all",children:"All viewports"}),u.map(p=>r.jsx("option",{value:p.value,children:p.label},p.value))]})]})]}):null]})}function pt({item:e,selected:t,onSelect:n}){const s=Ce(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:i=>{(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),n(e))},children:[r.jsxs("div",{className:"review-lens-comment__header",children:[r.jsx("span",{children:Z[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:j[e.category]}),r.jsx("span",{children:e.viewportPreset}),r.jsx("span",{children:s.label})]})]})}function ut({item:e,messages:t,messageDraft:n,canReply:s,canUpdate:i,canAssign:d,onMessageDraftChange:f,onSubmitMessage:b,onStatusChange:u,onAssigneeChange:c,onMarkFixed:w}){const h=Ce(e);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:[j[e.category]," feedback"]}),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:h.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:!i,onChange:v=>u(v.target.value),children:me.map(v=>r.jsx("option",{value:v,children:Z[v]},v))})]}),r.jsxs("label",{children:["Assignee",r.jsx("input",{defaultValue:e.assigneeEmail??"",disabled:!d,onBlur:v=>c(v.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:!i,onClick:w,children:"Mark fixed"}),r.jsx("button",{type:"button",className:"review-lens-button-primary",disabled:!i,onClick:()=>u("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(v=>r.jsxs("div",{className:"review-lens-thread__message",children:[r.jsx("p",{children:v.body}),r.jsx("span",{children:v.authorEmail})]},v.id)),r.jsx("textarea",{"aria-label":"Reply",value:n,disabled:!s,onChange:v=>f(v.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:b,children:"Reply"})})]})]})}function gt({feedback:e}){return r.jsxs("div",{className:"review-lens-summary",role:"tabpanel",children:[r.jsx(O,{title:"Status",values:K(e,t=>Z[t.status])}),r.jsx(O,{title:"Severity",values:K(e,t=>H[t.severity])}),r.jsx(O,{title:"Type",values:K(e,t=>j[t.category])}),r.jsx(O,{title:"Assignee",values:K(e,t=>t.assigneeEmail??"Unassigned")}),r.jsx(O,{title:"Viewport",values:K(e,t=>t.viewportPreset)})]})}function O({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 ft({target:e,locked:t}){const n=Ft(e),s=Nt(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=Et(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 vt({feedback:e,selectedFeedback:t,onSelect:n}){return r.jsx(r.Fragment,{children:e.map(s=>r.jsx(wt,{feedback:s,selected:(t==null?void 0:t.id)===s.id,onSelect:n},s.id))})}function wt({feedback:e,selected:t,onSelect:n}){const s=l.useRef(null);return l.useLayoutEffect(()=>{let i=0;const d=()=>{i=0;const b=s.current,u=D(e.selector),c=u==null?void 0:u.getBoundingClientRect();!b||!c||(b.style.top=`${c.top}px`,b.style.left=`${c.right}px`,b.hidden=c.bottom<0||c.top>window.innerHeight)},f=()=>{i||(i=window.requestAnimationFrame(d))};return d(),window.addEventListener("scroll",f,!0),window.addEventListener("resize",f),()=>{i&&window.cancelAnimationFrame(i),window.removeEventListener("scroll",f,!0),window.removeEventListener("resize",f)}},[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 mt({feedback:e,selectedFeedback:t,onSelect:n}){const s=e.map(i=>{const d=D(i.selector),f=d==null?void 0:d.getBoundingClientRect(),b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight,window.innerHeight);return!f||b<=0?null:{item:i,top:Math.min(100,Math.max(0,(f.top+window.scrollY)/b*100))}}).filter(i=>i!==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(i=>r.jsx("button",{type:"button",className:(t==null?void 0:t.id)===i.item.id?"review-lens-minimap__point review-lens-minimap__point--selected":"review-lens-minimap__point",style:{top:`${i.top}%`},onClick:()=>n(i.item),"aria-label":`Jump to feedback from ${i.item.authorEmail}`},i.item.id))})}function yt({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 ke({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 Ce(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 St(e){var u;const t=D(e.selector);if(!t)return["Selected element is no longer available."];const n=[],s=t.tagName.toLowerCase(),i=t.getAttribute("role"),d=["button","a","input","select","textarea"].includes(s)||i==="button"||i==="link",f=t.getAttribute("aria-label")||t.getAttribute("title")||((u=t.textContent)==null?void 0:u.trim());d&&!f&&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 b=/^h[1-6]$/.test(s)?Number(s.slice(1)):0;return b>1&&!document.querySelector(`h${b-1}`)&&n.push("Heading may skip the previous level."),At(e.cssSnapshot.color,e.cssSnapshot.backgroundColor)&&n.push("Text contrast may be low."),n}function kt(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,i={}){!n||n.length===0||!t||Ct(t,n,i)||s.push(`${e} ${t} is outside configured tokens.`)}function Ct(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(i=>t.includes(i))}function Nt(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 Et(e,t){const n=[],s=(Math.max(e.left,t.left)+Math.min(e.right,t.right))/2,i=(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,f=e.right<=t.left?t.left:e.left;n.push({key:"horizontal",axis:"horizontal",top:Ne(i,0,window.innerHeight),left:d,width:Math.max(f-d,1),height:1,label:`${Math.round(f-d)}px`})}if(e.bottom<=t.top||t.bottom<=e.top){const d=e.bottom<=t.top?e.bottom:t.bottom,f=e.bottom<=t.top?t.top:e.top;n.push({key:"vertical",axis:"vertical",top:d,left:Ne(s,0,window.innerWidth),width:1,height:Math.max(f-d,1),label:`${Math.round(f-d)}px`})}return n}function Ne(e,t,n){return Math.min(Math.max(e,t),n)}function K(e,t){const n=new Map;for(const s of e){const i=t(s);n.set(i,(n.get(i)??0)+1)}return Array.from(n.entries()).sort((s,i)=>i[1]-s[1]||s[0].localeCompare(i[0]))}function xt(e){return e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement||e instanceof HTMLElement&&e.isContentEditable}function At(e,t){const n=Ee(e),s=Ee(t);return!n||!s||s.alpha===0?!1:Lt(n,s)<4.5}function Ee(e){const t=e.match(/rgba?\(([^)]+)\)/);if(!t)return null;const[n,s,i,d="1"]=t[1].split(",").map(f=>f.trim());return{red:Number(n),green:Number(s),blue:Number(i),alpha:Number(d)}}function Lt(e,t){const n=Math.max(R(e),R(t)),s=Math.min(R(e),R(t));return(n+.05)/(s+.05)}function R(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 Ft(e){const t={top:L(e.cssSnapshot.marginTop),right:L(e.cssSnapshot.marginRight),bottom:L(e.cssSnapshot.marginBottom),left:L(e.cssSnapshot.marginLeft)},n={top:L(e.cssSnapshot.borderTopWidth),right:L(e.cssSnapshot.borderRightWidth),bottom:L(e.cssSnapshot.borderBottomWidth),left:L(e.cssSnapshot.borderLeftWidth)},s={top:L(e.cssSnapshot.paddingTop),right:L(e.cssSnapshot.paddingRight),bottom:L(e.cssSnapshot.paddingBottom),left:L(e.cssSnapshot.paddingLeft)},i={top:e.rect.top,left:e.rect.left,width:Math.max(e.rect.width,0),height:Math.max(e.rect.height,0)},d={top:i.top-t.top,left:i.left-t.left,width:i.width+t.left+t.right,height:i.height+t.top+t.bottom},f={top:i.top+n.top,left:i.left+n.left,width:Math.max(i.width-n.left-n.right,0),height:Math.max(i.height-n.top-n.bottom,0)},b={top:f.top+s.top,left:f.left+s.left,width:Math.max(f.width-s.left-s.right,0),height:Math.max(f.height-s.top-s.bottom,0)};return{margin:d,border:i,padding:f,content:b}}function L(e){const t=Number.parseFloat(e);return Number.isFinite(t)?t:0}x.ReviewLensOverlay=ct,x.ReviewLensProvider=rt,x.buildElementTarget=W,x.createGoogleSheetsAdapter=de,x.normalizeReviewUrl=fe,x.useReviewLens=ve,Object.defineProperty(x,Symbol.toStringTag,{value:"Module"})}));
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"})}));
@@ -7,6 +7,7 @@ type GoogleSheetsAdapterConfig = {
7
7
  messagesSheetName?: string;
8
8
  usersSheetName?: string;
9
9
  projectsSheetName?: string;
10
+ enableEmailNotifications?: boolean;
10
11
  };
11
12
  type TokenClient = {
12
13
  requestAccessToken(options?: {
package/dist/styles.css CHANGED
@@ -1 +1 @@
1
- .review-lens-root{color:#171717;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;top:0;right:0;bottom:0;left:0;pointer-events:none;position:fixed;z-index:2147483647}.review-lens-highlight{background:#f9731633;box-shadow:0 0 0 9999px #0f172a14;box-sizing:border-box;pointer-events:none;position:fixed}.review-lens-highlight--locked{box-shadow:0 0 0 9999px #0f172a1f}.review-lens-highlight__border,.review-lens-highlight__padding,.review-lens-highlight__content{box-sizing:border-box;position:absolute}.review-lens-highlight__border{border:2px solid #facc15;background:#facc1538}.review-lens-highlight__padding{border:2px solid #22c55e;background:#22c55e38}.review-lens-highlight__content{border:2px solid #2563eb;background:#2563eb29}.review-lens-highlight--locked .review-lens-highlight__content{border-color:#f97316}.review-lens-highlight__label{background:#171717;border-radius:4px;color:#fff;display:grid;gap:3px;font-size:11px;left:0;line-height:1.1;max-width:240px;padding:6px 7px;position:absolute;top:-38px;white-space:nowrap}.review-lens-highlight__label strong{font-size:11px;font-weight:800;overflow:hidden;text-overflow:ellipsis}.review-lens-highlight__label span{color:#d4d4d4;font-size:10px;font-weight:700}.review-lens-distance{background:#2563eb;pointer-events:none;position:fixed;z-index:1}.review-lens-distance:before,.review-lens-distance:after{background:#2563eb;content:"";position:absolute}.review-lens-distance--horizontal:before,.review-lens-distance--horizontal:after{height:9px;top:-4px;width:1px}.review-lens-distance--horizontal:before{left:0}.review-lens-distance--horizontal:after{right:0}.review-lens-distance--vertical:before,.review-lens-distance--vertical:after{height:1px;left:-4px;width:9px}.review-lens-distance--vertical:before{top:0}.review-lens-distance--vertical:after{bottom:0}.review-lens-distance span{background:#2563eb;border-radius:999px;color:#fff;font-size:10px;font-weight:800;left:50%;line-height:1;padding:4px 6px;position:absolute;top:50%;transform:translate(-50%,-50%);white-space:nowrap}.review-lens-panel{background:#fafafa;border:1px solid #d4d4d4;border-radius:8px;box-shadow:0 24px 70px #0f172a38;box-sizing:border-box;display:flex;flex-direction:column;height:min(680px,calc(100vh - 32px));min-height:min(520px,calc(100vh - 32px));overflow:hidden;padding:16px;pointer-events:auto;position:fixed;width:min(380px,calc(100vw - 32px))}.review-lens-panel--top-left{left:16px;top:16px}.review-lens-panel--top-right{right:16px;top:16px}.review-lens-panel--bottom-left{bottom:16px;left:16px}.review-lens-panel--bottom-right{bottom:16px;right:16px}.review-lens-panel__header{flex:0 0 auto;align-items:flex-start;display:flex;gap:16px;justify-content:space-between;margin-bottom:12px}.review-lens-panel__body{display:flex;flex:1 1 auto;flex-direction:column;gap:16px;min-height:0;overflow:hidden}.review-lens-panel h2,.review-lens-panel h3,.review-lens-panel p{margin:0}.review-lens-panel h2{font-size:18px;line-height:1.25}.review-lens-panel h3{font-size:14px;margin-top:18px}.review-lens-kicker{color:#525252;font-size:11px;font-weight:700;letter-spacing:0;text-transform:uppercase}.review-lens-panel button{background:#171717;border:1px solid #171717;border-radius:6px;color:#fff;cursor:pointer;font:inherit;font-size:13px;min-height:32px;padding:6px 10px;transition:transform .14s cubic-bezier(.23,1,.32,1)}.review-lens-panel button:active{transform:scale(.97)}.review-lens-panel button:disabled{cursor:not-allowed;opacity:.45}.review-lens-mode-switch{background:#eee;border:1px solid #d4d4d4;border-radius:7px;display:grid;flex:0 0 auto;gap:2px;grid-template-columns:repeat(3,minmax(0,1fr));padding:2px}.review-lens-mode-switch button{background:transparent;border:0;color:#525252;min-height:30px}.review-lens-mode-switch button[aria-selected=true]{background:#fff;box-shadow:0 1px 4px #0f172a1f;color:#171717}.review-lens-mode-switch span{color:#737373;font-size:11px}.review-lens-metrics{border:1px solid #e5e5e5;border-radius:8px;display:grid;gap:0;margin:0;overflow:hidden}.review-lens-metrics div{display:grid;grid-template-columns:96px minmax(0,1fr)}.review-lens-metrics dt,.review-lens-metrics dd{border-bottom:1px solid #e5e5e5;font-size:11px;margin:0;min-width:0;padding:6px 8px}.review-lens-metrics dt{background:#f5f5f5;color:#525252;font-weight:700}.review-lens-metrics dd{overflow-wrap:anywhere}.review-lens-inspection{display:grid;flex:0 0 auto;gap:16px}.review-lens-review-pane{display:flex;flex:1 1 auto;flex-direction:column;gap:16px;min-height:0;overflow:auto;padding-right:4px}.review-lens-feedback-form{display:grid;flex:1 1 auto;gap:8px;grid-template-rows:auto minmax(96px,auto) auto auto auto;margin-top:0;min-height:0}.review-lens-composer-panel{background:linear-gradient(#fafafa,#fafafa00) top / 100% 12px no-repeat,#fff;border:1px solid #d4d4d4;border-radius:8px;box-shadow:inset 0 8px 12px #0f172a0a;display:block;flex:0 0 auto;max-height:min(360px,44vh);min-height:0;overflow:auto;padding:10px;position:relative}.review-lens-composer-panel:before{background:#d4d4d4;border-radius:999px;content:"";display:block;height:3px;margin:0 auto 8px;width:44px}.review-lens-feedback-form label,.review-lens-form-grid label{display:grid;gap:4px;font-size:13px;font-weight:700}.review-lens-feedback-form textarea,.review-lens-detail textarea,.review-lens-panel input,.review-lens-panel select{border:1px solid #d4d4d4;border-radius:8px;box-sizing:border-box;font:inherit;padding:10px;width:100%}.review-lens-feedback-form textarea,.review-lens-detail textarea{flex:1 1 auto;min-height:96px;resize:vertical}.review-lens-panel input,.review-lens-panel select{background:#fff;color:#171717;font-size:12px;min-height:34px;padding:6px 8px}.review-lens-form-grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}.review-lens-feedback-form__hint{color:#737373;font-size:12px;line-height:1.4}.review-lens-feedback-form__hint kbd{background:#f5f5f5;border:1px solid #d4d4d4;border-radius:4px;color:#404040;font-family:inherit;font-size:11px;padding:1px 4px}.review-lens-actions{display:flex;gap:8px;justify-content:flex-end}.review-lens-comments{display:grid;flex:1 1 auto;gap:10px;grid-template-rows:auto minmax(108px,1.35fr) minmax(200px,.9fr);min-height:0;overflow:hidden;padding-right:4px}.review-lens-filter-shell{display:grid;gap:8px}.review-lens-filter-bar{align-items:center;display:flex;gap:8px;justify-content:space-between}.review-lens-filter-bar button{align-items:center;background:#fff;border-color:#d4d4d4;color:#404040;display:inline-flex;gap:6px;min-height:30px;padding:5px 9px}.review-lens-filter-bar button:first-child{font-weight:700}.review-lens-filter-bar button[aria-expanded=true]{background:#171717;border-color:#171717;color:#fff}.review-lens-filter-bar span{align-items:center;background:#f97316;border-radius:999px;color:#fff;display:inline-flex;font-size:10px;height:17px;justify-content:center;min-width:17px;padding:0 5px}.review-lens-filters{background:#f5f5f5;border:1px solid #e5e5e5;border-radius:8px;display:grid;flex:0 0 auto;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));padding:8px}.review-lens-filters label{color:#525252;display:grid;font-size:10px;font-weight:800;gap:4px;letter-spacing:0;text-transform:uppercase}.review-lens-filters label:last-child{grid-column:1 / -1}.review-lens-list-panel{background:#fff;border:1px solid #d4d4d4;border-radius:10px;display:grid;gap:8px;grid-template-rows:auto minmax(0,1fr);min-height:0;overflow:hidden;padding:10px}.review-lens-comments__header{align-items:center;color:#171717;display:flex;gap:8px;justify-content:space-between}.review-lens-comments__header h3{color:#525252;font-size:11px;font-weight:800;letter-spacing:0;margin:0;text-transform:uppercase}.review-lens-comments__header span{align-items:center;background:#e5e5e5;border-radius:999px;color:#404040;display:inline-flex;font-size:11px;justify-content:center;min-width:22px;padding:2px 7px}.review-lens-comments__list{align-content:start;display:grid;gap:8px;min-height:0;overflow:auto;padding-right:2px}.review-lens-selected-panel{background:#171717;border-radius:10px;box-shadow:0 -10px 28px #0f172a2e;display:grid;gap:0;grid-template-rows:auto minmax(0,1fr);min-height:0;overflow:hidden;padding:4px}.review-lens-selected-panel__label{color:#d4d4d4;font-size:10px;font-weight:800;letter-spacing:0;padding:7px 8px 8px;text-transform:uppercase}.review-lens-selected-panel--empty{color:#d4d4d4;font-size:12px;line-height:1.4;padding:4px 12px 12px}.review-lens-selected-panel--empty p{color:#f5f5f5}.review-lens-detail{background:linear-gradient(180deg,#fff,#f8fafc);border:0;border-radius:8px;box-shadow:none;box-sizing:border-box;display:grid;gap:10px;min-height:0;overflow:auto;padding:12px}.review-lens-detail__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.review-lens-detail__header h3{color:#171717;font-size:13px;line-height:1.2;margin:0;text-transform:capitalize}.review-lens-detail__header strong,.review-lens-comment__header strong{background:#fee2e2;border:1px solid #fecaca;border-radius:999px;color:#991b1b;flex:0 0 auto;font-size:10px;line-height:1;padding:5px 7px;text-transform:uppercase}.review-lens-detail blockquote{background:#f8fafc;border:1px solid #dbeafe;border-left:3px solid #2563eb;border-radius:6px;color:#171717;font-size:15px;font-weight:700;line-height:1.35;margin:0;padding:9px 10px}.review-lens-detail-meta{background:#fff;border:1px solid #e5e5e5;border-radius:6px;display:grid;gap:0;margin:0;overflow:hidden}.review-lens-detail-meta div{display:grid;gap:2px;grid-template-columns:72px minmax(0,1fr);padding:6px 8px}.review-lens-detail-meta div+div{border-top:1px solid #eeeeee}.review-lens-detail-meta dt,.review-lens-detail-meta dd{font-size:11px;line-height:1.25;margin:0;min-width:0}.review-lens-detail-meta dt{color:#737373;font-weight:800;text-transform:uppercase}.review-lens-detail-meta dd{color:#262626;overflow-wrap:anywhere}.review-lens-detail a{color:#2563eb;font-weight:700}.review-lens-comment{background:#fff;border:1px solid #e5e5e5;border-radius:8px;box-shadow:0 1px 2px #0f172a0a;cursor:pointer;display:grid;gap:10px;padding:12px;position:relative;text-align:left}.review-lens-comment:before{background:#737373;border-radius:999px;bottom:12px;content:"";left:8px;position:absolute;top:12px;width:3px}.review-lens-comment--high:before{background:#dc2626}.review-lens-comment--medium:before{background:#f97316}.review-lens-comment--low:before{background:#16a34a}.review-lens-comment:focus-visible{outline:2px solid #2563eb;outline-offset:2px}.review-lens-comment--selected{background:#eff6ff;border-color:#2563eb;box-shadow:0 8px 18px #2563eb1f}.review-lens-comment__header{align-items:center;display:flex;gap:8px;justify-content:space-between;padding-left:8px}.review-lens-comment__header span{color:#525252;font-size:10px;font-weight:800;letter-spacing:0;text-transform:uppercase}.review-lens-comment__content{display:grid;gap:6px;padding-left:8px}.review-lens-comment__content p{color:#171717;font-size:14px;line-height:1.35}.review-lens-comment__content span{color:#525252;font-size:11px;line-height:1}.review-lens-tags{display:flex;flex-wrap:wrap;gap:5px;padding-left:8px}.review-lens-tags span{background:#f5f5f5;border:1px solid #e5e5e5;border-radius:999px;color:#404040;font-size:10px;font-weight:700;line-height:1;padding:4px 6px}.review-lens-thread{border-top:1px solid #e5e5e5;display:grid;gap:6px;padding-top:10px}.review-lens-thread__header{align-items:center;display:flex;justify-content:space-between}.review-lens-thread h3{margin:0}.review-lens-thread__header span{color:#737373;font-size:11px;font-weight:800}.review-lens-detail .review-lens-thread textarea{min-height:48px}.review-lens-status-actions{align-items:center;display:grid;gap:8px;grid-template-columns:minmax(0,1fr) auto}.review-lens-status-actions button{min-height:30px}.review-lens-status-actions .review-lens-button-secondary{background:#fff;border-color:#d4d4d4;color:#404040}.review-lens-status-actions .review-lens-button-primary{background:#171717;border-color:#171717;color:#fff}.review-lens-thread__message{background:#f5f5f5;border-radius:6px;display:grid;gap:4px;padding:8px}.review-lens-thread__message p{font-size:12px;line-height:1.35}.review-lens-thread__message span{color:#737373;font-size:10px}.review-lens-comment__actions{display:flex;justify-content:flex-end}.review-lens-comment__actions button{background:transparent;border-color:#d4d4d4;color:#404040;min-height:28px;padding:4px 10px}.review-lens-comment__actions button:hover{background:#171717;border-color:#171717;color:#fff}.review-lens-marker{background:#f97316;border:2px solid #ffffff;border-radius:999px;box-shadow:0 8px 20px #0f172a3d;cursor:pointer;height:18px;pointer-events:auto;position:fixed;transform:translate(-50%,-50%);width:18px}.review-lens-marker--selected{background:#2563eb}.review-lens-minimap{background:#1717171f;border-radius:999px;bottom:24px;pointer-events:auto;position:fixed;right:8px;top:24px;width:10px}.review-lens-minimap__point{background:#f97316;border:2px solid #ffffff;border-radius:999px;box-shadow:0 2px 8px #0f172a38;height:14px;left:50%;min-height:0;padding:0;position:absolute;transform:translate(-50%,-50%);width:14px}.review-lens-minimap__point--selected{background:#2563eb}.review-lens-insights,.review-lens-summary{border:1px solid #e5e5e5;border-radius:8px;display:grid;gap:8px;padding:10px}.review-lens-insights h3,.review-lens-summary h3{margin:0}.review-lens-insights p,.review-lens-insights li,.review-lens-summary dt,.review-lens-summary dd{color:#404040;font-size:12px;line-height:1.35}.review-lens-insights ul{display:grid;gap:6px;margin:0;padding-left:18px}.review-lens-summary{align-content:start;flex:1 1 auto;min-height:0;overflow:auto;padding-right:4px}.review-lens-summary section{border-bottom:1px solid #e5e5e5;display:grid;gap:8px;padding-bottom:10px}.review-lens-summary section:last-child{border-bottom:0;padding-bottom:0}.review-lens-summary dl,.review-lens-summary div{display:grid;gap:6px;margin:0}.review-lens-summary div{grid-template-columns:minmax(0,1fr) auto}.review-lens-summary dd{font-weight:700;margin:0}
1
+ .review-lens-root{color:#171717;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;top:0;right:0;bottom:0;left:0;pointer-events:none;position:fixed;z-index:2147483647}.review-lens-highlight{background:#f9731633;box-shadow:0 0 0 9999px #0f172a14;box-sizing:border-box;pointer-events:none;position:fixed}.review-lens-highlight--locked{box-shadow:0 0 0 9999px #0f172a1f}.review-lens-highlight__border,.review-lens-highlight__padding,.review-lens-highlight__content{box-sizing:border-box;position:absolute}.review-lens-highlight__border{border:2px solid #facc15;background:#facc1538}.review-lens-highlight__padding{border:2px solid #22c55e;background:#22c55e38}.review-lens-highlight__content{border:2px solid #2563eb;background:#2563eb29}.review-lens-highlight--locked .review-lens-highlight__content{border-color:#f97316}.review-lens-highlight__label{background:#171717;border-radius:4px;color:#fff;display:grid;gap:3px;font-size:11px;left:0;line-height:1.1;max-width:240px;padding:6px 7px;position:absolute;top:-38px;white-space:nowrap}.review-lens-highlight__label strong{font-size:11px;font-weight:800;overflow:hidden;text-overflow:ellipsis}.review-lens-highlight__label span{color:#d4d4d4;font-size:10px;font-weight:700}.review-lens-distance{background:#2563eb;pointer-events:none;position:fixed;z-index:1}.review-lens-distance:before,.review-lens-distance:after{background:#2563eb;content:"";position:absolute}.review-lens-distance--horizontal:before,.review-lens-distance--horizontal:after{height:9px;top:-4px;width:1px}.review-lens-distance--horizontal:before{left:0}.review-lens-distance--horizontal:after{right:0}.review-lens-distance--vertical:before,.review-lens-distance--vertical:after{height:1px;left:-4px;width:9px}.review-lens-distance--vertical:before{top:0}.review-lens-distance--vertical:after{bottom:0}.review-lens-distance span{background:#2563eb;border-radius:999px;color:#fff;font-size:10px;font-weight:800;left:50%;line-height:1;padding:4px 6px;position:absolute;top:50%;transform:translate(-50%,-50%);white-space:nowrap}.review-lens-panel{background:#fafafa;border:1px solid #d4d4d4;border-radius:8px;box-shadow:0 24px 70px #0f172a38;box-sizing:border-box;display:flex;flex-direction:column;height:min(680px,calc(100vh - 32px));min-height:min(520px,calc(100vh - 32px));overflow:hidden;padding:16px;pointer-events:auto;position:fixed;width:min(380px,calc(100vw - 32px))}.review-lens-panel--top-left{left:16px;top:16px}.review-lens-panel--top-right{right:16px;top:16px}.review-lens-panel--bottom-left{bottom:16px;left:16px}.review-lens-panel--bottom-right{bottom:16px;right:16px}.review-lens-panel__header{flex:0 0 auto;align-items:flex-start;display:flex;gap:16px;justify-content:space-between;margin-bottom:12px}.review-lens-panel__body{display:flex;flex:1 1 auto;flex-direction:column;gap:16px;min-height:0;overflow:hidden}.review-lens-brand{align-items:center;display:flex;gap:10px;min-width:0}.review-lens-brand__mark{flex:0 0 auto;height:36px;width:36px}.review-lens-panel h2,.review-lens-panel h3,.review-lens-panel p{margin:0}.review-lens-panel h2{font-size:18px;line-height:1.25}.review-lens-panel h3{font-size:14px;margin-top:18px}.review-lens-kicker{color:#525252;font-size:11px;font-weight:700;letter-spacing:0;text-transform:uppercase}.review-lens-panel button{background:#171717;border:1px solid #171717;border-radius:6px;color:#fff;cursor:pointer;font:inherit;font-size:13px;min-height:32px;padding:6px 10px;transition:transform .14s cubic-bezier(.23,1,.32,1)}.review-lens-panel button:active{transform:scale(.97)}.review-lens-panel button:disabled{cursor:not-allowed;opacity:.45}.review-lens-mode-switch{background:#eee;border:1px solid #d4d4d4;border-radius:7px;display:grid;flex:0 0 auto;gap:2px;grid-template-columns:repeat(3,minmax(0,1fr));padding:2px}.review-lens-mode-switch button{background:transparent;border:0;color:#525252;min-height:30px}.review-lens-mode-switch button[aria-selected=true]{background:#fff;box-shadow:0 1px 4px #0f172a1f;color:#171717}.review-lens-mode-switch span{color:#737373;font-size:11px}.review-lens-metrics{border:1px solid #e5e5e5;border-radius:8px;display:grid;gap:0;margin:0;overflow:hidden}.review-lens-metrics div{display:grid;grid-template-columns:96px minmax(0,1fr)}.review-lens-metrics dt,.review-lens-metrics dd{border-bottom:1px solid #e5e5e5;font-size:11px;margin:0;min-width:0;padding:6px 8px}.review-lens-metrics dt{background:#f5f5f5;color:#525252;font-weight:700}.review-lens-metrics dd{overflow-wrap:anywhere}.review-lens-inspection{display:grid;flex:0 0 auto;gap:16px}.review-lens-review-pane{display:flex;flex:1 1 auto;flex-direction:column;gap:16px;min-height:0;overflow:auto;padding-right:4px}.review-lens-feedback-form{display:grid;flex:1 1 auto;gap:8px;grid-template-rows:auto minmax(96px,auto) auto auto auto;margin-top:0;min-height:0}.review-lens-composer-panel{background:linear-gradient(#fafafa,#fafafa00) top / 100% 12px no-repeat,#fff;border:1px solid #d4d4d4;border-radius:8px;box-shadow:inset 0 8px 12px #0f172a0a;display:block;flex:0 0 auto;max-height:min(360px,44vh);min-height:0;overflow:auto;padding:10px;position:relative}.review-lens-composer-panel:before{background:#d4d4d4;border-radius:999px;content:"";display:block;height:3px;margin:0 auto 8px;width:44px}.review-lens-feedback-form label,.review-lens-form-grid label{display:grid;gap:4px;font-size:13px;font-weight:700}.review-lens-feedback-form textarea,.review-lens-detail textarea,.review-lens-panel input,.review-lens-panel select{border:1px solid #d4d4d4;border-radius:8px;box-sizing:border-box;font:inherit;padding:10px;width:100%}.review-lens-feedback-form textarea,.review-lens-detail textarea{flex:1 1 auto;min-height:96px;resize:vertical}.review-lens-panel input,.review-lens-panel select{background:#fff;color:#171717;font-size:12px;min-height:34px;padding:6px 8px}.review-lens-form-grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}.review-lens-feedback-form__hint{color:#737373;font-size:12px;line-height:1.4}.review-lens-feedback-form__hint kbd{background:#f5f5f5;border:1px solid #d4d4d4;border-radius:4px;color:#404040;font-family:inherit;font-size:11px;padding:1px 4px}.review-lens-actions{display:flex;gap:8px;justify-content:flex-end}.review-lens-comments{display:grid;flex:1 1 auto;gap:10px;grid-template-rows:auto minmax(108px,1.35fr) minmax(200px,.9fr);min-height:0;overflow:hidden;padding-right:4px}.review-lens-filter-shell{display:grid;gap:8px}.review-lens-filter-bar{align-items:center;display:flex;gap:8px;justify-content:space-between}.review-lens-filter-bar button{align-items:center;background:#fff;border-color:#d4d4d4;color:#404040;display:inline-flex;gap:6px;min-height:30px;padding:5px 9px}.review-lens-filter-bar button:first-child{font-weight:700}.review-lens-filter-bar button[aria-expanded=true]{background:#171717;border-color:#171717;color:#fff}.review-lens-filter-bar span{align-items:center;background:#f97316;border-radius:999px;color:#fff;display:inline-flex;font-size:10px;height:17px;justify-content:center;min-width:17px;padding:0 5px}.review-lens-filters{background:#f5f5f5;border:1px solid #e5e5e5;border-radius:8px;display:grid;flex:0 0 auto;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));padding:8px}.review-lens-filters label{color:#525252;display:grid;font-size:10px;font-weight:800;gap:4px;letter-spacing:0;text-transform:uppercase}.review-lens-filters label:last-child{grid-column:1 / -1}.review-lens-list-panel{background:#fff;border:1px solid #d4d4d4;border-radius:10px;display:grid;gap:8px;grid-template-rows:auto minmax(0,1fr);min-height:0;overflow:hidden;padding:10px}.review-lens-comments__header{align-items:center;color:#171717;display:flex;gap:8px;justify-content:space-between}.review-lens-comments__header h3{color:#525252;font-size:11px;font-weight:800;letter-spacing:0;margin:0;text-transform:uppercase}.review-lens-comments__header span{align-items:center;background:#e5e5e5;border-radius:999px;color:#404040;display:inline-flex;font-size:11px;justify-content:center;min-width:22px;padding:2px 7px}.review-lens-comments__list{align-content:start;display:grid;gap:8px;min-height:0;overflow:auto;padding-right:2px}.review-lens-selected-panel{background:#171717;border-radius:10px;box-shadow:0 -10px 28px #0f172a2e;display:grid;gap:0;grid-template-rows:auto minmax(0,1fr);min-height:0;overflow:hidden;padding:4px}.review-lens-selected-panel__label{color:#d4d4d4;font-size:10px;font-weight:800;letter-spacing:0;padding:7px 8px 8px;text-transform:uppercase}.review-lens-selected-panel--empty{color:#d4d4d4;font-size:12px;line-height:1.4;padding:4px 12px 12px}.review-lens-selected-panel--empty p{color:#f5f5f5}.review-lens-detail{background:linear-gradient(180deg,#fff,#f8fafc);border:0;border-radius:8px;box-shadow:none;box-sizing:border-box;display:grid;gap:10px;min-height:0;overflow:auto;padding:12px}.review-lens-detail__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.review-lens-detail__header-actions{align-items:center;display:flex;flex:0 0 auto;gap:8px}.review-lens-copy-link{background:none;border:1px solid #e2e8f0;border-radius:4px;color:#2563eb;cursor:pointer;font-size:11px;line-height:1;padding:4px 8px}.review-lens-copy-link:hover{background:#eff6ff}.review-lens-detail__header h3{color:#171717;font-size:13px;line-height:1.2;margin:0;text-transform:capitalize}.review-lens-detail__header strong,.review-lens-comment__header strong{background:#fee2e2;border:1px solid #fecaca;border-radius:999px;color:#991b1b;flex:0 0 auto;font-size:10px;line-height:1;padding:5px 7px;text-transform:uppercase}.review-lens-detail blockquote{background:#f8fafc;border:1px solid #dbeafe;border-left:3px solid #2563eb;border-radius:6px;color:#171717;font-size:15px;font-weight:700;line-height:1.35;margin:0;padding:9px 10px}.review-lens-detail-meta{background:#fff;border:1px solid #e5e5e5;border-radius:6px;display:grid;gap:0;margin:0;overflow:hidden}.review-lens-detail-meta div{display:grid;gap:2px;grid-template-columns:72px minmax(0,1fr);padding:6px 8px}.review-lens-detail-meta div+div{border-top:1px solid #eeeeee}.review-lens-detail-meta dt,.review-lens-detail-meta dd{font-size:11px;line-height:1.25;margin:0;min-width:0}.review-lens-detail-meta dt{color:#737373;font-weight:800;text-transform:uppercase}.review-lens-detail-meta dd{color:#262626;overflow-wrap:anywhere}.review-lens-detail a{color:#2563eb;font-weight:700}.review-lens-comment{background:#fff;border:1px solid #e5e5e5;border-radius:8px;box-shadow:0 1px 2px #0f172a0a;cursor:pointer;display:grid;gap:10px;padding:12px;position:relative;text-align:left}.review-lens-comment:before{background:#737373;border-radius:999px;bottom:12px;content:"";left:8px;position:absolute;top:12px;width:3px}.review-lens-comment--high:before{background:#dc2626}.review-lens-comment--medium:before{background:#f97316}.review-lens-comment--low:before{background:#16a34a}.review-lens-comment:focus-visible{outline:2px solid #2563eb;outline-offset:2px}.review-lens-comment--selected{background:#eff6ff;border-color:#2563eb;box-shadow:0 8px 18px #2563eb1f}.review-lens-comment__header{align-items:center;display:flex;gap:8px;justify-content:space-between;padding-left:8px}.review-lens-comment__header span{color:#525252;font-size:10px;font-weight:800;letter-spacing:0;text-transform:uppercase}.review-lens-comment__content{display:grid;gap:6px;padding-left:8px}.review-lens-comment__content p{color:#171717;font-size:14px;line-height:1.35}.review-lens-comment__content span{color:#525252;font-size:11px;line-height:1}.review-lens-tags{display:flex;flex-wrap:wrap;gap:5px;padding-left:8px}.review-lens-tags span{background:#f5f5f5;border:1px solid #e5e5e5;border-radius:999px;color:#404040;font-size:10px;font-weight:700;line-height:1;padding:4px 6px}.review-lens-thread{border-top:1px solid #e5e5e5;display:grid;gap:6px;padding-top:10px}.review-lens-thread__header{align-items:center;display:flex;justify-content:space-between}.review-lens-thread h3{margin:0}.review-lens-thread__header span{color:#737373;font-size:11px;font-weight:800}.review-lens-detail .review-lens-thread textarea{min-height:48px}.review-lens-status-actions{align-items:center;display:grid;gap:8px;grid-template-columns:minmax(0,1fr) auto}.review-lens-status-actions button{min-height:30px}.review-lens-status-actions .review-lens-button-secondary{background:#fff;border-color:#d4d4d4;color:#404040}.review-lens-status-actions .review-lens-button-primary{background:#171717;border-color:#171717;color:#fff}.review-lens-thread__message{background:#f5f5f5;border-radius:6px;display:grid;gap:4px;padding:8px}.review-lens-thread__message p{font-size:12px;line-height:1.35}.review-lens-thread__message span{color:#737373;font-size:10px}.review-lens-comment__actions{display:flex;justify-content:flex-end}.review-lens-comment__actions button{background:transparent;border-color:#d4d4d4;color:#404040;min-height:28px;padding:4px 10px}.review-lens-comment__actions button:hover{background:#171717;border-color:#171717;color:#fff}.review-lens-marker{background:#f97316;border:2px solid #ffffff;border-radius:999px;box-shadow:0 8px 20px #0f172a3d;cursor:pointer;height:18px;pointer-events:auto;position:fixed;transform:translate(-50%,-50%);width:18px}.review-lens-marker--selected{background:#2563eb}.review-lens-minimap{background:#1717171f;border-radius:999px;bottom:24px;pointer-events:auto;position:fixed;right:8px;top:24px;width:10px}.review-lens-minimap__point{background:#f97316;border:2px solid #ffffff;border-radius:999px;box-shadow:0 2px 8px #0f172a38;height:14px;left:50%;min-height:0;padding:0;position:absolute;transform:translate(-50%,-50%);width:14px}.review-lens-minimap__point--selected{background:#2563eb}.review-lens-insights,.review-lens-summary{border:1px solid #e5e5e5;border-radius:8px;display:grid;gap:8px;padding:10px}.review-lens-insights h3,.review-lens-summary h3{margin:0}.review-lens-insights p,.review-lens-insights li,.review-lens-summary dt,.review-lens-summary dd{color:#404040;font-size:12px;line-height:1.35}.review-lens-insights ul{display:grid;gap:6px;margin:0;padding-left:18px}.review-lens-summary{align-content:start;flex:1 1 auto;min-height:0;overflow:auto;padding-right:4px}.review-lens-summary section{border-bottom:1px solid #e5e5e5;display:grid;gap:8px;padding-bottom:10px}.review-lens-summary section:last-child{border-bottom:0;padding-bottom:0}.review-lens-summary dl,.review-lens-summary div{display:grid;gap:6px;margin:0}.review-lens-summary div{grid-template-columns:minmax(0,1fr) auto}.review-lens-summary dd{font-weight:700;margin:0}
package/dist/types.d.ts CHANGED
@@ -100,6 +100,15 @@ export type CreateAttachmentInput = {
100
100
  data: Blob | string;
101
101
  createdBy: string;
102
102
  };
103
+ export type ReviewLensEmailNotificationOptions = {
104
+ enabled?: boolean;
105
+ subjectPrefix?: string;
106
+ };
107
+ export type ReviewLensSendEmailInput = {
108
+ to: string[];
109
+ subject: string;
110
+ text: string;
111
+ };
103
112
  export type ReviewLensDesignTokens = {
104
113
  spacing?: string[];
105
114
  fontSize?: string[];
@@ -121,6 +130,7 @@ export type ReviewLensAdapter = {
121
130
  updateFeedback(id: string, patch: UpdateFeedbackInput): Promise<ReviewLensFeedback>;
122
131
  listMessages(feedbackId: string): Promise<ReviewLensThreadMessage[]>;
123
132
  createMessage(input: CreateMessageInput): Promise<ReviewLensThreadMessage>;
133
+ sendEmail?(input: ReviewLensSendEmailInput): Promise<void>;
124
134
  uploadAttachment?(feedbackId: string, input: CreateAttachmentInput): Promise<ReviewLensAttachment>;
125
135
  };
126
136
  export type ReviewLensConfig = {
@@ -134,6 +144,7 @@ export type ReviewLensConfig = {
134
144
  normalizeUrl?: (url: string) => string;
135
145
  designTokens?: ReviewLensDesignTokens;
136
146
  captureScreenshot?: (target: ReviewLensTarget) => Promise<Blob | string>;
147
+ emailNotifications?: boolean | ReviewLensEmailNotificationOptions;
137
148
  uploadAttachment?: (feedbackId: string, input: CreateAttachmentInput) => Promise<ReviewLensAttachment>;
138
149
  adapter?: ReviewLensAdapter;
139
150
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "review-lens-react",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "React overlay for UX review feedback backed by Google Sheets.",
5
5
  "repository": {
6
6
  "type": "git",