feedbackkit-web 1.0.42 → 1.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/feedbackkit.iife.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var FeedbackKit=(function(){"use strict";async function $t(t={}){const e=Math.min(window.devicePixelRatio||1,t.maxPixelRatio??2);if(t.mode==="display")try{const n=await Ze(e);if(n)return n}catch{}return Xe(e,t.exclude)}const rt="data-feedbackkit-pin";async function Xe(t,e){const n=window.innerWidth,r=window.innerHeight,o=Ye(e),s=document.documentElement,i=getComputedStyle(document.body).backgroundColor,a=getComputedStyle(s).backgroundColor,c=Bt(a)?Bt(i)?"#ffffff":i:a;try{const{domToCanvas:l}=await Promise.resolve().then(()=>Jr);return{canvas:await l(s,{width:n,height:r,scale:t,backgroundColor:c,filter:e?h=>!e(h):null,features:{restoreScrollPosition:!0},timeout:8e3,onCloneEachNode:h=>{if(!(h instanceof HTMLElement))return;h.tagName==="BODY"&&!h.style.transform&&(h.style.transform="translate(0px, 0px)");const f=h.getAttribute(rt);if(f===null)return;h.removeAttribute(rt);const u=o.info.get(f);if(!u)return;const m=h.style;u.kind==="sticky"?(m.setProperty("position","relative","important"),m.setProperty("inset","auto","important"),m.setProperty("top",`${u.top}px`,"important"),m.setProperty("left",`${u.left}px`,"important")):(m.setProperty("position","fixed","important"),m.setProperty("inset","auto","important"),m.setProperty("top",`${u.top}px`,"important"),m.setProperty("left",`${u.left}px`,"important"),m.setProperty("width",`${u.width}px`,"important"),m.setProperty("height",`${u.height}px`,"important"),m.setProperty("margin","0","important"),m.setProperty("box-sizing","border-box","important"),m.setProperty("transform","none","important"),m.setProperty("translate","none","important"))}}),width:n,height:r,pixelRatio:t}}finally{o.cleanup()}}function Ye(t){const e=new Map,n=[],r=document.body;if(!r)return{info:e,cleanup:()=>{}};const o=document.createTreeWalker(r,NodeFilter.SHOW_ELEMENT,{acceptNode:i=>t?.(i)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT});let s=0;for(let i=o.nextNode();i;i=o.nextNode()){const a=i,c=getComputedStyle(a);if(c.position!=="fixed"&&c.position!=="sticky"||c.display==="none")continue;const l=a.getBoundingClientRect(),d=String(s++);if(c.position==="sticky"){const h=a.style.getPropertyValue("position"),f=a.style.getPropertyPriority("position");a.style.setProperty("position","static","important");const u=a.getBoundingClientRect();a.style.setProperty("position",h,f),h||a.style.removeProperty("position");const m=l.top-u.top,p=l.left-u.left;if(Math.abs(p)<.5&&Math.abs(m)<.5)continue;e.set(d,{kind:"sticky",top:m,left:p,width:l.width,height:l.height})}else{const h=Je(a),f=h.getBoundingClientRect();e.set(d,{kind:"fixed",top:l.top-(f.top+h.clientTop),left:l.left-(f.left+h.clientLeft),width:l.width,height:l.height})}a.setAttribute(rt,d),n.push(a)}return{info:e,cleanup:()=>{for(const i of n)i.removeAttribute(rt)}}}function Je(t){for(let e=t.parentElement;e&&e!==document.body;e=e.parentElement){const n=getComputedStyle(e);if(n.transform!=="none"||n.filter!=="none"||n.perspective!=="none"||n.backdropFilter!==void 0&&n.backdropFilter!=="none"||/paint|layout|strict|content/.test(n.contain)||/transform|filter|perspective/.test(n.willChange))return e;const r=e.parentElement;if(r&&(r.scrollTop!==0||r.scrollLeft!==0))return e}return document.body}function Bt(t){return!t||t==="transparent"||/rgba\(\s*0,\s*0,\s*0,\s*0\s*\)/.test(t)}async function Ze(t){if(!navigator.mediaDevices?.getDisplayMedia)return null;const e={video:{displaySurface:"browser"},audio:!1,preferCurrentTab:!0,selfBrowserSurface:"include"},n=await navigator.mediaDevices.getDisplayMedia(e);try{const r=document.createElement("video");r.muted=!0,r.playsInline=!0,r.srcObject=n,await r.play(),await new Promise(c=>setTimeout(c,250));const o=window.innerWidth,s=window.innerHeight,i=document.createElement("canvas");i.width=Math.round(o*t),i.height=Math.round(s*t);const a=i.getContext("2d");return a?(a.drawImage(r,0,0,i.width,i.height),{canvas:i,width:o,height:s,pixelRatio:t}):null}finally{for(const r of n.getTracks())r.stop()}}function yt(t){return new Promise((e,n)=>{t.toBlob(r=>r?e(r):n(new Error("Failed to encode screenshot")),"image/png")})}function Qe(t){let e="Unknown",n="",r;(r=t.match(/(?:iPhone|iPad|iPod).*?OS (\d+[_.\d]*)/))?(e=/iPad/.test(t)?"iPadOS":"iOS",n=r[1].replace(/_/g,".")):(r=t.match(/Android (\d+(?:\.\d+)*)/))?(e="Android",n=r[1]):(r=t.match(/Windows NT (\d+\.\d+)/))?(e="Windows",n={"10.0":"10","6.3":"8.1","6.2":"8","6.1":"7"}[r[1]]??r[1]):(r=t.match(/Mac OS X (\d+[_.\d]*)/))?(e="macOS",n=r[1].replace(/_/g,".")):/CrOS/.test(t)?e="ChromeOS":/Linux/.test(t)&&(e="Linux");let o="Unknown",s="";const i=[["Edge",/Edg(?:e|A|iOS)?\/([\d.]+)/],["Opera",/(?:OPR|Opera)\/([\d.]+)/],["Samsung Internet",/SamsungBrowser\/([\d.]+)/],["Firefox",/(?:Firefox|FxiOS)\/([\d.]+)/],["Chrome",/(?:Chrome|CriOS)\/([\d.]+)/],["Safari",/Version\/([\d.]+).*Safari/]];for(const[a,c]of i){const l=t.match(c);if(l){o=a,s=l[1];break}}return{osName:e,osVersion:n,browserName:o,browserVersion:s}}const Ot=/token|secret|password|passwd|pwd|auth|session|key|code|signature|sig|jwt|otp|email/i;function Ut(t){try{const e=new URL(t);for(const n of[...e.searchParams.keys()])Ot.test(n)&&e.searchParams.set(n,"[redacted]");return e.hash&&Ot.test(e.hash)&&(e.hash="#[redacted]"),e.toString()}catch{return t}}async function tn(){const t=navigator.userAgentData;if(!t?.getHighEntropyValues)return null;try{return await Promise.race([t.getHighEntropyValues(["platform","platformVersion","fullVersionList"]),new Promise(e=>setTimeout(()=>e(null),300))])}catch{return null}}function en(t,e){const n=t.platform,r=t.platformVersion??"";if(!n)return e;if(n==="macOS")return{osName:"macOS",osVersion:ot(r)};if(n==="Windows"){const o=parseInt(r,10);return{osName:"Windows",osVersion:o>=13?"11":o>0?"10":e.osVersion}}return n==="Android"?{osName:"Android",osVersion:ot(r)||e.osVersion}:n==="Chrome OS"||n==="ChromeOS"?{osName:"ChromeOS",osVersion:ot(r)}:{osName:n,osVersion:ot(r)||e.osVersion}}function ot(t){return t.replace(/(\.0)+$/,"")}function nn(t){const e=t.fullVersionList??[],n=["Microsoft Edge","Opera","Google Chrome","Chromium"];for(const r of n){const o=e.find(s=>s.brand===r);if(o)return{name:r==="Microsoft Edge"?"Edge":r==="Google Chrome"?"Chrome":r,version:o.version}}return null}async function rn(t={}){const e=navigator.userAgent,n=Qe(e),r=await tn(),o=r?en(r,n):n,s=r&&nn(r)||{name:n.browserName,version:n.browserVersion},i=s.version.split(".")[0];return{osName:o.osName,osVersion:o.osVersion,deviceModel:i?`${s.name} ${i}`:s.name,appVersion:t.appVersion??"",appBuild:t.appBuild??"",bundleIdentifier:location.host,screenName:t.screenName||location.pathname||null,locale:navigator.language||"en",screenWidthPoints:window.innerWidth,screenHeightPoints:window.innerHeight,screenScale:window.devicePixelRatio||1,platform:"web",pageUrl:Ut(location.href),userAgent:e,browserName:s.name,browserVersion:s.version}}const jt=1e3;function on(t){return t.replace(/\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]+/gi,"$1 [redacted]").replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g,"[redacted-jwt]").replace(/https?:\/\/[^\s"'<>)]+/g,e=>Ut(e)).replace(/("?(?:password|passwd|secret|token|api[_-]?key|access[_-]?token|refresh[_-]?token)"?\s*[:=]\s*)("[^"]*"|'[^']*'|[^\s,}&]+)/gi,"$1[redacted]")}function st(t){if(typeof t=="string")return t;if(t instanceof Error)return t.stack||`${t.name}: ${t.message}`;if(t===void 0)return"undefined";if(typeof t=="function")return`[function ${t.name||"anonymous"}]`;if(typeof Element<"u"&&t instanceof Element)return`<${t.tagName.toLowerCase()}>`;try{const e=new WeakSet;return JSON.stringify(t,(n,r)=>{if(typeof r=="object"&&r!==null){if(e.has(r))return"[circular]";e.add(r)}return typeof r=="bigint"?r.toString():r})}catch{return String(t)}}class sn{constructor(e=50){this.maxEntries=e,this.entries=[]}push(e,n){let r=on(n);r.length>jt&&(r=`${r.slice(0,jt)}… [truncated]`),this.entries.push({level:e,message:r,timestamp:new Date().toISOString()}),this.entries.length>this.maxEntries&&this.entries.splice(0,this.entries.length-this.maxEntries)}snapshot(){return this.entries.slice()}clear(){this.entries=[]}}function an(t={}){const e=new sn(t.maxEntries??50),n=[],r=t.includeVerbose?["log","info","warn","error","debug"]:["warn","error"];for(const i of r){const a=console[i];console[i]=function(...c){try{e.push(i,c.map(st).join(" "))}catch{}return a.apply(this,c)},n.push(()=>{console[i]=a})}const o=i=>{const a=i.filename?` (${i.filename}:${i.lineno}:${i.colno})`:"";e.push("error",`Uncaught ${i.error?st(i.error):i.message}${a}`)},s=i=>{e.push("error",`Unhandled promise rejection: ${st(i.reason)}`)};return window.addEventListener("error",o),window.addEventListener("unhandledrejection",s),n.push(()=>{window.removeEventListener("error",o),window.removeEventListener("unhandledrejection",s)}),t.network!==!1&&n.push(ln(e),dn(e)),{buffer:e,uninstall:()=>{for(const i of n.reverse())i()}}}let bt=null;function cn(t){bt=t}function wt(t){return!!bt&&t.startsWith(bt)}function ln(t){if(typeof window.fetch!="function")return()=>{};const e=window.fetch;return window.fetch=async function(n,r){const o=(r?.method||(n instanceof Request?n.method:"GET")).toUpperCase(),s=n instanceof Request?n.url:String(n);try{const i=await e.call(window,n,r);return i.status>=400&&!wt(s)&&t.push("network",`${o} ${s} → ${i.status} ${i.statusText}`.trim()),i}catch(i){throw!wt(s)&&!(i instanceof DOMException&&i.name==="AbortError")&&t.push("network",`${o} ${s} → failed: ${st(i)}`),i}},()=>{window.fetch=e}}function dn(t){if(typeof XMLHttpRequest>"u")return()=>{};const e=XMLHttpRequest.prototype,n=e.open,r=e.send,o=new WeakMap;return e.open=function(s,i,...a){return o.set(this,{method:String(s).toUpperCase(),url:String(i)}),n.call(this,s,i,...a)},e.send=function(s){return this.addEventListener("loadend",()=>{const i=o.get(this);!i||wt(i.url)||(this.status===0?t.push("network",`${i.method} ${i.url} → failed (network error)`):this.status>=400&&t.push("network",`${i.method} ${i.url} → ${this.status} ${this.statusText}`.trim()))}),r.call(this,s)},()=>{e.open=n,e.send=r}}const j="https://gpucoladcyvijefdjudf.supabase.co/functions/v1/ingest-feedback";class I extends Error{constructor(e,n,r){super(e),this.kind=n,this.status=r,this.name="FeedbackSubmissionError"}}async function H(t){const e=new Uint8Array(await t.arrayBuffer());let n="";const r=32768;for(let o=0;o<e.length;o+=r)n+=String.fromCharCode(...e.subarray(o,o+r));return btoa(n)}async function hn(t,e,n={}){const r={project_key:e,id:t.id,created_at:t.createdAt.toISOString(),text:t.text,annotations:t.annotations,environment:t.environment};if(t.screenshotRaw&&t.screenshotAnnotated){const[o,s]=await Promise.all([H(t.screenshotRaw),H(t.screenshotAnnotated)]);r.screenshot_raw_png_base64=o,r.screenshot_annotated_png_base64=s}return t.attachment&&(r.attachment_filename=t.attachment.filename,r.attachment_mime_type=t.attachment.mimeType,r.attachment_data_base64=await H(t.attachment.data)),t.products.length>0&&(r.product_keys=t.products.map(o=>o.key),r.products=t.products.map(o=>({key:o.key,name:o.name,description:o.description??"",is_default:o.isDefault??!1}))),t.logs.length>0&&(r.logs=t.logs),n.reporterId&&(r.reporter_id=n.reporterId),n.user&&(r.reporter=n.user),r}async function Ht(t,e,n={}){if(!e.projectKey)throw new I("FeedbackKit is not configured with a project key.","not_configured");const r=JSON.stringify(await hn(t,e.projectKey,n));let o;try{o=await fetch(e.endpoint??j,{method:"POST",headers:{"Content-Type":"application/json"},body:r})}catch(s){throw new I(`Network error: ${s instanceof Error?s.message:String(s)}`,"network")}if(!o.ok){let s="";try{s=(await o.json()).error??""}catch{}const i=s?` (${s})`:"",a=s==="origin_not_allowed"?`This site (${location.origin}) isn't in the project's allowed origins.`:o.status===401||o.status===403?`Server rejected the project key or origin (HTTP ${o.status})${i}.`:o.status===429?"Too many reports right now — please try again in a minute.":`Server returned HTTP ${o.status}${i}.`;throw new I(a,"server",o.status)}}async function un(t){const e=new URL(t.endpoint??j);e.searchParams.set("project_key",t.projectKey);const n=await fetch(e.toString());if(!n.ok)throw new I(`HTTP ${n.status}`,"server",n.status);return((await n.json()).products??[]).map(o=>({key:o.key,name:o.name,description:o.description??"",isDefault:o.is_default??!1}))}const Vt="feedbackkit.reporterId",fn=/^[A-Za-z0-9_-]{16,128}$/;let V=null,zt=null;function Wt(){const t=new Uint8Array(16);return crypto.getRandomValues(t),[...t].map(e=>e.toString(16).padStart(2,"0")).join("")}function z(){if(V)return V;try{const t=localStorage.getItem(Vt);if(t&&fn.test(t))return V=t;const e=Wt();return localStorage.setItem(Vt,e),V=e}catch{return V=Wt()}}function pn(t){zt=t&&(t.id||t.email||t.name)?{...t}:null}function Kt(){return zt}function qt(t){if(t.reporterUpdatesEndpoint)return t.reporterUpdatesEndpoint;const e=new URL(t.endpoint??j);return e.pathname=e.pathname.replace(/\/[^/]*\/?$/,"/reporter-updates"),e.search="",e.toString()}function mn(t){return{feedbackId:t.feedback_id,text:t.text??"",createdAt:t.created_at??"",screenName:t.screen_name??null,fixStage:t.fix_stage??null,fixedInBuild:t.fixed_in_build??null,fixSummary:t.fix_summary??null,needsVerification:t.needs_verification??!1,openQuestion:t.open_question?{id:t.open_question.id,body:t.open_question.body,createdAt:t.open_question.created_at}:null,screenshotUrl:t.screenshot_url??null,messages:(t.messages??[]).map(e=>({id:e.id,kind:e.kind,body:e.body,author:e.author,createdAt:e.created_at}))}}async function Gt(t){const e=new URL(qt(t));e.searchParams.set("project_key",t.projectKey),e.searchParams.set("reporter_id",z()),t.appBuild&&e.searchParams.set("build",t.appBuild);let n;try{n=await fetch(e.toString())}catch(o){throw new I(`Network error: ${o instanceof Error?o.message:String(o)}`,"network")}if(!n.ok)throw new I(`HTTP ${n.status}`,"server",n.status);return((await n.json()).updates??[]).map(mn)}async function gn(t,e,n){const r={project_key:t.projectKey,reporter_id:z(),feedback_id:e,action:n.type};if(t.appBuild&&(r.build=t.appBuild),n.type==="reply"&&(r.text=n.text),n.type==="reopen"){const o=n.report,s=o?.text??n.text;s&&(r.text=s),o?.screenshotAnnotated&&(r.screenshot_annotated_png_base64=await H(o.screenshotAnnotated),o.screenshotRaw&&(r.screenshot_raw_png_base64=await H(o.screenshotRaw)),r.annotations=o.annotations)}return r}async function kt(t,e,n){const r=JSON.stringify(await gn(t,e,n));let o;try{o=await fetch(qt(t),{method:"POST",headers:{"Content-Type":"application/json"},body:r})}catch(s){throw new I(`Network error: ${s instanceof Error?s.message:String(s)}`,"network")}if(!o.ok)throw new I(`HTTP ${o.status}`,"server",o.status)}const C=t=>`<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${t}</svg>`,v={feedback:C('<path d="M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12Z"/><path d="M8.5 10.5h7M8.5 14h4.5"/>'),pen:C('<path d="M4 20l4-1L19 8a2.1 2.1 0 0 0-3-3L5 16l-1 4Z"/><path d="M14.5 6.5l3 3"/>'),rectangle:C('<rect x="4" y="6" width="16" height="12" rx="1.5"/>'),arrow:C('<path d="M6 18L18 6"/><path d="M9 6h9v9"/>'),text:C('<path d="M5 6V5h14v1"/><path d="M12 5v14"/><path d="M9 19h6"/>'),move:C('<path d="M12 3v18M3 12h18"/><path d="M9 6l3-3 3 3M9 18l3 3 3-3M6 9l-3 3 3 3M18 9l3 3-3 3"/>'),undo:C('<path d="M9 14L4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 0 11H11"/>'),trash:C('<path d="M4 7h16"/><path d="M10 11v6M14 11v6"/><path d="M6 7l1 13h10l1-13"/><path d="M9 7V4h6v3"/>'),close:C('<path d="M6 6l12 12M18 6L6 18"/>'),paperclip:C('<path d="M21 11.5l-8.6 8.6a5.5 5.5 0 0 1-7.8-7.8l8.6-8.6a3.7 3.7 0 0 1 5.2 5.2l-8.6 8.6a1.8 1.8 0 0 1-2.6-2.6l7.9-7.9"/>'),send:C('<path d="M4 12l16-8-6 16-3-7-7-1Z"/>'),check:C('<path d="M5 12.5l4.5 4.5L19 7.5"/>')};class yn{constructor(e,n,r){this.shadow=e,this.update=n,this.onOutcome=r,this.root=null,this.settled=!1}show(e){const n=this.update,r=_("section","fk-fixcard");r.dataset.position=e,r.setAttribute("role","dialog"),r.setAttribute("aria-labelledby","fk-fixcard-title");const o=_("div","fk-fixcard-header"),s=_("h2","fk-title");s.id="fk-fixcard-title",s.textContent=n.needsVerification?"We fixed something you reported":"A question about your report";const i=document.createElement("button");if(i.type="button",i.className="fk-close",i.innerHTML=v.close,i.setAttribute("aria-label","Remind me later"),i.title="Remind me later",i.addEventListener("click",()=>this.settle({type:"later"})),o.append(s,i),r.append(o),n.needsVerification&&n.fixedInBuild&&r.append(R("p","fk-meta",`Fixed in build ${n.fixedInBuild}.`)),n.screenshotUrl){const c=document.createElement("img");c.className="fk-fixcard-shot",c.alt="Your screenshot from the original report",c.src=n.screenshotUrl,c.addEventListener("error",()=>c.remove()),r.append(c)}r.append(R("p","fk-meta","You reported")),r.append(R("p","fk-fixcard-quote",n.text?`“${n.text}”`:"(no description)")),n.needsVerification&&n.fixSummary&&r.append(R("p","fk-fixcard-summary",`What changed: ${n.fixSummary}`));for(const c of n.messages.filter(l=>l.kind==="comment")){const l=_("div","fk-fixcard-message");l.append(R("span","fk-meta",c.author),R("p","",c.body)),r.append(l)}const a=_("div","fk-fixcard-actions");if(n.needsVerification){const c=xt("fk-btn fk-btn-primary","Yes, it's fixed");c.addEventListener("click",()=>this.settle({type:"verified"}));const l=xt("fk-btn fk-btn-secondary","No, still broken");l.addEventListener("click",()=>this.settle({type:"stillBroken"})),a.append(c,l)}else if(n.openQuestion){a.append(R("p","fk-fixcard-question",n.openQuestion.body));const c=document.createElement("textarea");c.className="fk-textarea",c.placeholder="Your answer",c.setAttribute("aria-label","Your answer");const l=xt("fk-btn fk-btn-primary","Send");l.disabled=!0,c.addEventListener("input",()=>l.disabled=c.value.trim()===""),l.addEventListener("click",()=>this.settle({type:"replied",text:c.value.trim()})),a.append(c,l)}r.append(a),this.root=r,this.shadow.append(r)}dismiss(){this.settle({type:"later"})}remove(){this.settled=!0,this.root?.remove(),this.root=null}settle(e){this.settled||(this.settled=!0,this.root?.remove(),this.root=null,this.onOutcome(e))}}function _(t,e){const n=document.createElement(t);return e&&(n.className=e),n}function R(t,e,n){const r=_(t,e);return r.textContent=n,r}function xt(t,e){const n=_("button",t);return n.type="button",n.textContent=e,n}const it=4,W=16,at=18,ct=Math.PI/7,vt=16,St=8,Xt=1.19,Yt="#FF0000";function Et(t=1){return`bold ${vt*t}px -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif`}function Jt(t){if(Array.isArray(t))return{x:Number(t[0])||0,y:Number(t[1])||0};if(t&&typeof t=="object"){const e=t;return{x:Number(e.x)||0,y:Number(e.y)||0}}return{x:0,y:0}}function Ct(t,e){return(t.points??[]).map(n=>{const{x:r,y:o}=Jt(n);return{x:r*e.width,y:o*e.height}})}function Zt(t){if(!t)return Yt;const e=t.trim().replace(/^#/,"");return/^[0-9a-fA-F]{6}$/.test(e)||/^[0-9a-fA-F]{8}$/.test(e)?`#${e}`:Yt}function Tt(t,e,n){for(const r of e)At(t,r,n)}function At(t,e,n){const r=Zt(e.colorHex),o=Ct(e,n),s=e.scale??1,i=e.rotation??0;switch(e.kind){case"freehand":bn(t,o,r);break;case"rectangle":o.length===2&&wn(t,o[0],o[1],r,s,i);break;case"arrow":o.length===2&&kn(t,o[0],o[1],r,s,i);break;case"text":o.length>=1&&e.label&&xn(t,e.label,o[0],r,s);break}}function bn(t,e,n){if(e.length!==0){t.save(),t.lineWidth=it,t.lineJoin="round",t.lineCap="round",t.strokeStyle=n,t.beginPath(),t.moveTo(e[0].x,e[0].y),e.length===1&&t.lineTo(e[0].x+.01,e[0].y);for(const r of e.slice(1))t.lineTo(r.x,r.y);t.stroke(),t.restore()}}function wn(t,e,n,r,o,s){const i=K(e,n),a=te(i,Math.abs(n.x-e.x)/2*o,Math.abs(n.y-e.y)/2*o,s);t.save(),t.lineWidth=it,t.lineJoin="miter",t.strokeStyle=r,t.beginPath(),t.moveTo(a[0].x,a[0].y);for(const c of a.slice(1))t.lineTo(c.x,c.y);t.closePath(),t.stroke(),t.restore()}function kn(t,e,n,r,o,s){const{start:i,end:a,left:c,right:l}=Qt(e,n,o,s);t.save(),t.lineWidth=it,t.lineJoin="round",t.lineCap="round",t.strokeStyle=r,t.beginPath(),t.moveTo(i.x,i.y),t.lineTo(a.x,a.y),t.lineTo(c.x,c.y),t.moveTo(a.x,a.y),t.lineTo(l.x,l.y),t.stroke(),t.restore()}function Qt(t,e,n=1,r=0){const o=K(t,e),s=lt(q(t,n,o),r,o),i=lt(q(e,n,o),r,o),a=Math.atan2(i.y-s.y,i.x-s.x),c={x:i.x-at*Math.cos(a-ct),y:i.y-at*Math.sin(a-ct)},l={x:i.x-at*Math.cos(a+ct),y:i.y-at*Math.sin(a+ct)};return{start:s,end:i,left:c,right:l}}function xn(t,e,n,r,o){const s=Pt(t,e,n,o);t.save(),t.fillStyle=r,t.beginPath(),vn(t,s.x,s.y,s.width,s.height,8),t.fill(),t.font=Et(o),t.fillStyle="#FFFFFF",t.textBaseline="top",t.fillText(e,s.x+St,s.y+St+vt*o*(Xt-1)/2),t.restore()}function vn(t,e,n,r,o,s){const i=Math.min(s,r/2,o/2);t.moveTo(e+i,n),t.arcTo(e+r,n,e+r,n+o,i),t.arcTo(e+r,n+o,e,n+o,i),t.arcTo(e,n+o,e,n,i),t.arcTo(e,n,e+r,n,i),t.closePath()}function Pt(t,e,n,r=1){const o=t.font;t.font=Et(r);const s=t.measureText(e).width;t.font=o;const i=vt*r*Xt,a=St*r;return{x:n.x,y:n.y,width:s+a*2,height:i+a*2}}function te(t,e,n,r){return[{x:t.x-e,y:t.y-n},{x:t.x+e,y:t.y-n},{x:t.x+e,y:t.y+n},{x:t.x-e,y:t.y+n}].map(o=>lt(o,r,t))}function ee(t,e,n,r){const o=Ct(t,n),s=t.scale??1;switch(t.kind){case"rectangle":{if(o.length!==2)return!1;const i=K(o[0],o[1]),a=Math.abs(o[1].x-o[0].x)/2*s+W,c=Math.abs(o[1].y-o[0].y)/2*s+W;return Math.abs(e.x-i.x)<=a&&Math.abs(e.y-i.y)<=c}case"arrow":{if(o.length!==2)return!1;const i=K(o[0],o[1]);return ne(e,q(o[0],s,i),q(o[1],s,i))<=W}case"text":{if(o.length<1||!t.label)return!1;const i=Pt(r,t.label,o[0],s),a=W/2;return e.x>=i.x-a&&e.x<=i.x+i.width+a&&e.y>=i.y-a&&e.y<=i.y+i.height+a}case"freehand":return!1}}function K(t,e){return{x:(t.x+e.x)/2,y:(t.y+e.y)/2}}function lt(t,e,n){const r=t.x-n.x,o=t.y-n.y;return{x:n.x+r*Math.cos(e)-o*Math.sin(e),y:n.y+r*Math.sin(e)+o*Math.cos(e)}}function q(t,e,n){return{x:n.x+(t.x-n.x)*e,y:n.y+(t.y-n.y)*e}}function ne(t,e,n){const r=n.x-e.x,o=n.y-e.y,s=r*r+o*o;if(s===0)return Math.hypot(t.x-e.x,t.y-e.y);const i=Math.max(0,Math.min(1,((t.x-e.x)*r+(t.y-e.y)*o)/s));return Math.hypot(t.x-(e.x+i*r),t.y-(e.y+i*o))}const Sn=Object.freeze(Object.defineProperty({__proto__:null,HIT_TEST_TOLERANCE:W,STROKE_WIDTH:it,arrowGeometry:Qt,denormalize:Ct,distanceToSegment:ne,drawAnnotation:At,drawAnnotations:Tt,hitTest:ee,midpoint:K,normalizeColor:Zt,readPoint:Jt,rectangleCorners:te,rotate:lt,scaled:q,textBubbleRect:Pt,textFont:Et},Symbol.toStringTag,{value:"Module"})),re=["#FF3B30","#FFCC00","#34C759","#007AFF","#000000"],oe=.3,se=5;class En{constructor(e){this.shot=e,this.annotations=[],this.tool="pen",this.color=re[0],this.onChange=()=>{},this.history=[],this.draft=null,this.draftStart=null,this.pointers=new Map,this.drag=null,this.gesture=null,this.selected=null,this.textInput=null,this.displayScale=1,this.element=document.createElement("div"),this.element.className="fk-canvas-box",this.base=document.createElement("canvas"),this.ink=document.createElement("canvas"),this.ink.className="fk-ink",this.ink.setAttribute("role","img"),this.ink.setAttribute("aria-label","Screenshot — draw on it to highlight the problem"),this.element.append(this.base,this.ink);const n=this.ink.getContext("2d");if(!n)throw new Error("Canvas 2D is unavailable");this.inkCtx=n,this.ink.addEventListener("pointerdown",r=>this.onPointerDown(r)),this.ink.addEventListener("pointermove",r=>this.onPointerMove(r)),this.ink.addEventListener("pointerup",r=>this.onPointerUp(r)),this.ink.addEventListener("pointercancel",r=>this.onPointerUp(r)),this.ink.addEventListener("wheel",r=>this.onWheel(r),{passive:!1})}layout(e,n){const r=Math.max(.05,Math.min(e/this.shot.width,n/this.shot.height,1));this.displayScale=r;const o=Math.round(this.shot.width*r),s=Math.round(this.shot.height*r),i=window.devicePixelRatio||1;for(const c of[this.base,this.ink])c.style.width=`${o}px`,c.style.height=`${s}px`,c.width=Math.round(o*i),c.height=Math.round(s*i);const a=this.base.getContext("2d");a&&(a.imageSmoothingQuality="high",a.drawImage(this.shot.canvas,0,0,this.base.width,this.base.height)),this.cancelTextInput(),this.render()}setTool(e){this.commitTextInput(),this.tool=e,this.selected=null,this.ink.style.cursor=e==="move"?"grab":e==="text"?"text":"crosshair",this.render()}undo(){this.commitTextInput();const e=this.history.pop();e&&(this.annotations=e,this.selected=null,this.changed())}clear(){this.annotations.length!==0&&(this.snapshot(),this.annotations=[],this.selected=null,this.changed())}get canUndo(){return this.history.length>0}deleteSelected(){return this.selected===null||!this.annotations[this.selected]?!1:(this.snapshot(),this.annotations.splice(this.selected,1),this.selected=null,this.changed(),!0)}flatten(){this.commitTextInput();const e=document.createElement("canvas");e.width=this.shot.canvas.width,e.height=this.shot.canvas.height;const n=e.getContext("2d");if(!n)throw new Error("Canvas 2D is unavailable");return n.drawImage(this.shot.canvas,0,0),n.scale(e.width/this.shot.width,e.height/this.shot.height),Tt(n,this.annotations,{width:this.shot.width,height:this.shot.height}),e}commitTextInput(){const e=this.textInput;if(!e)return;this.textInput=null;const n=e.value.trim(),r=JSON.parse(e.dataset.origin??"[0,0]");e.remove(),n&&(this.snapshot(),this.annotations.push({kind:"text",points:[r],colorHex:this.color,label:n,scale:1,rotation:0}),this.changed())}cancelTextInput(){this.textInput?.remove(),this.textInput=null}render(){const e=this.inkCtx;e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,this.ink.width,this.ink.height);const n=this.ink.width/this.shot.width;e.setTransform(n,0,0,n,0,0);const r={width:this.shot.width,height:this.shot.height};Tt(e,this.annotations,r),this.draft&&At(e,this.draft,r)}changed(){this.render(),this.onChange()}snapshot(){this.history.push(this.annotations.map(e=>({...e,points:e.points.map(n=>[n[0],n[1]])}))),this.history.length>100&&this.history.shift()}toCapture(e){const n=this.ink.getBoundingClientRect();return{x:Math.max(0,Math.min(this.shot.width,(e.clientX-n.left)/this.displayScale)),y:Math.max(0,Math.min(this.shot.height,(e.clientY-n.top)/this.displayScale))}}normalize(e){return[M(e.x/this.shot.width),M(e.y/this.shot.height)]}hitIndex(e){const n={width:this.shot.width,height:this.shot.height};for(let r=this.annotations.length-1;r>=0;r--)if(ee(this.annotations[r],e,n,this.inkCtx))return r;return null}onPointerDown(e){if(e.button!==0&&e.pointerType==="mouse")return;e.preventDefault();const n=this.toCapture(e);if(this.ink.setPointerCapture(e.pointerId),this.pointers.set(e.pointerId,n),this.tool==="move"){if(this.pointers.size===2&&this.selected!==null){this.drag=null,this.startGesture();return}const o=this.hitIndex(n);this.selected=o,o!==null&&(this.snapshot(),this.drag={index:o,last:n,moved:!1},this.ink.style.cursor="grabbing");return}if(this.pointers.size>1)return;if(this.tool==="text"){this.commitTextInput(),this.openTextInput(n);return}this.draftStart=n;const r=this.normalize(n);this.draft={kind:this.tool==="pen"?"freehand":this.tool,points:this.tool==="pen"?[r]:[r,r],colorHex:this.color,scale:1,rotation:0},this.render()}onPointerMove(e){if(!this.pointers.has(e.pointerId)){this.tool==="move"&&e.pointerType==="mouse"&&(this.ink.style.cursor=this.hitIndex(this.toCapture(e))!==null?"grab":"default");return}const n=this.toCapture(e);if(this.pointers.set(e.pointerId,n),this.gesture){this.updateGesture();return}if(this.drag){const o=(n.x-this.drag.last.x)/this.shot.width,s=(n.y-this.drag.last.y)/this.shot.height;this.drag.last=n,this.drag.moved=!0;const i=this.annotations[this.drag.index];i.points=i.points.map(([a,c])=>[M(a+o),M(c+s)]),this.render();return}if(!this.draft||!this.draftStart)return;const r=this.normalize(n);if(this.draft.kind==="freehand"){const o=this.draft.points[this.draft.points.length-1];Math.hypot((r[0]-o[0])*this.shot.width,(r[1]-o[1])*this.shot.height)>=1.5&&this.draft.points.push(r)}else this.draft.points=[this.draft.points[0],r];this.render()}onPointerUp(e){if(!this.pointers.has(e.pointerId))return;if(this.pointers.delete(e.pointerId),this.ink.hasPointerCapture(e.pointerId)&&this.ink.releasePointerCapture(e.pointerId),this.gesture){this.pointers.size<2&&(this.gesture=null,this.onChange());return}if(this.drag){this.drag.moved||this.history.pop(),this.drag=null,this.ink.style.cursor="grab",this.onChange();return}const n=this.draft;this.draft=null;const r=this.draftStart;if(this.draftStart=null,!(!n||!r)){if(n.kind!=="freehand"){const[o,s]=n.points;if(Math.hypot((s[0]-o[0])*this.shot.width,(s[1]-o[1])*this.shot.height)<6){this.render();return}}this.snapshot(),this.annotations.push(n),this.changed()}}onWheel(e){if(this.tool!=="move")return;const n=this.toCapture(e),r=this.hitIndex(n)??this.selected;if(r===null||!this.annotations[r])return;e.preventDefault();const o=this.annotations[r];if(o.kind!=="freehand"){if(this.selected=r,e.shiftKey||e.altKey){if(o.kind==="text")return;const s=e.deltaY!==0?e.deltaY:e.deltaX;o.rotation=M(o.rotation+s*.004)}else o.scale=M(ie(o.scale*Math.exp(-e.deltaY*(e.ctrlKey?.01:.0015)),oe,se));this.render(),this.onChange()}}startGesture(){if(this.selected===null)return;const[e,n]=[...this.pointers.values()],r=this.annotations[this.selected];this.snapshot(),this.gesture={index:this.selected,startDistance:Math.max(1,Math.hypot(n.x-e.x,n.y-e.y)),startAngle:Math.atan2(n.y-e.y,n.x-e.x),startScale:r.scale,startRotation:r.rotation}}updateGesture(){const e=this.gesture;if(!e||this.pointers.size<2)return;const[n,r]=[...this.pointers.values()],o=this.annotations[e.index];if(!o||o.kind==="freehand")return;const s=Math.hypot(r.x-n.x,r.y-n.y);o.scale=M(ie(e.startScale*(s/e.startDistance),oe,se)),o.kind!=="text"&&(o.rotation=M(e.startRotation+(Math.atan2(r.y-n.y,r.x-n.x)-e.startAngle))),this.render()}openTextInput(e){const n=document.createElement("input");n.type="text",n.className="fk-text-input",n.placeholder="Add a note…",n.setAttribute("aria-label","Annotation text"),n.dataset.origin=JSON.stringify(this.normalize(e)),n.style.left=`${Math.min(e.x*this.displayScale,this.shot.width*this.displayScale-130)}px`,n.style.top=`${Math.min(e.y*this.displayScale,this.shot.height*this.displayScale-36)}px`,n.style.borderColor=this.color,n.addEventListener("keydown",r=>{r.stopPropagation(),r.key==="Enter"?this.commitTextInput():r.key==="Escape"&&this.cancelTextInput()}),n.addEventListener("blur",()=>this.commitTextInput()),this.element.append(n),this.textInput=n,requestAnimationFrame(()=>n.focus())}}function ie(t,e,n){return Math.max(e,Math.min(n,t))}function M(t){return Math.round(t*1e4)/1e4}const Cn=`
|
|
1
|
+
var FeedbackKit=(function(){"use strict";async function $t(t={}){const e=Math.min(window.devicePixelRatio||1,t.maxPixelRatio??2);if(t.mode==="display")try{const n=await Ze(e);if(n)return n}catch{}return Xe(e,t.exclude)}const rt="data-feedbackkit-pin";async function Xe(t,e){const n=window.innerWidth,r=window.innerHeight,o=Ye(e),s=document.documentElement,i=getComputedStyle(document.body).backgroundColor,a=getComputedStyle(s).backgroundColor,c=Bt(a)?Bt(i)?"#ffffff":i:a;try{const{domToCanvas:l}=await Promise.resolve().then(()=>Jr);return{canvas:await l(s,{width:n,height:r,scale:t,backgroundColor:c,filter:e?h=>!e(h):null,features:{restoreScrollPosition:!0},timeout:8e3,onCloneEachNode:h=>{if(!(h instanceof HTMLElement))return;h.tagName==="BODY"&&!h.style.transform&&(h.style.transform="translate(0px, 0px)");const f=h.getAttribute(rt);if(f===null)return;h.removeAttribute(rt);const u=o.info.get(f);if(!u)return;const m=h.style;u.kind==="sticky"?(m.setProperty("position","relative","important"),m.setProperty("inset","auto","important"),m.setProperty("top",`${u.top}px`,"important"),m.setProperty("left",`${u.left}px`,"important")):(m.setProperty("position","fixed","important"),m.setProperty("inset","auto","important"),m.setProperty("top",`${u.top}px`,"important"),m.setProperty("left",`${u.left}px`,"important"),m.setProperty("width",`${u.width}px`,"important"),m.setProperty("height",`${u.height}px`,"important"),m.setProperty("margin","0","important"),m.setProperty("box-sizing","border-box","important"),m.setProperty("transform","none","important"),m.setProperty("translate","none","important"))}}),width:n,height:r,pixelRatio:t}}finally{o.cleanup()}}function Ye(t){const e=new Map,n=[],r=document.body;if(!r)return{info:e,cleanup:()=>{}};const o=document.createTreeWalker(r,NodeFilter.SHOW_ELEMENT,{acceptNode:i=>t?.(i)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT});let s=0;for(let i=o.nextNode();i;i=o.nextNode()){const a=i,c=getComputedStyle(a);if(c.position!=="fixed"&&c.position!=="sticky"||c.display==="none")continue;const l=a.getBoundingClientRect(),d=String(s++);if(c.position==="sticky"){const h=a.style.getPropertyValue("position"),f=a.style.getPropertyPriority("position");a.style.setProperty("position","static","important");const u=a.getBoundingClientRect();a.style.setProperty("position",h,f),h||a.style.removeProperty("position");const m=l.top-u.top,p=l.left-u.left;if(Math.abs(p)<.5&&Math.abs(m)<.5)continue;e.set(d,{kind:"sticky",top:m,left:p,width:l.width,height:l.height})}else{const h=Je(a),f=h.getBoundingClientRect();e.set(d,{kind:"fixed",top:l.top-(f.top+h.clientTop),left:l.left-(f.left+h.clientLeft),width:l.width,height:l.height})}a.setAttribute(rt,d),n.push(a)}return{info:e,cleanup:()=>{for(const i of n)i.removeAttribute(rt)}}}function Je(t){for(let e=t.parentElement;e&&e!==document.body;e=e.parentElement){const n=getComputedStyle(e);if(n.transform!=="none"||n.filter!=="none"||n.perspective!=="none"||n.backdropFilter!==void 0&&n.backdropFilter!=="none"||/paint|layout|strict|content/.test(n.contain)||/transform|filter|perspective/.test(n.willChange))return e;const r=e.parentElement;if(r&&(r.scrollTop!==0||r.scrollLeft!==0))return e}return document.body}function Bt(t){return!t||t==="transparent"||/rgba\(\s*0,\s*0,\s*0,\s*0\s*\)/.test(t)}async function Ze(t){if(!navigator.mediaDevices?.getDisplayMedia)return null;const e={video:{displaySurface:"browser"},audio:!1,preferCurrentTab:!0,selfBrowserSurface:"include"},n=await navigator.mediaDevices.getDisplayMedia(e);try{const r=document.createElement("video");r.muted=!0,r.playsInline=!0,r.srcObject=n,await r.play(),await new Promise(c=>setTimeout(c,250));const o=window.innerWidth,s=window.innerHeight,i=document.createElement("canvas");i.width=Math.round(o*t),i.height=Math.round(s*t);const a=i.getContext("2d");return a?(a.drawImage(r,0,0,i.width,i.height),{canvas:i,width:o,height:s,pixelRatio:t}):null}finally{for(const r of n.getTracks())r.stop()}}function yt(t){return new Promise((e,n)=>{t.toBlob(r=>r?e(r):n(new Error("Failed to encode screenshot")),"image/png")})}function Qe(t){let e="Unknown",n="",r;(r=t.match(/(?:iPhone|iPad|iPod).*?OS (\d+[_.\d]*)/))?(e=/iPad/.test(t)?"iPadOS":"iOS",n=r[1].replace(/_/g,".")):(r=t.match(/Android (\d+(?:\.\d+)*)/))?(e="Android",n=r[1]):(r=t.match(/Windows NT (\d+\.\d+)/))?(e="Windows",n={"10.0":"10","6.3":"8.1","6.2":"8","6.1":"7"}[r[1]]??r[1]):(r=t.match(/Mac OS X (\d+[_.\d]*)/))?(e="macOS",n=r[1].replace(/_/g,".")):/CrOS/.test(t)?e="ChromeOS":/Linux/.test(t)&&(e="Linux");let o="Unknown",s="";const i=[["Edge",/Edg(?:e|A|iOS)?\/([\d.]+)/],["Opera",/(?:OPR|Opera)\/([\d.]+)/],["Samsung Internet",/SamsungBrowser\/([\d.]+)/],["Firefox",/(?:Firefox|FxiOS)\/([\d.]+)/],["Chrome",/(?:Chrome|CriOS)\/([\d.]+)/],["Safari",/Version\/([\d.]+).*Safari/]];for(const[a,c]of i){const l=t.match(c);if(l){o=a,s=l[1];break}}return{osName:e,osVersion:n,browserName:o,browserVersion:s}}const Ot=/token|secret|password|passwd|pwd|auth|session|key|code|signature|sig|jwt|otp|email/i;function Ut(t){try{const e=new URL(t);for(const n of[...e.searchParams.keys()])Ot.test(n)&&e.searchParams.set(n,"[redacted]");return e.hash&&Ot.test(e.hash)&&(e.hash="#[redacted]"),e.toString()}catch{return t}}async function tn(){const t=navigator.userAgentData;if(!t?.getHighEntropyValues)return null;try{return await Promise.race([t.getHighEntropyValues(["platform","platformVersion","fullVersionList"]),new Promise(e=>setTimeout(()=>e(null),300))])}catch{return null}}function en(t,e){const n=t.platform,r=t.platformVersion??"";if(!n)return e;if(n==="macOS")return{osName:"macOS",osVersion:ot(r)};if(n==="Windows"){const o=parseInt(r,10);return{osName:"Windows",osVersion:o>=13?"11":o>0?"10":e.osVersion}}return n==="Android"?{osName:"Android",osVersion:ot(r)||e.osVersion}:n==="Chrome OS"||n==="ChromeOS"?{osName:"ChromeOS",osVersion:ot(r)}:{osName:n,osVersion:ot(r)||e.osVersion}}function ot(t){return t.replace(/(\.0)+$/,"")}function nn(t){const e=t.fullVersionList??[],n=["Microsoft Edge","Opera","Google Chrome","Chromium"];for(const r of n){const o=e.find(s=>s.brand===r);if(o)return{name:r==="Microsoft Edge"?"Edge":r==="Google Chrome"?"Chrome":r,version:o.version}}return null}async function rn(t={}){const e=navigator.userAgent,n=Qe(e),r=await tn(),o=r?en(r,n):n,s=r&&nn(r)||{name:n.browserName,version:n.browserVersion},i=s.version.split(".")[0];return{osName:o.osName,osVersion:o.osVersion,deviceModel:i?`${s.name} ${i}`:s.name,appVersion:t.appVersion??"",appBuild:t.appBuild??"",bundleIdentifier:location.host,screenName:t.screenName||location.pathname||null,locale:navigator.language||"en",screenWidthPoints:window.innerWidth,screenHeightPoints:window.innerHeight,screenScale:window.devicePixelRatio||1,platform:"web",pageUrl:Ut(location.href),userAgent:e,browserName:s.name,browserVersion:s.version}}const jt=1e3;function on(t){return t.replace(/\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]+/gi,"$1 [redacted]").replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g,"[redacted-jwt]").replace(/https?:\/\/[^\s"'<>)]+/g,e=>Ut(e)).replace(/("?(?:password|passwd|secret|token|api[_-]?key|access[_-]?token|refresh[_-]?token)"?\s*[:=]\s*)("[^"]*"|'[^']*'|[^\s,}&]+)/gi,"$1[redacted]")}function st(t){if(typeof t=="string")return t;if(t instanceof Error)return t.stack||`${t.name}: ${t.message}`;if(t===void 0)return"undefined";if(typeof t=="function")return`[function ${t.name||"anonymous"}]`;if(typeof Element<"u"&&t instanceof Element)return`<${t.tagName.toLowerCase()}>`;try{const e=new WeakSet;return JSON.stringify(t,(n,r)=>{if(typeof r=="object"&&r!==null){if(e.has(r))return"[circular]";e.add(r)}return typeof r=="bigint"?r.toString():r})}catch{return String(t)}}class sn{constructor(e=50){this.maxEntries=e,this.entries=[]}push(e,n){let r=on(n);r.length>jt&&(r=`${r.slice(0,jt)}… [truncated]`),this.entries.push({level:e,message:r,timestamp:new Date().toISOString()}),this.entries.length>this.maxEntries&&this.entries.splice(0,this.entries.length-this.maxEntries)}snapshot(){return this.entries.slice()}clear(){this.entries=[]}}function an(t={}){const e=new sn(t.maxEntries??50),n=[],r=t.includeVerbose?["log","info","warn","error","debug"]:["warn","error"];for(const i of r){const a=console[i];console[i]=function(...c){try{e.push(i,c.map(st).join(" "))}catch{}return a.apply(this,c)},n.push(()=>{console[i]=a})}const o=i=>{const a=i.filename?` (${i.filename}:${i.lineno}:${i.colno})`:"";e.push("error",`Uncaught ${i.error?st(i.error):i.message}${a}`)},s=i=>{e.push("error",`Unhandled promise rejection: ${st(i.reason)}`)};return window.addEventListener("error",o),window.addEventListener("unhandledrejection",s),n.push(()=>{window.removeEventListener("error",o),window.removeEventListener("unhandledrejection",s)}),t.network!==!1&&n.push(ln(e),dn(e)),{buffer:e,uninstall:()=>{for(const i of n.reverse())i()}}}let bt=null;function cn(t){bt=t}function wt(t){return!!bt&&t.startsWith(bt)}function ln(t){if(typeof window.fetch!="function")return()=>{};const e=window.fetch;return window.fetch=async function(n,r){const o=(r?.method||(n instanceof Request?n.method:"GET")).toUpperCase(),s=n instanceof Request?n.url:String(n);try{const i=await e.call(window,n,r);return i.status>=400&&!wt(s)&&t.push("network",`${o} ${s} → ${i.status} ${i.statusText}`.trim()),i}catch(i){throw!wt(s)&&!(i instanceof DOMException&&i.name==="AbortError")&&t.push("network",`${o} ${s} → failed: ${st(i)}`),i}},()=>{window.fetch=e}}function dn(t){if(typeof XMLHttpRequest>"u")return()=>{};const e=XMLHttpRequest.prototype,n=e.open,r=e.send,o=new WeakMap;return e.open=function(s,i,...a){return o.set(this,{method:String(s).toUpperCase(),url:String(i)}),n.call(this,s,i,...a)},e.send=function(s){return this.addEventListener("loadend",()=>{const i=o.get(this);!i||wt(i.url)||(this.status===0?t.push("network",`${i.method} ${i.url} → failed (network error)`):this.status>=400&&t.push("network",`${i.method} ${i.url} → ${this.status} ${this.statusText}`.trim()))}),r.call(this,s)},()=>{e.open=n,e.send=r}}const j="https://gpucoladcyvijefdjudf.supabase.co/functions/v1/ingest-feedback";class I extends Error{constructor(e,n,r){super(e),this.kind=n,this.status=r,this.name="FeedbackSubmissionError"}}async function H(t){const e=new Uint8Array(await t.arrayBuffer());let n="";const r=32768;for(let o=0;o<e.length;o+=r)n+=String.fromCharCode(...e.subarray(o,o+r));return btoa(n)}async function hn(t,e,n={}){const r={project_key:e,id:t.id,created_at:t.createdAt.toISOString(),text:t.text,annotations:t.annotations,environment:t.environment};if(t.screenshotRaw&&t.screenshotAnnotated){const[o,s]=await Promise.all([H(t.screenshotRaw),H(t.screenshotAnnotated)]);r.screenshot_raw_png_base64=o,r.screenshot_annotated_png_base64=s}return t.attachment&&(r.attachment_filename=t.attachment.filename,r.attachment_mime_type=t.attachment.mimeType,r.attachment_data_base64=await H(t.attachment.data)),t.products.length>0&&(r.product_keys=t.products.map(o=>o.key),r.products=t.products.map(o=>({key:o.key,name:o.name,description:o.description??"",is_default:o.isDefault??!1}))),t.logs.length>0&&(r.logs=t.logs),n.reporterId&&(r.reporter_id=n.reporterId),n.user&&(r.reporter=n.user),r}async function Ht(t,e,n={}){if(!e.projectKey)throw new I("FeedbackKit is not configured with a project key.","not_configured");const r=JSON.stringify(await hn(t,e.projectKey,n));let o;try{o=await fetch(e.endpoint??j,{method:"POST",headers:{"Content-Type":"application/json"},body:r})}catch(s){throw new I(`Network error: ${s instanceof Error?s.message:String(s)}`,"network")}if(!o.ok){let s="";try{s=(await o.json()).error??""}catch{}const i=s?` (${s})`:"",a=s==="origin_not_allowed"?`This site (${location.origin}) isn't in the project's allowed origins.`:o.status===401||o.status===403?`Server rejected the project key or origin (HTTP ${o.status})${i}.`:o.status===429?"Too many reports right now — please try again in a minute.":o.status===402?"Feedback for this site is paused this month. Please try again later.":`Server returned HTTP ${o.status}${i}.`;throw new I(a,"server",o.status)}}async function un(t){const e=new URL(t.endpoint??j);e.searchParams.set("project_key",t.projectKey);const n=await fetch(e.toString());if(!n.ok)throw new I(`HTTP ${n.status}`,"server",n.status);return((await n.json()).products??[]).map(o=>({key:o.key,name:o.name,description:o.description??"",isDefault:o.is_default??!1}))}const Vt="feedbackkit.reporterId",fn=/^[A-Za-z0-9_-]{16,128}$/;let V=null,zt=null;function Wt(){const t=new Uint8Array(16);return crypto.getRandomValues(t),[...t].map(e=>e.toString(16).padStart(2,"0")).join("")}function z(){if(V)return V;try{const t=localStorage.getItem(Vt);if(t&&fn.test(t))return V=t;const e=Wt();return localStorage.setItem(Vt,e),V=e}catch{return V=Wt()}}function pn(t){zt=t&&(t.id||t.email||t.name)?{...t}:null}function Kt(){return zt}function qt(t){if(t.reporterUpdatesEndpoint)return t.reporterUpdatesEndpoint;const e=new URL(t.endpoint??j);return e.pathname=e.pathname.replace(/\/[^/]*\/?$/,"/reporter-updates"),e.search="",e.toString()}function mn(t){return{feedbackId:t.feedback_id,text:t.text??"",createdAt:t.created_at??"",screenName:t.screen_name??null,fixStage:t.fix_stage??null,fixedInBuild:t.fixed_in_build??null,fixSummary:t.fix_summary??null,needsVerification:t.needs_verification??!1,openQuestion:t.open_question?{id:t.open_question.id,body:t.open_question.body,createdAt:t.open_question.created_at}:null,screenshotUrl:t.screenshot_url??null,messages:(t.messages??[]).map(e=>({id:e.id,kind:e.kind,body:e.body,author:e.author,createdAt:e.created_at}))}}async function Gt(t){const e=new URL(qt(t));e.searchParams.set("project_key",t.projectKey),e.searchParams.set("reporter_id",z()),t.appBuild&&e.searchParams.set("build",t.appBuild);let n;try{n=await fetch(e.toString())}catch(o){throw new I(`Network error: ${o instanceof Error?o.message:String(o)}`,"network")}if(!n.ok)throw new I(`HTTP ${n.status}`,"server",n.status);return((await n.json()).updates??[]).map(mn)}async function gn(t,e,n){const r={project_key:t.projectKey,reporter_id:z(),feedback_id:e,action:n.type};if(t.appBuild&&(r.build=t.appBuild),n.type==="reply"&&(r.text=n.text),n.type==="reopen"){const o=n.report,s=o?.text??n.text;s&&(r.text=s),o?.screenshotAnnotated&&(r.screenshot_annotated_png_base64=await H(o.screenshotAnnotated),o.screenshotRaw&&(r.screenshot_raw_png_base64=await H(o.screenshotRaw)),r.annotations=o.annotations)}return r}async function kt(t,e,n){const r=JSON.stringify(await gn(t,e,n));let o;try{o=await fetch(qt(t),{method:"POST",headers:{"Content-Type":"application/json"},body:r})}catch(s){throw new I(`Network error: ${s instanceof Error?s.message:String(s)}`,"network")}if(!o.ok)throw new I(`HTTP ${o.status}`,"server",o.status)}const C=t=>`<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${t}</svg>`,v={feedback:C('<path d="M21 12a8 8 0 0 1-11.6 7.1L4 20l1-4.6A8 8 0 1 1 21 12Z"/><path d="M8.5 10.5h7M8.5 14h4.5"/>'),pen:C('<path d="M4 20l4-1L19 8a2.1 2.1 0 0 0-3-3L5 16l-1 4Z"/><path d="M14.5 6.5l3 3"/>'),rectangle:C('<rect x="4" y="6" width="16" height="12" rx="1.5"/>'),arrow:C('<path d="M6 18L18 6"/><path d="M9 6h9v9"/>'),text:C('<path d="M5 6V5h14v1"/><path d="M12 5v14"/><path d="M9 19h6"/>'),move:C('<path d="M12 3v18M3 12h18"/><path d="M9 6l3-3 3 3M9 18l3 3 3-3M6 9l-3 3 3 3M18 9l3 3-3 3"/>'),undo:C('<path d="M9 14L4 9l5-5"/><path d="M4 9h10.5a5.5 5.5 0 0 1 0 11H11"/>'),trash:C('<path d="M4 7h16"/><path d="M10 11v6M14 11v6"/><path d="M6 7l1 13h10l1-13"/><path d="M9 7V4h6v3"/>'),close:C('<path d="M6 6l12 12M18 6L6 18"/>'),paperclip:C('<path d="M21 11.5l-8.6 8.6a5.5 5.5 0 0 1-7.8-7.8l8.6-8.6a3.7 3.7 0 0 1 5.2 5.2l-8.6 8.6a1.8 1.8 0 0 1-2.6-2.6l7.9-7.9"/>'),send:C('<path d="M4 12l16-8-6 16-3-7-7-1Z"/>'),check:C('<path d="M5 12.5l4.5 4.5L19 7.5"/>')};class yn{constructor(e,n,r){this.shadow=e,this.update=n,this.onOutcome=r,this.root=null,this.settled=!1}show(e){const n=this.update,r=_("section","fk-fixcard");r.dataset.position=e,r.setAttribute("role","dialog"),r.setAttribute("aria-labelledby","fk-fixcard-title");const o=_("div","fk-fixcard-header"),s=_("h2","fk-title");s.id="fk-fixcard-title",s.textContent=n.needsVerification?"We fixed something you reported":"A question about your report";const i=document.createElement("button");if(i.type="button",i.className="fk-close",i.innerHTML=v.close,i.setAttribute("aria-label","Remind me later"),i.title="Remind me later",i.addEventListener("click",()=>this.settle({type:"later"})),o.append(s,i),r.append(o),n.needsVerification&&n.fixedInBuild&&r.append(R("p","fk-meta",`Fixed in build ${n.fixedInBuild}.`)),n.screenshotUrl){const c=document.createElement("img");c.className="fk-fixcard-shot",c.alt="Your screenshot from the original report",c.src=n.screenshotUrl,c.addEventListener("error",()=>c.remove()),r.append(c)}r.append(R("p","fk-meta","You reported")),r.append(R("p","fk-fixcard-quote",n.text?`“${n.text}”`:"(no description)")),n.needsVerification&&n.fixSummary&&r.append(R("p","fk-fixcard-summary",`What changed: ${n.fixSummary}`));for(const c of n.messages.filter(l=>l.kind==="comment")){const l=_("div","fk-fixcard-message");l.append(R("span","fk-meta",c.author),R("p","",c.body)),r.append(l)}const a=_("div","fk-fixcard-actions");if(n.needsVerification){const c=xt("fk-btn fk-btn-primary","Yes, it's fixed");c.addEventListener("click",()=>this.settle({type:"verified"}));const l=xt("fk-btn fk-btn-secondary","No, still broken");l.addEventListener("click",()=>this.settle({type:"stillBroken"})),a.append(c,l)}else if(n.openQuestion){a.append(R("p","fk-fixcard-question",n.openQuestion.body));const c=document.createElement("textarea");c.className="fk-textarea",c.placeholder="Your answer",c.setAttribute("aria-label","Your answer");const l=xt("fk-btn fk-btn-primary","Send");l.disabled=!0,c.addEventListener("input",()=>l.disabled=c.value.trim()===""),l.addEventListener("click",()=>this.settle({type:"replied",text:c.value.trim()})),a.append(c,l)}r.append(a),this.root=r,this.shadow.append(r)}dismiss(){this.settle({type:"later"})}remove(){this.settled=!0,this.root?.remove(),this.root=null}settle(e){this.settled||(this.settled=!0,this.root?.remove(),this.root=null,this.onOutcome(e))}}function _(t,e){const n=document.createElement(t);return e&&(n.className=e),n}function R(t,e,n){const r=_(t,e);return r.textContent=n,r}function xt(t,e){const n=_("button",t);return n.type="button",n.textContent=e,n}const it=4,W=16,at=18,ct=Math.PI/7,vt=16,St=8,Xt=1.19,Yt="#FF0000";function Et(t=1){return`bold ${vt*t}px -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif`}function Jt(t){if(Array.isArray(t))return{x:Number(t[0])||0,y:Number(t[1])||0};if(t&&typeof t=="object"){const e=t;return{x:Number(e.x)||0,y:Number(e.y)||0}}return{x:0,y:0}}function Ct(t,e){return(t.points??[]).map(n=>{const{x:r,y:o}=Jt(n);return{x:r*e.width,y:o*e.height}})}function Zt(t){if(!t)return Yt;const e=t.trim().replace(/^#/,"");return/^[0-9a-fA-F]{6}$/.test(e)||/^[0-9a-fA-F]{8}$/.test(e)?`#${e}`:Yt}function Tt(t,e,n){for(const r of e)At(t,r,n)}function At(t,e,n){const r=Zt(e.colorHex),o=Ct(e,n),s=e.scale??1,i=e.rotation??0;switch(e.kind){case"freehand":bn(t,o,r);break;case"rectangle":o.length===2&&wn(t,o[0],o[1],r,s,i);break;case"arrow":o.length===2&&kn(t,o[0],o[1],r,s,i);break;case"text":o.length>=1&&e.label&&xn(t,e.label,o[0],r,s);break}}function bn(t,e,n){if(e.length!==0){t.save(),t.lineWidth=it,t.lineJoin="round",t.lineCap="round",t.strokeStyle=n,t.beginPath(),t.moveTo(e[0].x,e[0].y),e.length===1&&t.lineTo(e[0].x+.01,e[0].y);for(const r of e.slice(1))t.lineTo(r.x,r.y);t.stroke(),t.restore()}}function wn(t,e,n,r,o,s){const i=K(e,n),a=te(i,Math.abs(n.x-e.x)/2*o,Math.abs(n.y-e.y)/2*o,s);t.save(),t.lineWidth=it,t.lineJoin="miter",t.strokeStyle=r,t.beginPath(),t.moveTo(a[0].x,a[0].y);for(const c of a.slice(1))t.lineTo(c.x,c.y);t.closePath(),t.stroke(),t.restore()}function kn(t,e,n,r,o,s){const{start:i,end:a,left:c,right:l}=Qt(e,n,o,s);t.save(),t.lineWidth=it,t.lineJoin="round",t.lineCap="round",t.strokeStyle=r,t.beginPath(),t.moveTo(i.x,i.y),t.lineTo(a.x,a.y),t.lineTo(c.x,c.y),t.moveTo(a.x,a.y),t.lineTo(l.x,l.y),t.stroke(),t.restore()}function Qt(t,e,n=1,r=0){const o=K(t,e),s=lt(q(t,n,o),r,o),i=lt(q(e,n,o),r,o),a=Math.atan2(i.y-s.y,i.x-s.x),c={x:i.x-at*Math.cos(a-ct),y:i.y-at*Math.sin(a-ct)},l={x:i.x-at*Math.cos(a+ct),y:i.y-at*Math.sin(a+ct)};return{start:s,end:i,left:c,right:l}}function xn(t,e,n,r,o){const s=Pt(t,e,n,o);t.save(),t.fillStyle=r,t.beginPath(),vn(t,s.x,s.y,s.width,s.height,8),t.fill(),t.font=Et(o),t.fillStyle="#FFFFFF",t.textBaseline="top",t.fillText(e,s.x+St,s.y+St+vt*o*(Xt-1)/2),t.restore()}function vn(t,e,n,r,o,s){const i=Math.min(s,r/2,o/2);t.moveTo(e+i,n),t.arcTo(e+r,n,e+r,n+o,i),t.arcTo(e+r,n+o,e,n+o,i),t.arcTo(e,n+o,e,n,i),t.arcTo(e,n,e+r,n,i),t.closePath()}function Pt(t,e,n,r=1){const o=t.font;t.font=Et(r);const s=t.measureText(e).width;t.font=o;const i=vt*r*Xt,a=St*r;return{x:n.x,y:n.y,width:s+a*2,height:i+a*2}}function te(t,e,n,r){return[{x:t.x-e,y:t.y-n},{x:t.x+e,y:t.y-n},{x:t.x+e,y:t.y+n},{x:t.x-e,y:t.y+n}].map(o=>lt(o,r,t))}function ee(t,e,n,r){const o=Ct(t,n),s=t.scale??1;switch(t.kind){case"rectangle":{if(o.length!==2)return!1;const i=K(o[0],o[1]),a=Math.abs(o[1].x-o[0].x)/2*s+W,c=Math.abs(o[1].y-o[0].y)/2*s+W;return Math.abs(e.x-i.x)<=a&&Math.abs(e.y-i.y)<=c}case"arrow":{if(o.length!==2)return!1;const i=K(o[0],o[1]);return ne(e,q(o[0],s,i),q(o[1],s,i))<=W}case"text":{if(o.length<1||!t.label)return!1;const i=Pt(r,t.label,o[0],s),a=W/2;return e.x>=i.x-a&&e.x<=i.x+i.width+a&&e.y>=i.y-a&&e.y<=i.y+i.height+a}case"freehand":return!1}}function K(t,e){return{x:(t.x+e.x)/2,y:(t.y+e.y)/2}}function lt(t,e,n){const r=t.x-n.x,o=t.y-n.y;return{x:n.x+r*Math.cos(e)-o*Math.sin(e),y:n.y+r*Math.sin(e)+o*Math.cos(e)}}function q(t,e,n){return{x:n.x+(t.x-n.x)*e,y:n.y+(t.y-n.y)*e}}function ne(t,e,n){const r=n.x-e.x,o=n.y-e.y,s=r*r+o*o;if(s===0)return Math.hypot(t.x-e.x,t.y-e.y);const i=Math.max(0,Math.min(1,((t.x-e.x)*r+(t.y-e.y)*o)/s));return Math.hypot(t.x-(e.x+i*r),t.y-(e.y+i*o))}const Sn=Object.freeze(Object.defineProperty({__proto__:null,HIT_TEST_TOLERANCE:W,STROKE_WIDTH:it,arrowGeometry:Qt,denormalize:Ct,distanceToSegment:ne,drawAnnotation:At,drawAnnotations:Tt,hitTest:ee,midpoint:K,normalizeColor:Zt,readPoint:Jt,rectangleCorners:te,rotate:lt,scaled:q,textBubbleRect:Pt,textFont:Et},Symbol.toStringTag,{value:"Module"})),re=["#FF3B30","#FFCC00","#34C759","#007AFF","#000000"],oe=.3,se=5;class En{constructor(e){this.shot=e,this.annotations=[],this.tool="pen",this.color=re[0],this.onChange=()=>{},this.history=[],this.draft=null,this.draftStart=null,this.pointers=new Map,this.drag=null,this.gesture=null,this.selected=null,this.textInput=null,this.displayScale=1,this.element=document.createElement("div"),this.element.className="fk-canvas-box",this.base=document.createElement("canvas"),this.ink=document.createElement("canvas"),this.ink.className="fk-ink",this.ink.setAttribute("role","img"),this.ink.setAttribute("aria-label","Screenshot — draw on it to highlight the problem"),this.element.append(this.base,this.ink);const n=this.ink.getContext("2d");if(!n)throw new Error("Canvas 2D is unavailable");this.inkCtx=n,this.ink.addEventListener("pointerdown",r=>this.onPointerDown(r)),this.ink.addEventListener("pointermove",r=>this.onPointerMove(r)),this.ink.addEventListener("pointerup",r=>this.onPointerUp(r)),this.ink.addEventListener("pointercancel",r=>this.onPointerUp(r)),this.ink.addEventListener("wheel",r=>this.onWheel(r),{passive:!1})}layout(e,n){const r=Math.max(.05,Math.min(e/this.shot.width,n/this.shot.height,1));this.displayScale=r;const o=Math.round(this.shot.width*r),s=Math.round(this.shot.height*r),i=window.devicePixelRatio||1;for(const c of[this.base,this.ink])c.style.width=`${o}px`,c.style.height=`${s}px`,c.width=Math.round(o*i),c.height=Math.round(s*i);const a=this.base.getContext("2d");a&&(a.imageSmoothingQuality="high",a.drawImage(this.shot.canvas,0,0,this.base.width,this.base.height)),this.cancelTextInput(),this.render()}setTool(e){this.commitTextInput(),this.tool=e,this.selected=null,this.ink.style.cursor=e==="move"?"grab":e==="text"?"text":"crosshair",this.render()}undo(){this.commitTextInput();const e=this.history.pop();e&&(this.annotations=e,this.selected=null,this.changed())}clear(){this.annotations.length!==0&&(this.snapshot(),this.annotations=[],this.selected=null,this.changed())}get canUndo(){return this.history.length>0}deleteSelected(){return this.selected===null||!this.annotations[this.selected]?!1:(this.snapshot(),this.annotations.splice(this.selected,1),this.selected=null,this.changed(),!0)}flatten(){this.commitTextInput();const e=document.createElement("canvas");e.width=this.shot.canvas.width,e.height=this.shot.canvas.height;const n=e.getContext("2d");if(!n)throw new Error("Canvas 2D is unavailable");return n.drawImage(this.shot.canvas,0,0),n.scale(e.width/this.shot.width,e.height/this.shot.height),Tt(n,this.annotations,{width:this.shot.width,height:this.shot.height}),e}commitTextInput(){const e=this.textInput;if(!e)return;this.textInput=null;const n=e.value.trim(),r=JSON.parse(e.dataset.origin??"[0,0]");e.remove(),n&&(this.snapshot(),this.annotations.push({kind:"text",points:[r],colorHex:this.color,label:n,scale:1,rotation:0}),this.changed())}cancelTextInput(){this.textInput?.remove(),this.textInput=null}render(){const e=this.inkCtx;e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,this.ink.width,this.ink.height);const n=this.ink.width/this.shot.width;e.setTransform(n,0,0,n,0,0);const r={width:this.shot.width,height:this.shot.height};Tt(e,this.annotations,r),this.draft&&At(e,this.draft,r)}changed(){this.render(),this.onChange()}snapshot(){this.history.push(this.annotations.map(e=>({...e,points:e.points.map(n=>[n[0],n[1]])}))),this.history.length>100&&this.history.shift()}toCapture(e){const n=this.ink.getBoundingClientRect();return{x:Math.max(0,Math.min(this.shot.width,(e.clientX-n.left)/this.displayScale)),y:Math.max(0,Math.min(this.shot.height,(e.clientY-n.top)/this.displayScale))}}normalize(e){return[M(e.x/this.shot.width),M(e.y/this.shot.height)]}hitIndex(e){const n={width:this.shot.width,height:this.shot.height};for(let r=this.annotations.length-1;r>=0;r--)if(ee(this.annotations[r],e,n,this.inkCtx))return r;return null}onPointerDown(e){if(e.button!==0&&e.pointerType==="mouse")return;e.preventDefault();const n=this.toCapture(e);if(this.ink.setPointerCapture(e.pointerId),this.pointers.set(e.pointerId,n),this.tool==="move"){if(this.pointers.size===2&&this.selected!==null){this.drag=null,this.startGesture();return}const o=this.hitIndex(n);this.selected=o,o!==null&&(this.snapshot(),this.drag={index:o,last:n,moved:!1},this.ink.style.cursor="grabbing");return}if(this.pointers.size>1)return;if(this.tool==="text"){this.commitTextInput(),this.openTextInput(n);return}this.draftStart=n;const r=this.normalize(n);this.draft={kind:this.tool==="pen"?"freehand":this.tool,points:this.tool==="pen"?[r]:[r,r],colorHex:this.color,scale:1,rotation:0},this.render()}onPointerMove(e){if(!this.pointers.has(e.pointerId)){this.tool==="move"&&e.pointerType==="mouse"&&(this.ink.style.cursor=this.hitIndex(this.toCapture(e))!==null?"grab":"default");return}const n=this.toCapture(e);if(this.pointers.set(e.pointerId,n),this.gesture){this.updateGesture();return}if(this.drag){const o=(n.x-this.drag.last.x)/this.shot.width,s=(n.y-this.drag.last.y)/this.shot.height;this.drag.last=n,this.drag.moved=!0;const i=this.annotations[this.drag.index];i.points=i.points.map(([a,c])=>[M(a+o),M(c+s)]),this.render();return}if(!this.draft||!this.draftStart)return;const r=this.normalize(n);if(this.draft.kind==="freehand"){const o=this.draft.points[this.draft.points.length-1];Math.hypot((r[0]-o[0])*this.shot.width,(r[1]-o[1])*this.shot.height)>=1.5&&this.draft.points.push(r)}else this.draft.points=[this.draft.points[0],r];this.render()}onPointerUp(e){if(!this.pointers.has(e.pointerId))return;if(this.pointers.delete(e.pointerId),this.ink.hasPointerCapture(e.pointerId)&&this.ink.releasePointerCapture(e.pointerId),this.gesture){this.pointers.size<2&&(this.gesture=null,this.onChange());return}if(this.drag){this.drag.moved||this.history.pop(),this.drag=null,this.ink.style.cursor="grab",this.onChange();return}const n=this.draft;this.draft=null;const r=this.draftStart;if(this.draftStart=null,!(!n||!r)){if(n.kind!=="freehand"){const[o,s]=n.points;if(Math.hypot((s[0]-o[0])*this.shot.width,(s[1]-o[1])*this.shot.height)<6){this.render();return}}this.snapshot(),this.annotations.push(n),this.changed()}}onWheel(e){if(this.tool!=="move")return;const n=this.toCapture(e),r=this.hitIndex(n)??this.selected;if(r===null||!this.annotations[r])return;e.preventDefault();const o=this.annotations[r];if(o.kind!=="freehand"){if(this.selected=r,e.shiftKey||e.altKey){if(o.kind==="text")return;const s=e.deltaY!==0?e.deltaY:e.deltaX;o.rotation=M(o.rotation+s*.004)}else o.scale=M(ie(o.scale*Math.exp(-e.deltaY*(e.ctrlKey?.01:.0015)),oe,se));this.render(),this.onChange()}}startGesture(){if(this.selected===null)return;const[e,n]=[...this.pointers.values()],r=this.annotations[this.selected];this.snapshot(),this.gesture={index:this.selected,startDistance:Math.max(1,Math.hypot(n.x-e.x,n.y-e.y)),startAngle:Math.atan2(n.y-e.y,n.x-e.x),startScale:r.scale,startRotation:r.rotation}}updateGesture(){const e=this.gesture;if(!e||this.pointers.size<2)return;const[n,r]=[...this.pointers.values()],o=this.annotations[e.index];if(!o||o.kind==="freehand")return;const s=Math.hypot(r.x-n.x,r.y-n.y);o.scale=M(ie(e.startScale*(s/e.startDistance),oe,se)),o.kind!=="text"&&(o.rotation=M(e.startRotation+(Math.atan2(r.y-n.y,r.x-n.x)-e.startAngle))),this.render()}openTextInput(e){const n=document.createElement("input");n.type="text",n.className="fk-text-input",n.placeholder="Add a note…",n.setAttribute("aria-label","Annotation text"),n.dataset.origin=JSON.stringify(this.normalize(e)),n.style.left=`${Math.min(e.x*this.displayScale,this.shot.width*this.displayScale-130)}px`,n.style.top=`${Math.min(e.y*this.displayScale,this.shot.height*this.displayScale-36)}px`,n.style.borderColor=this.color,n.addEventListener("keydown",r=>{r.stopPropagation(),r.key==="Enter"?this.commitTextInput():r.key==="Escape"&&this.cancelTextInput()}),n.addEventListener("blur",()=>this.commitTextInput()),this.element.append(n),this.textInput=n,requestAnimationFrame(()=>n.focus())}}function ie(t,e,n){return Math.max(e,Math.min(n,t))}function M(t){return Math.round(t*1e4)/1e4}const Cn=`
|
|
2
2
|
:host {
|
|
3
3
|
all: initial;
|
|
4
4
|
--fk-primary: #007aff;
|