import{ar as K,bc as ee,bb as te,aY as b,aP as H,aT as e,a2 as ae,p as V,V as B,a7 as re,aq as F,d as _,x as se,E as ne,I as oe,L as ie,Q as O,c as G,J as le,aR as ce,aj as de,b4 as ue,ax as me,ah as Z,aB as q}from"./chunk-02oqS8tD.js";import{c as he}from"./chunk-Cd_gpmCR.js";import{u as xe}from"./chunk-BR3_qbVm.js";import"./chunk-B8Q4vgLh.js";import"./chunk-x_Z6cwvR.js";import"./chunk-CoYD1fGq.js";/**
 * @license lucide-react v0.451.0 - ISC
 *
 * This source code is licensed under the ISC license.
 * See the LICENSE file in the root directory of this source tree.
 */const fe=K("SquareSplitHorizontal",[["path",{d:"M8 19H5c-1 0-2-1-2-2V7c0-1 1-2 2-2h3",key:"lubmu8"}],["path",{d:"M16 5h3c1 0 2 1 2 2v10c0 1-1 2-2 2h-3",key:"1ag34g"}],["line",{x1:"12",x2:"12",y1:"4",y2:"20",key:"1tx1rr"}]]);/**
 * @license lucide-react v0.451.0 - ISC
 *
 * This source code is licensed under the ISC license.
 * See the LICENSE file in the root directory of this source tree.
 */const ge=K("ZoomIn",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["line",{x1:"21",x2:"16.65",y1:"21",y2:"16.65",key:"13gj7c"}],["line",{x1:"11",x2:"11",y1:"8",y2:"14",key:"1vmskp"}],["line",{x1:"8",x2:"14",y1:"11",y2:"11",key:"durymu"}]]),W=28,pe=2;async function X(h){return new Promise((o,c)=>{const s=new Image;s.onload=()=>o(s),s.onerror=()=>c(new Error("That image could not be decoded. PNG, JPEG and WebP all work.")),s.src=h})}function Y(h,o,c){const s=document.createElement("canvas");s.width=o,s.height=c;const r=s.getContext("2d",{willReadFrequently:!0});if(!r)throw new Error("This browser did not provide a 2D canvas context.");return r.imageSmoothingEnabled=!0,r.imageSmoothingQuality="high",r.drawImage(h,0,0,o,c),r.getImageData(0,0,o,c)}function be(h,o,c){const s=h[c+3]/255,r=o[c+3]/255,y=Math.abs(h[c]*s+255*(1-s)-(o[c]*r+255*(1-r))),a=Math.abs(h[c+1]*s+255*(1-s)-(o[c+1]*r+255*(1-r))),d=Math.abs(h[c+2]*s+255*(1-s)-(o[c+2]*r+255*(1-r)));return .2126*y+.7152*a+.0722*d}async function ye(h,o,c={}){const s=c.threshold??W,[r,y]=await Promise.all([X(h),X(o)]),a=r.naturalWidth,d=r.naturalHeight;if(a===0||d===0)throw new Error("The reference image has no dimensions.");const R=y.naturalWidth!==a||y.naturalHeight!==d?`The capture (${String(y.naturalWidth)} × ${String(y.naturalHeight)}) was scaled to the reference's ${String(a)} × ${String(d)}. Differences caused by that rescaling are not real regressions — capture at the reference's size for an exact comparison.`:void 0,g=Y(r,a,d),i=Y(y,a,d),l=g.data,u=i.data,j=new Uint8Array(a*d);for(let x=0;x<a*d;x++)be(l,u,x*4)>s&&(j[x]=1);const U=new Uint8Array(a*d);let S=0,k=a,w=d,f=-1,C=-1;for(let x=0;x<d;x++)for(let m=0;m<a;m++){const z=x*a+m;if(j[z]===0)continue;let M=0;for(let I=-1;I<=1;I++)for(let L=-1;L<=1;L++){if(L===0&&I===0)continue;const t=m+L,T=x+I;t<0||T<0||t>=a||T>=d||j[T*a+t]===1&&(M+=1)}M<pe||(U[z]=1,S+=1,m<k&&(k=m),x<w&&(w=x),m>f&&(f=m),x>C&&(C=x))}const p=new ImageData(a,d);for(let x=0;x<a*d;x++){const m=x*4;if(U[x]===1)p.data[m]=243,p.data[m+1]=88,p.data[m+2]=0,p.data[m+3]=255;else{const M=(.2126*l[m]+.7152*l[m+1]+.0722*l[m+2])*.35+255*.65;p.data[m]=M,p.data[m+1]=M,p.data[m+2]=M,p.data[m+3]=255}}const v=document.createElement("canvas");v.width=a,v.height=d;const D=v.getContext("2d");if(!D)throw new Error("This browser did not provide a 2D canvas context.");return D.putImageData(p,0,0),{comparison:{id:`vis_${String(Date.now())}`,capturedAt:Date.now(),referenceLabel:c.referenceLabel??"Reference",candidateLabel:c.candidateLabel??"Capture",width:a,height:d,diffRatio:S/(a*d),diffPixels:S,threshold:s,...f>=0?{bounds:{x:k,y:w,width:f-k+1,height:C-w+1}}:{},...S>0?{regions:we(U,a,d)}:{}},diffDataUrl:v.toDataURL("image/png"),...R===void 0?{}:{scaleNote:R}}}const E=16,J=8;function we(h,o,c){const s=Math.ceil(o/E),r=Math.ceil(c/E),y=new Uint8Array(s*r);for(let i=0;i<c;i++){const l=Math.floor(i/E)*s;for(let u=0;u<o;u++)h[i*o+u]===1&&(y[l+Math.floor(u/E)]=1)}const a=new Uint8Array(s*r),d=[],n=[];for(let i=0;i<y.length;i++){if(y[i]===0||a[i]===1)continue;a[i]=1,n.push(i);let l=s,u=r,j=-1,U=-1,S=0;for(;n.length>0;){const k=n.pop(),w=k%s,f=(k-w)/s;S+=1,w<l&&(l=w),f<u&&(u=f),w>j&&(j=w),f>U&&(U=f);for(let C=-1;C<=1;C++)for(let p=-1;p<=1;p++){const v=w+p,D=f+C;if(v<0||D<0||v>=s||D>=r)continue;const $=D*s+v;y[$]===0||a[$]===1||(a[$]=1,n.push($))}}d.push({x:l*E,y:u*E,width:Math.min(o,(j+1)*E)-l*E,height:Math.min(c,(U+1)*E)-u*E,cells:S})}d.sort((i,l)=>l.cells-i.cells);const R=d.slice(0,J),g=d.slice(J);if(g.length>0&&R.length>0){const i=g.reduce((l,u)=>({x:Math.min(l.x,u.x),y:Math.min(l.y,u.y),right:Math.max(l.x+l.width,u.x+u.width),bottom:Math.max(l.y+l.height,u.y+u.height),width:0,height:0}),{x:g[0].x,y:g[0].y,right:g[0].x+g[0].width,bottom:g[0].y+g[0].height,width:0,height:0});R.push({x:i.x,y:i.y,width:i.right-i.x,height:i.bottom-i.y,cells:g.reduce((l,u)=>l+u.cells,0)})}return R.map(({x:i,y:l,width:u,height:j})=>({x:i,y:l,width:u,height:j}))}function Q(h){const o=h.diffRatio*100;return h.diffPixels===0?{label:"Pixel-identical",tone:"clean"}:o<.1?{label:`${o.toFixed(3)}% differs — likely rendering noise`,tone:"minor"}:o<1?{label:`${o.toFixed(2)}% differs`,tone:"minor"}:{label:`${o.toFixed(1)}% differs`,tone:"major"}}const ve=12*1024*1024;function Ue(){const h=ee(t=>t.go),o=te(t=>t.projectId),c=xe(),s=b.useRef(null),[r,y]=b.useState(null),[a,d]=b.useState(null),[n,R]=b.useState(null),[g,i]=b.useState("overlay"),[l,u]=b.useState(50),[j,U]=b.useState(W),[S,k]=b.useState(null),[w,f]=b.useState(null),[C,p]=b.useState(null),[v,D]=b.useState(!0),[$,x]=b.useState(1),m=b.useCallback(()=>{H().then(t=>{if(!t.ok)return D(t.error);D(t.value.targetable===!1?"Switch to a normal web page — Chrome does not allow capturing its own pages.":t.value.tabId===null?"Open the app under test in a browser window first.":!0)})},[]);b.useEffect(m,[m]),b.useEffect(()=>()=>{r?.url.startsWith("blob:")&&URL.revokeObjectURL(r.url),a?.url.startsWith("blob:")&&URL.revokeObjectURL(a.url)},[r,a]);const z=t=>{if(t){if(!t.type.startsWith("image/")){f("That is not an image. PNG, JPEG and WebP all work.");return}if(t.size>ve){f(`That image is ${(t.size/1024/1024).toFixed(1)} MB. Keep references under 12 MB.`);return}r?.url.startsWith("blob:")&&URL.revokeObjectURL(r.url),f(null),R(null),y({url:URL.createObjectURL(t),name:t.name})}},M=async()=>{k("capturing"),f(null);try{const t=await de();a?.url.startsWith("blob:")&&URL.revokeObjectURL(a.url),d({url:URL.createObjectURL(t),blob:t}),R(null)}catch(t){f(t.message)}finally{k(null)}},I=async()=>{if(!r||!a)return;k("comparing"),f(null);const t=await H(),T=await he({context:c}),P=await ue({kind:"visual",title:`Visual · ${Ne(t.ok?t.value.url:null)}`,snapshot:T,...c===void 0?{}:{context:c},...o==null?{}:{projectId:o}});p(P);try{const N=await ye(r.url,a.url,{threshold:j,referenceLabel:r.name,candidateLabel:"Live capture"});R(N),i("difference");const A=Q(N.comparison);await me(P,{type:"VISUAL_COMPARED",message:A.label,severity:A.tone==="major"?"warn":"info",meta:{diffPixels:N.comparison.diffPixels,diffRatio:N.comparison.diffRatio,threshold:N.comparison.threshold,...N.scaleNote?{rescaled:!0}:{}}}),await Z(P,{type:"screenshot",source:"visual",label:"Live capture",artifact:{blob:a.blob,fileName:`visual-capture-${String(Date.now())}.png`}}),await Z(P,{type:"visual-diff",source:"visual",label:A.label,artifact:{blob:await je(N.diffDataUrl),fileName:`visual-diff-${String(Date.now())}.png`},data:{...N.comparison,...N.scaleNote?{scaleNote:N.scaleNote}:{}}}),await q(P,{status:"passed",summary:A.label})}catch(N){f(N.message),await q(P,{status:"error",error:N.message})}finally{k(null)}},L=n?Q(n.comparison):null;return e.jsxs(ae,{title:"Visual",subtitle:"Compare the live page against a reference image.",onBack:()=>h(ce("tools")),actions:e.jsxs(e.Fragment,{children:[e.jsxs(G,{size:"sm",variant:"outline",className:"h-7",loading:S==="capturing",disabled:v!==!0,onClick:()=>void M(),children:[e.jsx(_,{className:"h-3 w-3"}),"Capture"]}),e.jsxs(G,{size:"sm",className:"h-7",loading:S==="comparing",disabled:!r||!a,onClick:()=>void I(),children:[e.jsx(le,{className:"h-3 w-3"}),"Compare"]})]}),sticky:L?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:F("shrink-0 rounded-full border px-2 py-0.5 text-[10px] font-semibold",L.tone==="clean"&&"border-emerald-500/40 bg-emerald-500/10 text-emerald-700 dark:text-emerald-400",L.tone==="minor"&&"border-amber-500/40 bg-amber-500/10 text-amber-700 dark:text-amber-400",L.tone==="major"&&"border-alert-orange/40 bg-alert-orange/10 text-alert-orange"),children:L.label}),C&&e.jsx("button",{type:"button",onClick:()=>h({name:"execution-detail",executionId:C.id}),className:"ml-auto shrink-0 text-[10px] font-semibold text-dynamic-azure hover:underline",children:"Open execution"})]}):void 0,children:[v!==!0&&e.jsx(V,{title:"Capture not available here",message:v,onRetry:m}),w&&e.jsx(V,{message:w,onRetry:()=>f(null),retryLabel:"Dismiss"}),e.jsx(B,{title:"Inputs",children:e.jsxs("div",{className:"grid grid-cols-2 gap-1.5",children:[e.jsxs("button",{type:"button",onClick:()=>s.current?.click(),className:F("flex flex-col items-center gap-1 rounded-lg border border-dashed px-2 py-3 transition-colors",r?"border-dynamic-azure/50 bg-dynamic-azure/[0.04]":"border-stroke hover:border-dynamic-azure/40"),children:[e.jsx(re,{className:"h-3.5 w-3.5 text-muted-foreground"}),e.jsx("span",{className:"text-[10px] font-semibold",children:"Reference"}),e.jsx("span",{className:"max-w-full truncate text-[9px] text-muted-foreground",children:r?r.name:"Upload an image"})]}),e.jsx("input",{ref:s,type:"file",accept:"image/*",className:"hidden",onChange:t=>z(t.target.files?.[0])}),e.jsxs("button",{type:"button",disabled:v!==!0,onClick:()=>void M(),className:F("flex flex-col items-center gap-1 rounded-lg border border-dashed px-2 py-3 transition-colors",a?"border-dynamic-azure/50 bg-dynamic-azure/[0.04]":"border-stroke hover:border-dynamic-azure/40",v!==!0&&"cursor-not-allowed opacity-50"),children:[e.jsx(_,{className:"h-3.5 w-3.5 text-muted-foreground"}),e.jsx("span",{className:"text-[10px] font-semibold",children:"Capture"}),e.jsx("span",{className:"text-[9px] text-muted-foreground",children:a?"Captured":"From the live page"})]})]})}),S==="comparing"&&e.jsx(se,{label:"Comparing pixels…"}),!r&&!a&&e.jsx(ne,{icon:oe,title:"Nothing to compare yet.",description:"Upload the design or a known-good screenshot as the reference, then capture the live page. We'll measure exactly which pixels moved and keep both as evidence."}),(r??a)&&e.jsxs(e.Fragment,{children:[e.jsxs(B,{title:"View",children:[e.jsx("div",{className:"flex gap-0.5 rounded-md bg-stroke/15 p-0.5 dark:bg-white/[0.04]",children:[{id:"overlay",label:"Overlay",icon:ie},{id:"side-by-side",label:"Side by side",icon:fe},{id:"difference",label:"Difference",icon:ge}].map(t=>e.jsxs("button",{type:"button",onClick:()=>i(t.id),disabled:t.id==="difference"&&!n,className:F("flex flex-1 items-center justify-center gap-1 rounded px-1.5 py-1 text-[10px] font-semibold transition-colors",g===t.id?"bg-white text-dynamic-azure shadow-sm dark:bg-midnight-navy":"text-muted-foreground hover:text-foreground",t.id==="difference"&&!n&&"cursor-not-allowed opacity-40"),children:[e.jsx(t.icon,{className:"h-2.5 w-2.5"}),t.label]},t.id))}),g==="overlay"&&r&&a&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("div",{className:"relative overflow-auto rounded-lg border border-stroke/70 bg-white dark:border-stroke/25",children:e.jsxs("div",{className:"relative",style:{width:`${String(100*$)}%`},children:[e.jsx("img",{src:r.url,alt:"Reference",className:"block w-full"}),e.jsx("img",{src:a.url,alt:"Capture",className:"absolute inset-0 block w-full",style:{opacity:l/100}})]})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"shrink-0 text-[9px] text-muted-foreground",children:"Reference"}),e.jsx("input",{type:"range",min:0,max:100,value:l,onChange:t=>u(Number(t.target.value)),"aria-label":"Blend between reference and capture",className:"h-1 flex-1 accent-dynamic-azure"}),e.jsx("span",{className:"shrink-0 text-[9px] text-muted-foreground",children:"Capture"})]})]}),g==="side-by-side"&&e.jsx("div",{className:"grid grid-cols-2 gap-1.5",children:[{src:r?.url,label:r?.name??"Reference"},{src:a?.url,label:"Live capture"}].map((t,T)=>e.jsxs("div",{children:[e.jsx("div",{className:"overflow-auto rounded-lg border border-stroke/70 bg-white dark:border-stroke/25",children:t.src?e.jsx("img",{src:t.src,alt:t.label,className:"block w-full"}):e.jsx("div",{className:"flex h-24 items-center justify-center text-[9px] text-muted-foreground",children:"Not set"})}),e.jsx("p",{className:"mt-1 truncate text-[9px] text-muted-foreground",children:t.label})]},T))}),g==="difference"&&n&&e.jsx("div",{className:"overflow-auto rounded-lg border border-stroke/70 bg-white dark:border-stroke/25",children:e.jsx("img",{src:n.diffDataUrl,alt:"Pixel differences",className:"block w-full"})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"shrink-0 text-[9px] text-muted-foreground",children:"Zoom"}),e.jsx("input",{type:"range",min:100,max:400,step:25,value:$*100,onChange:t=>x(Number(t.target.value)/100),"aria-label":"Zoom",className:"h-1 flex-1 accent-dynamic-azure"}),e.jsxs("span",{className:"w-8 shrink-0 text-right text-[9px] text-muted-foreground",children:[String(Math.round($*100)),"%"]})]})]}),e.jsxs(B,{title:"Tolerance",hint:"How different a pixel must be before it counts.",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"range",min:0,max:80,value:j,onChange:t=>U(Number(t.target.value)),"aria-label":"Difference tolerance",className:"h-1 flex-1 accent-dynamic-azure"}),e.jsx("span",{className:"w-6 shrink-0 text-right font-mono text-[10px] text-muted-foreground",children:String(j)})]}),e.jsxs("p",{className:"text-[10px] leading-relaxed text-muted-foreground",children:["The default of ",String(W)," passes antialiasing — two renders of the same text differ by up to about 20 — and fails a real colour or position change. Raise it when comparing captures from two different machines; lower it to catch a subtle colour shift."]})]})]}),n&&e.jsxs(B,{title:"Measured",children:[n.scaleNote&&e.jsx("div",{className:"rounded-lg border border-amber-500/30 bg-amber-500/[0.06] p-2.5",children:e.jsx("p",{className:"text-[10px] leading-relaxed text-amber-700 dark:text-amber-300",children:n.scaleNote})}),e.jsxs("div",{className:"rounded-lg bg-stroke/10 px-2.5 py-1.5 dark:bg-white/[0.03]",children:[e.jsx(O,{label:"Differing pixels",value:n.comparison.diffPixels.toLocaleString()}),e.jsx(O,{label:"Of total",value:`${(n.comparison.diffRatio*100).toFixed(3)}%`}),e.jsx(O,{label:"Compared at",value:`${String(n.comparison.width)} × ${String(n.comparison.height)}`,mono:!0}),e.jsx(O,{label:"Tolerance",value:String(n.comparison.threshold)}),n.comparison.bounds&&e.jsx(O,{label:"Overall extent",value:`${String(n.comparison.bounds.width)} × ${String(n.comparison.bounds.height)} at ${String(n.comparison.bounds.x)}, ${String(n.comparison.bounds.y)}`,mono:!0})]}),(n.comparison.regions?.length??0)>0&&e.jsxs("div",{className:"rounded-lg border border-stroke/70 px-2.5 py-2 dark:border-stroke/25",children:[e.jsx("p",{className:"mb-1 text-[10px] font-semibold",children:n.comparison.regions.length===1?"1 changed area":`${String(n.comparison.regions.length)} changed areas`}),e.jsx("ul",{className:"space-y-0.5",children:n.comparison.regions.map((t,T)=>e.jsxs("li",{className:"flex items-baseline justify-between gap-2 font-mono text-[9.5px] text-muted-foreground",children:[e.jsxs("span",{children:[String(t.width)," × ",String(t.height)]}),e.jsxs("span",{children:["at ",String(t.x),", ",String(t.y)]})]},`${String(t.x)}-${String(t.y)}-${String(T)}`))}),e.jsx("p",{className:"mt-1 text-[9.5px] leading-snug text-muted-foreground",children:"Positions are in the compared image's pixels, largest area first."})]})]})]})}async function je(h){return(await fetch(h)).blob()}function Ne(h){if(!h)return"page";try{return new URL(h).host}catch{return"page"}}export{Ue as VisualScreen};
//# sourceMappingURL=chunk-BgTnbjrQ.js.map
