@siteping/widget 0.9.4 → 0.9.5

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.
@@ -128,7 +128,7 @@
128
128
  border-radius:8px;
129
129
  box-shadow:0 0 16px ${this.colors.accentGlow};
130
130
  transition:box-shadow 0.15s ease;
131
- `}),this.overlay?.appendChild(this.drawingRect)}onMouseMove=e=>{this.scheduleRectUpdate(e)};onTouchMove=e=>{e.preventDefault(),e.touches[0]&&this.scheduleRectUpdate(e.touches[0])};scheduleRectUpdate(e){!this.isDrawing||!this.drawingRect||(this.pendingMoveEvent=e,this.rafId===null&&(this.rafId=requestAnimationFrame(()=>{this.rafId=null;let n=this.pendingMoveEvent;if(!n||!this.drawingRect)return;let i=Math.min(n.clientX,this.startX),s=Math.min(n.clientY,this.startY),o=Math.abs(n.clientX-this.startX),r=Math.abs(n.clientY-this.startY);this.drawingRect.style.left=`${i}px`,this.drawingRect.style.top=`${s}px`,this.drawingRect.style.width=`${o}px`,this.drawingRect.style.height=`${r}px`})))}onTouchEnd=async e=>{let n=e.changedTouches[0];n&&await this.finishDrawing(n.clientX,n.clientY)};onMouseUp=async e=>{await this.finishDrawing(e.clientX,e.clientY)};finishDrawing=async(e,n)=>{if(!this.isDrawing||!this.drawingRect)return;this.isDrawing=!1;let i=Math.min(e,this.startX),s=Math.min(n,this.startY),o=Math.abs(e-this.startX),r=Math.abs(n-this.startY);if(o<10||r<10){this.drawingRect.remove(),this.drawingRect=null;return}let a=new DOMRect(i,s,o,r),l=await this.popup.show(a);if(!l){this.drawingRect?.remove(),this.drawingRect=null;return}let c=this.buildAnnotation(a);this.drawingRect?.remove(),this.drawingRect=null,this.deactivate(),this.bus.emit("annotation:complete",{annotation:c,type:l.type,message:l.message})};buildAnnotation(e){this.overlay&&(this.overlay.style.pointerEvents="none");let n=De(e);this.overlay&&(this.overlay.style.pointerEvents="auto");let i=ue(n),s=n.getBoundingClientRect(),o=He(e,s);return{anchor:i,rect:o,scrollX:window.scrollX,scrollY:window.scrollY,viewportW:window.innerWidth,viewportH:window.innerHeight,devicePixelRatio:window.devicePixelRatio}}destroy(){this.deactivate(),this.popup.destroy()}};var H="siteping_retry_queue";async function D(t,e,n=3){for(let i=0;i<=n;i++){let s=new AbortController,o=setTimeout(()=>s.abort(),1e4);try{let l=await fetch(t,{...e,signal:s.signal});if(clearTimeout(o),l.ok||l.status>=400&&l.status<500||i===n)return l}catch(l){if(clearTimeout(o),i===n)throw l}let r=1e3*2**i,a=Math.random()*1e3-500;await new Promise(l=>setTimeout(l,r+a))}throw new Error("Max retries exceeded")}function Nt(t,e){try{let n=localStorage.getItem(H),i=n?JSON.parse(n):[],s=Array.isArray(i)?i:[];s.length>=20&&s.shift(),s.push({endpoint:t,payload:e}),localStorage.setItem(H,JSON.stringify(s))}catch{}}async function Je(t){try{let e=localStorage.getItem(H);if(!e)return;let n=JSON.parse(e),i=Array.isArray(n)?n:[],s=i.filter(a=>a.endpoint===t);if(s.length===0)return;let o=[];for(let a of s)try{(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a.payload)})).ok||o.push(a)}catch{o.push(a)}let r=i.filter(a=>a.endpoint!==t).concat(o);r.length>0?localStorage.setItem(H,JSON.stringify(r)):localStorage.removeItem(H)}catch{}}var J=class{constructor(e,n){this.endpoint=e;this.projectName=n}endpoint;projectName;async sendFeedback(e){try{let n=await D(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok){let i=await n.text().catch(()=>"Unknown error");throw new Error(`Failed to send feedback: ${n.status} ${i}`)}return await n.json()}catch(n){throw Nt(this.endpoint,e),n}}async getFeedbacks(e,n){let i=new URLSearchParams({projectName:e});n?.page&&i.set("page",String(n.page)),n?.limit&&i.set("limit",String(n.limit)),n?.type&&i.set("type",n.type),n?.status&&i.set("status",n.status),n?.search&&i.set("search",n.search);let s=await D(`${this.endpoint}?${i.toString()}`,{method:"GET"});if(!s.ok)throw new Error(`Failed to fetch feedbacks: ${s.status}`);return await s.json()}async resolveFeedback(e,n){let i=await D(this.endpoint,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e,projectName:this.projectName,status:n?"resolved":"open"})});if(!i.ok)throw new Error(`Failed to update feedback: ${i.status}`);return await i.json()}async deleteFeedback(e){let n=await D(this.endpoint,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e,projectName:this.projectName})});if(!n.ok)throw new Error(`Failed to delete feedback: ${n.status}`)}async deleteAllFeedbacks(e){let n=await D(this.endpoint,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectName:e,deleteAll:!0})});if(!n.ok)throw new Error(`Failed to delete all feedbacks: ${n.status}`)}};var O=class{listeners=new Map;on(e,n){this.listeners.has(e)||this.listeners.set(e,new Set);let i=this.listeners.get(e);return i.add(n),()=>{i.delete(n)}}off(e,n){let i=this.listeners.get(e);i&&i.delete(n)}emit(e,...n){let i=this.listeners.get(e);if(i)for(let s of i)try{s(...n)}catch(o){console.error(`[siteping] Error in event listener for "${String(e)}":`,o)}}removeAll(){this.listeners.clear()}};var $t=54,Z=class{constructor(e,n,i,s){this.bus=i;this.t=s;let o=n.position??"bottom-right",r=o==="bottom-right";this.items=[{id:"chat",icon:Oe,label:s("fab.messages")},{id:"annotate",icon:je,label:s("fab.annotate")},{id:"toggle-annotations",icon:fe,iconAlt:me,label:s("fab.annotations")}],this.fab=document.createElement("button"),this.fab.className=`sp-fab sp-fab--${o} sp-anim-fab-in`,this.fab.style.position="fixed",this.fab.appendChild(F(he)),this.fab.setAttribute("aria-label",s("fab.aria")),this.fab.setAttribute("aria-expanded","false"),this.fab.addEventListener("click",()=>this.toggle()),this.radialContainer=document.createElement("div"),this.radialContainer.className=`sp-radial sp-radial--${o}`,this.radialContainer.setAttribute("role","menu");for(let c=0;c<this.items.length;c++){let d=this.items[c];if(!d)continue;let p=document.createElement("button");p.className="sp-radial-item",p.style.setProperty("--sp-i",String(c)),p.appendChild(F(d.icon)),p.setAttribute("role","menuitem"),p.setAttribute("aria-label",d.label),p.dataset.itemId=d.id,p.addEventListener("click",m=>{m.stopPropagation(),this.handleItemClick(d.id)});let f=document.createElement("span");f.className="sp-radial-label",f.textContent=d.label,f.style.cssText=r?"position:absolute; right:54px; top:50%; transform:translateY(-50%); white-space:nowrap;":"position:absolute; left:54px; top:50%; transform:translateY(-50%); white-space:nowrap;",p.appendChild(f),this.radialContainer.appendChild(p)}this.root=document.createElement("div"),this.root.appendChild(this.radialContainer),this.root.appendChild(this.fab),e.appendChild(this.root);let a=e.host;this.onDocumentClick=c=>{this.isOpen&&!c.composedPath().includes(a)&&this.close()},document.addEventListener("click",this.onDocumentClick);let l=c=>{c.key==="Escape"&&this.isOpen&&(c.stopPropagation(),this.close())};this.fab.addEventListener("keydown",l),this.radialContainer.addEventListener("keydown",l),this.radialContainer.addEventListener("keydown",c=>{let d=Array.from(this.radialContainer.querySelectorAll(".sp-radial-item"));if(d.length===0||!this.isOpen)return;let p=e.activeElement??document.activeElement,f=d.indexOf(p);switch(c.key){case"ArrowUp":{c.preventDefault();let m=f<=0?d.length-1:f-1;d[m]?.focus();break}case"ArrowDown":{c.preventDefault();let m=f>=d.length-1?0:f+1;d[m]?.focus();break}case"Home":{c.preventDefault(),d[0]?.focus();break}case"End":{c.preventDefault(),d[d.length-1]?.focus();break}}})}bus;t;root;fab;radialContainer;badgeEl=null;isOpen=!1;annotationsVisible=!0;items;onDocumentClick;updateBadge(e){if(e<=0){this.badgeEl?.remove(),this.badgeEl=null;return}this.badgeEl||(this.badgeEl=document.createElement("span"),this.badgeEl.className="sp-fab-badge",this.badgeEl.setAttribute("role","status"),this.badgeEl.setAttribute("aria-live","polite"),this.fab.appendChild(this.badgeEl));let n=e>99?"99+":String(e);b(this.badgeEl,n),this.badgeEl.setAttribute("aria-label",this.t("fab.badge").replace("{count}",String(e)))}toggle(){this.isOpen?this.close():this.open()}open(){this.isOpen=!0,this.setFabIcon(G),this.fab.setAttribute("aria-expanded","true"),this.radialContainer.querySelectorAll(".sp-radial-item").forEach((n,i)=>{let s=-(16+$t*(i+1));n.style.transform=`translate(0px, ${s}px) scale(1)`,n.classList.add("sp-radial-item--open")}),requestAnimationFrame(()=>{this.radialContainer.querySelector(".sp-radial-item")?.focus()})}close(){this.isOpen=!1,this.setFabIcon(he),this.fab.setAttribute("aria-expanded","false"),this.radialContainer.querySelectorAll(".sp-radial-item").forEach(n=>{n.style.transform="translate(0, 0) scale(0.8)",n.classList.remove("sp-radial-item--open")}),this.fab.focus()}setFabIcon(e){let n=this.badgeEl;this.fab.replaceChildren(F(e)),n&&this.fab.appendChild(n)}handleItemClick(e){switch(this.close(),e){case"chat":this.bus.emit("panel:toggle",!0);break;case"annotate":this.bus.emit("annotation:start");break;case"toggle-annotations":{this.annotationsVisible=!this.annotationsVisible,this.bus.emit("annotations:toggle",this.annotationsVisible);let n=this.radialContainer.querySelector('[data-item-id="toggle-annotations"]');n&&n.replaceChildren(F(this.annotationsVisible?fe:me));break}}}destroy(){document.removeEventListener("click",this.onDocumentClick),this.root.remove()}};var Ze={"panel.title":"Feedbacks","panel.ariaLabel":"Siteping feedback panel","panel.feedbackList":"Feedback list","panel.loading":"Loading feedbacks","panel.close":"Close panel","panel.deleteAll":"Delete all","panel.deleteAllConfirmTitle":"Delete all","panel.deleteAllConfirmMessage":"Delete all feedbacks for this project? This action cannot be undone.","panel.search":"Search...","panel.searchAria":"Search feedbacks","panel.filterAll":"All","panel.loadError":"Failed to load","panel.retry":"Retry","panel.empty":"No feedback yet","panel.showMore":"Show more","panel.showLess":"Show less","panel.resolve":"Resolve","panel.reopen":"Reopen","panel.delete":"Delete","panel.cancel":"Cancel","panel.confirmDelete":"Delete","type.question":"Question","type.change":"Change","type.bug":"Bug","type.other":"Other","fab.aria":"Siteping \u2014 Feedback menu","fab.messages":"Messages","fab.annotate":"Annotate","fab.annotations":"Annotations","annotator.instruction":"Draw a rectangle on the area to comment","annotator.cancel":"Cancel","popup.ariaLabel":"Feedback form","popup.placeholder":"Describe your feedback...","popup.textareaAria":"Feedback message","popup.submitHintMac":"\u2318+Enter to send","popup.submitHintOther":"Ctrl+Enter to send","popup.cancel":"Cancel","popup.submit":"Send","identity.title":"Identify yourself","identity.nameLabel":"Name","identity.namePlaceholder":"Your name","identity.emailLabel":"Email","identity.emailPlaceholder":"your@email.com","identity.cancel":"Cancel","identity.submit":"Continue","marker.approximate":"Approximate position (confidence: {confidence}%)","marker.aria":"Feedback #{number}: {type} \u2014 {message}","fab.badge":"{count} unresolved feedbacks","feedback.sent.confirmation":"Feedback sent successfully","feedback.error.message":"Failed to send feedback","feedback.deleted.confirmation":"Feedback deleted","badge.count":"{count} unresolved feedbacks"};var et={"panel.title":"Feedbacks","panel.ariaLabel":"Panneau de feedback Siteping","panel.feedbackList":"Liste des feedbacks","panel.loading":"Chargement des feedbacks","panel.close":"Fermer le panneau","panel.deleteAll":"Tout supprimer","panel.deleteAllConfirmTitle":"Tout supprimer","panel.deleteAllConfirmMessage":"Supprimer tous les feedbacks de ce projet ? Cette action est irr\xE9versible.","panel.search":"Rechercher...","panel.searchAria":"Rechercher dans les feedbacks","panel.filterAll":"Tous","panel.loadError":"Erreur de chargement","panel.retry":"R\xE9essayer","panel.empty":"Aucun feedback pour le moment","panel.showMore":"Voir plus","panel.showLess":"Voir moins","panel.resolve":"R\xE9soudre","panel.reopen":"Rouvrir","panel.delete":"Supprimer","panel.cancel":"Annuler","panel.confirmDelete":"Supprimer","type.question":"Question","type.change":"Changement","type.bug":"Bug","type.other":"Autre","fab.aria":"Siteping \u2014 Menu feedback","fab.messages":"Messages","fab.annotate":"Annoter","fab.annotations":"Annotations","annotator.instruction":"Tracez un rectangle sur la zone \xE0 commenter","annotator.cancel":"Annuler","popup.ariaLabel":"Formulaire de feedback","popup.placeholder":"D\xE9crivez votre retour...","popup.textareaAria":"Message de feedback","popup.submitHintMac":"\u2318+Entr\xE9e pour envoyer","popup.submitHintOther":"Ctrl+Entr\xE9e pour envoyer","popup.cancel":"Annuler","popup.submit":"Envoyer","identity.title":"Identifiez-vous","identity.nameLabel":"Nom","identity.namePlaceholder":"Votre nom","identity.emailLabel":"Email","identity.emailPlaceholder":"votre@email.com","identity.cancel":"Annuler","identity.submit":"Continuer","marker.approximate":"Position approximative (confiance : {confidence}%)","marker.aria":"Feedback n\xB0{number} : {type} \u2014 {message}","fab.badge":"{count} feedbacks non r\xE9solus","feedback.sent.confirmation":"Feedback envoy\xE9 avec succ\xE8s","feedback.error.message":"\xC9chec de l'envoi du feedback","feedback.deleted.confirmation":"Feedback supprim\xE9","badge.count":"{count} feedbacks non r\xE9solus"};var be={fr:et,en:Ze};function ee(t){let e=(t.split("-")[0]??t).toLowerCase();be[e]||console.warn(`[siteping] Unknown locale "${t}", falling back to "en"`);let n=be[e]??be.en??{};return i=>n[i]??i}function B(t,e){switch(t){case"question":return e("type.question");case"change":return e("type.change");case"bug":return e("type.bug");case"other":return e("type.other");default:return t}}var tt="siteping_identity";function nt(){try{let t=localStorage.getItem(tt);if(!t)return null;let e=JSON.parse(t);if(typeof e=="object"&&e!==null&&"name"in e&&typeof e.name=="string"&&"email"in e&&typeof e.email=="string"){let n=e;if(n.name&&n.email)return n}return null}catch{return null}}function it(t){try{localStorage.setItem(tt,JSON.stringify(t))}catch{}}function Dt(t,e){if(t===e)return 0;if(t.length===0)return e.length;if(e.length===0)return t.length;if(t.length>e.length){let r=t;t=e,e=r}let n=t.length,i=e.length,s=new Array(n+1);for(let r=0;r<=n;r++)s[r]=r;let o=new Array(n+1);for(let r=1;r<=i;r++){o[0]=r;for(let l=1;l<=n;l++){let c=s[l-1]??0;o[l]=t[l-1]===e[r-1]?c:1+Math.min(c,s[l]??0,o[l-1]??0)}let a=s;s=o,o=a}return s[n]??0}function $(t,e){if(t===e)return 1;let n=Math.max(t.length,e.length);return n===0?1:1-Dt(t,e)/n}function ye(t,e,n=.6){if(!e||!t)return 0;if(t.includes(e))return 1;let i=e.length;if(i>t.length){let a=$(t,e);return a>=n?a:0}let s=0,o=t.length>500?t.slice(0,500):t,r=o.length-i;for(let a=0;a<=r;a++){let l=o.slice(a,a+i),c=$(l,e);if(c>s&&(s=c),s>=.95)break}return s>=n?s:0}var Ht=300,Ot=.3;function ve(t,e){if(!e.textSnippet)return!0;let n=(t.textContent?.trim()??"").slice(0,500);return ye(n,e.textSnippet,.5)>Ot}function jt(t){if(t.elementId){let e=document.getElementById(t.elementId);if(e&&e.tagName===t.elementTag&&ve(e,t))return{element:e,confidence:1,strategy:"id"}}try{let e=document.querySelector(t.cssSelector);if(e&&e.tagName===t.elementTag&&ve(e,t))return{element:e,confidence:.95,strategy:"css"}}catch{}try{let n=document.evaluate(t.xpath,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue;if(n instanceof Element&&n.tagName===t.elementTag&&ve(n,t))return{element:n,confidence:.9,strategy:"xpath"}}catch{}return zt(t)}function zt(t){let e=t.elementTag.toLowerCase(),n=document.querySelectorAll(e);if(n.length===0)return null;let i=null,s=0,o=Math.min(n.length,Ht);for(let r=0;r<o;r++){let a=n[r];if(!a)continue;let l=_t(a,t);if(l>s&&(s=l,i=a,s>=.85))break}return!i||s<.4?null:{element:i,confidence:Math.min(s,.85),strategy:"scan"}}function _t(t,e){let n=0,i=0,s=(t.textContent?.trim()??"").slice(0,500);if(e.textSnippet&&(i+=40,n+=ye(s,e.textSnippet,.5)*40),e.fingerprint&&(i+=20,n+=Ne(t,e.fingerprint)*20),e.textPrefix||e.textSuffix){i+=20;let o=0,r=0;if(e.textPrefix){let a=N(t,"before");o+=a?$(a,e.textPrefix):0,r++}if(e.textSuffix){let a=N(t,"after");o+=a?$(a,e.textSuffix):0,r++}r>0&&(n+=o/r*20)}if(e.neighborText){i+=20;let o=U(t);n+=o?$(o,e.neighborText)*20:0}return i>0?n/i:0}function te(t,e){let n=jt(t);if(!n)return null;let i=n.element.getBoundingClientRect(),s=new DOMRect(i.x+e.xPct*i.width,i.y+e.yPct*i.height,e.wPct*i.width,e.hPct*i.height);return{element:n.element,rect:s,confidence:n.confidence,strategy:n.strategy}}function xe(t){return{cssSelector:t.cssSelector,xpath:t.xpath,textSnippet:t.textSnippet,elementTag:t.elementTag,elementId:t.elementId??void 0,textPrefix:t.textPrefix,textSuffix:t.textSuffix,fingerprint:t.fingerprint,neighborText:t.neighborText}}function ne(t){return{xPct:t.xPct,yPct:t.yPct,wPct:t.wPct,hPct:t.hPct}}var st=13;function ot(t){return{top:t.top+window.scrollY-st,left:t.right+window.scrollX-st}}function j(t,e){let n=t.entries[e],i=t.elementIndices[e];if(!(!n||i===void 0))return n.elements[i]}var rt=300,at=200,Kt=.7,Yt=28,lt=32,ie=class{constructor(e,n,i,s){this.colors=e;this.tooltip=n;this.bus=i;this.t=s;this.container=h("div",{style:"position:absolute;top:0;left:0;pointer-events:none;z-index:2147483646;"}),this.container.id="siteping-markers",document.body.appendChild(this.container),this.bus.on("annotations:toggle",o=>{this.container.style.display=o?"block":"none"}),this.resizeHandler=()=>this.scheduleReposition(),window.addEventListener("resize",this.resizeHandler,{passive:!0}),this.scrollHandler=()=>this.scheduleReposition(),window.addEventListener("scroll",this.scrollHandler,{passive:!0,capture:!0}),this.mutationObserver=new MutationObserver(o=>{if(o.length>20){this.scheduleReposition();return}let r=!1;for(let a of o)if(!(this.container.contains(a.target)||this.tooltip.contains(a.target))){r=!0;break}r&&this.scheduleReposition()}),this.mutationObserver.observe(document.body,{childList:!0,subtree:!0,attributes:!1,characterData:!1}),this.onDocumentClickForClusters=o=>{this.container.contains(o.target)||this.collapseAllClusters()},document.addEventListener("click",this.onDocumentClickForClusters)}colors;tooltip;bus;t;container;entries=[];highlightElements=[];pinnedFeedback=null;onDocumentClick=null;repositionTimer=null;mutationObserver=null;scrollHandler=null;resizeHandler=null;anchorCache=new Map;clusters=[];onDocumentClickForClusters=null;get count(){return this.entries.length}scheduleReposition(){this.repositionTimer||("requestIdleCallback"in window?this.repositionTimer=window.requestIdleCallback(()=>{this.repositionTimer=null,this.repositionAll()},{timeout:at+100}):this.repositionTimer=+setTimeout(()=>{this.repositionTimer=null,this.repositionAll()},at))}repositionAll(){for(let e of this.entries)for(let n=0;n<e.feedback.annotations.length;n++){let i=e.elements[n];if(!i)continue;let s=e.feedback.annotations[n];if(!s)continue;let o=`${e.feedback.id}:${n}`,a=this.anchorCache.get(o)?.deref(),l;if(a?.isConnected){let d=a.getBoundingClientRect(),p=ne(s);l={element:a,rect:new DOMRect(d.left+p.xPct*d.width,d.top+p.yPct*d.height,p.wPct*d.width,p.hPct*d.height),confidence:1,strategy:"css"}}else l=te(xe(s),ne(s)),l?.element&&this.anchorCache.set(o,new WeakRef(l.element));if(!l){i.style.display="none";continue}let c=ot(l.rect);e.baseTop=c.top,e.baseLeft=c.left,i.style.display="flex",this.applyConfidenceStyle(i,l.confidence,e.feedback)}this.applyClusterPositions()}applyClusterPositions(){for(let e of this.clusters)e.expanded?this.applyFanPositions(e):this.applyStackPositions(e)}render(e){this.clear(),e.forEach((n,i)=>{let s=this.buildEntry(n,i+1);this.entries.push(s)}),this.buildClusters()}addFeedback(e,n){let i=this.buildEntry(e,n);for(let s of i.elements)s.style.animation="sp-marker-in 0.35s cubic-bezier(0.34,1.56,0.64,1) both";this.entries.push(i),this.buildClusters()}buildEntry(e,n){let i={feedback:e,elements:[],baseTop:0,baseLeft:0};for(let s of e.annotations){let o=te(xe(s),ne(s));if(!o)continue;let r=ot(o.rect);i.baseTop=r.top,i.baseLeft=r.left;let a=this.createMarker(n,e,r);this.applyConfidenceStyle(a,o.confidence,e),this.container.appendChild(a),i.elements.push(a)}return i}buildClusters(){for(let i of this.container.querySelectorAll(".sp-cluster-badge"))i.remove();let e=[];for(let i of this.entries)for(let s=0;s<i.elements.length;s++)e.push({entry:i,elIdx:s});let n=new Set;this.clusters=[];for(let i=0;i<e.length;i++){if(n.has(i))continue;let s=e[i];if(!s)continue;let o={entries:[s.entry],elementIndices:[s.elIdx],expanded:!1};n.add(i);for(let r=i+1;r<e.length;r++){if(n.has(r))continue;let a=s.entry,l=e[r];if(!l)continue;let c=l.entry;Math.sqrt((a.baseLeft-c.baseLeft)**2+(a.baseTop-c.baseTop)**2)<Yt&&(o.entries.push(c),o.elementIndices.push(l.elIdx),n.add(r))}this.clusters.push(o)}for(let i of this.clusters)i.entries.length<=1||(this.applyStackPositions(i),this.addClusterBadge(i))}applyStackPositions(e){let n=e.entries[0];if(!n)return;let{baseTop:i,baseLeft:s}=n,o=e.entries.length<=1;for(let r=0;r<e.entries.length;r++){let a=j(e,r);a&&(a.style.top=`${i+(o?0:r*3)}px`,a.style.left=`${s+(o?0:r*3)}px`,a.style.zIndex=String(r+1))}}applyFanPositions(e){let n=e.entries[0];if(!n)return;let{baseTop:i,baseLeft:s}=n,o=e.entries.length,r=(o-1)*lt,a=s-r/2;for(let l=0;l<o;l++){let c=j(e,l);c&&(c.style.top=`${i}px`,c.style.left=`${a+l*lt}px`,c.style.zIndex=String(10+l))}}addClusterBadge(e){let n=j(e,e.entries.length-1);if(!n)return;let i=h("div",{class:"sp-cluster-badge",style:`
131
+ `}),this.overlay?.appendChild(this.drawingRect)}onMouseMove=e=>{this.scheduleRectUpdate(e)};onTouchMove=e=>{e.preventDefault(),e.touches[0]&&this.scheduleRectUpdate(e.touches[0])};scheduleRectUpdate(e){!this.isDrawing||!this.drawingRect||(this.pendingMoveEvent=e,this.rafId===null&&(this.rafId=requestAnimationFrame(()=>{this.rafId=null;let n=this.pendingMoveEvent;if(!n||!this.drawingRect)return;let i=Math.min(n.clientX,this.startX),s=Math.min(n.clientY,this.startY),o=Math.abs(n.clientX-this.startX),r=Math.abs(n.clientY-this.startY);this.drawingRect.style.left=`${i}px`,this.drawingRect.style.top=`${s}px`,this.drawingRect.style.width=`${o}px`,this.drawingRect.style.height=`${r}px`})))}onTouchEnd=async e=>{let n=e.changedTouches[0];n&&await this.finishDrawing(n.clientX,n.clientY)};onMouseUp=async e=>{await this.finishDrawing(e.clientX,e.clientY)};finishDrawing=async(e,n)=>{if(!this.isDrawing||!this.drawingRect)return;this.isDrawing=!1;let i=Math.min(e,this.startX),s=Math.min(n,this.startY),o=Math.abs(e-this.startX),r=Math.abs(n-this.startY);if(o<10||r<10){this.drawingRect.remove(),this.drawingRect=null;return}let a=new DOMRect(i,s,o,r),l=await this.popup.show(a);if(!l){this.drawingRect?.remove(),this.drawingRect=null;return}let c=this.buildAnnotation(a);this.drawingRect?.remove(),this.drawingRect=null,this.deactivate(),this.bus.emit("annotation:complete",{annotation:c,type:l.type,message:l.message})};buildAnnotation(e){this.overlay&&(this.overlay.style.pointerEvents="none");let n=De(e);this.overlay&&(this.overlay.style.pointerEvents="auto");let i=ue(n),s=n.getBoundingClientRect(),o=He(e,s);return{anchor:i,rect:o,scrollX:window.scrollX,scrollY:window.scrollY,viewportW:window.innerWidth,viewportH:window.innerHeight,devicePixelRatio:window.devicePixelRatio}}destroy(){this.deactivate(),this.popup.destroy()}};var H="siteping_retry_queue";async function D(t,e,n=3){for(let i=0;i<=n;i++){let s=new AbortController,o=setTimeout(()=>s.abort(),1e4);try{let l=await fetch(t,{...e,signal:s.signal});if(clearTimeout(o),l.ok||l.status>=400&&l.status<500||i===n)return l}catch(l){if(clearTimeout(o),i===n)throw l}let r=1e3*2**i,a=Math.random()*1e3-500;await new Promise(l=>setTimeout(l,r+a))}throw new Error("Max retries exceeded")}function Nt(t,e){try{let n=localStorage.getItem(H),i=n?JSON.parse(n):[],s=Array.isArray(i)?i:[];s.length>=20&&s.shift(),s.push({endpoint:t,payload:e}),localStorage.setItem(H,JSON.stringify(s))}catch{}}async function Je(t){try{let e=localStorage.getItem(H);if(!e)return;let n=JSON.parse(e),i=Array.isArray(n)?n:[],s=i.filter(a=>a.endpoint===t);if(s.length===0)return;let o=[];for(let a of s)try{(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a.payload)})).ok||o.push(a)}catch{o.push(a)}let r=i.filter(a=>a.endpoint!==t).concat(o);r.length>0?localStorage.setItem(H,JSON.stringify(r)):localStorage.removeItem(H)}catch{}}var J=class{constructor(e,n){this.endpoint=e;this.projectName=n}endpoint;projectName;async sendFeedback(e){try{let n=await D(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok){let i=await n.text().catch(()=>"Unknown error");throw new Error(`Failed to send feedback: ${n.status} ${i}`)}return await n.json()}catch(n){throw Nt(this.endpoint,e),n}}async getFeedbacks(e,n){let i=new URLSearchParams({projectName:e});n?.page&&i.set("page",String(n.page)),n?.limit&&i.set("limit",String(n.limit)),n?.type&&i.set("type",n.type),n?.status&&i.set("status",n.status),n?.search&&i.set("search",n.search);let s=await D(`${this.endpoint}?${i.toString()}`,{method:"GET",cache:"no-store"});if(!s.ok)throw new Error(`Failed to fetch feedbacks: ${s.status}`);return await s.json()}async resolveFeedback(e,n){let i=await D(this.endpoint,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e,projectName:this.projectName,status:n?"resolved":"open"})});if(!i.ok)throw new Error(`Failed to update feedback: ${i.status}`);return await i.json()}async deleteFeedback(e){let n=await D(this.endpoint,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e,projectName:this.projectName})});if(!n.ok)throw new Error(`Failed to delete feedback: ${n.status}`)}async deleteAllFeedbacks(e){let n=await D(this.endpoint,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectName:e,deleteAll:!0})});if(!n.ok)throw new Error(`Failed to delete all feedbacks: ${n.status}`)}};var O=class{listeners=new Map;on(e,n){this.listeners.has(e)||this.listeners.set(e,new Set);let i=this.listeners.get(e);return i.add(n),()=>{i.delete(n)}}off(e,n){let i=this.listeners.get(e);i&&i.delete(n)}emit(e,...n){let i=this.listeners.get(e);if(i)for(let s of i)try{s(...n)}catch(o){console.error(`[siteping] Error in event listener for "${String(e)}":`,o)}}removeAll(){this.listeners.clear()}};var $t=54,Z=class{constructor(e,n,i,s){this.bus=i;this.t=s;let o=n.position??"bottom-right",r=o==="bottom-right";this.items=[{id:"chat",icon:Oe,label:s("fab.messages")},{id:"annotate",icon:je,label:s("fab.annotate")},{id:"toggle-annotations",icon:fe,iconAlt:me,label:s("fab.annotations")}],this.fab=document.createElement("button"),this.fab.className=`sp-fab sp-fab--${o} sp-anim-fab-in`,this.fab.style.position="fixed",this.fab.appendChild(F(he)),this.fab.setAttribute("aria-label",s("fab.aria")),this.fab.setAttribute("aria-expanded","false"),this.fab.addEventListener("click",()=>this.toggle()),this.radialContainer=document.createElement("div"),this.radialContainer.className=`sp-radial sp-radial--${o}`,this.radialContainer.setAttribute("role","menu");for(let c=0;c<this.items.length;c++){let d=this.items[c];if(!d)continue;let p=document.createElement("button");p.className="sp-radial-item",p.style.setProperty("--sp-i",String(c)),p.appendChild(F(d.icon)),p.setAttribute("role","menuitem"),p.setAttribute("aria-label",d.label),p.dataset.itemId=d.id,p.addEventListener("click",m=>{m.stopPropagation(),this.handleItemClick(d.id)});let f=document.createElement("span");f.className="sp-radial-label",f.textContent=d.label,f.style.cssText=r?"position:absolute; right:54px; top:50%; transform:translateY(-50%); white-space:nowrap;":"position:absolute; left:54px; top:50%; transform:translateY(-50%); white-space:nowrap;",p.appendChild(f),this.radialContainer.appendChild(p)}this.root=document.createElement("div"),this.root.appendChild(this.radialContainer),this.root.appendChild(this.fab),e.appendChild(this.root);let a=e.host;this.onDocumentClick=c=>{this.isOpen&&!c.composedPath().includes(a)&&this.close()},document.addEventListener("click",this.onDocumentClick);let l=c=>{c.key==="Escape"&&this.isOpen&&(c.stopPropagation(),this.close())};this.fab.addEventListener("keydown",l),this.radialContainer.addEventListener("keydown",l),this.radialContainer.addEventListener("keydown",c=>{let d=Array.from(this.radialContainer.querySelectorAll(".sp-radial-item"));if(d.length===0||!this.isOpen)return;let p=e.activeElement??document.activeElement,f=d.indexOf(p);switch(c.key){case"ArrowUp":{c.preventDefault();let m=f<=0?d.length-1:f-1;d[m]?.focus();break}case"ArrowDown":{c.preventDefault();let m=f>=d.length-1?0:f+1;d[m]?.focus();break}case"Home":{c.preventDefault(),d[0]?.focus();break}case"End":{c.preventDefault(),d[d.length-1]?.focus();break}}})}bus;t;root;fab;radialContainer;badgeEl=null;isOpen=!1;annotationsVisible=!0;items;onDocumentClick;updateBadge(e){if(e<=0){this.badgeEl?.remove(),this.badgeEl=null;return}this.badgeEl||(this.badgeEl=document.createElement("span"),this.badgeEl.className="sp-fab-badge",this.badgeEl.setAttribute("role","status"),this.badgeEl.setAttribute("aria-live","polite"),this.fab.appendChild(this.badgeEl));let n=e>99?"99+":String(e);b(this.badgeEl,n),this.badgeEl.setAttribute("aria-label",this.t("fab.badge").replace("{count}",String(e)))}toggle(){this.isOpen?this.close():this.open()}open(){this.isOpen=!0,this.setFabIcon(G),this.fab.setAttribute("aria-expanded","true"),this.radialContainer.querySelectorAll(".sp-radial-item").forEach((n,i)=>{let s=-(16+$t*(i+1));n.style.transform=`translate(0px, ${s}px) scale(1)`,n.classList.add("sp-radial-item--open")}),requestAnimationFrame(()=>{this.radialContainer.querySelector(".sp-radial-item")?.focus()})}close(){this.isOpen=!1,this.setFabIcon(he),this.fab.setAttribute("aria-expanded","false"),this.radialContainer.querySelectorAll(".sp-radial-item").forEach(n=>{n.style.transform="translate(0, 0) scale(0.8)",n.classList.remove("sp-radial-item--open")}),this.fab.focus()}setFabIcon(e){let n=this.badgeEl;this.fab.replaceChildren(F(e)),n&&this.fab.appendChild(n)}handleItemClick(e){switch(this.close(),e){case"chat":this.bus.emit("panel:toggle",!0);break;case"annotate":this.bus.emit("annotation:start");break;case"toggle-annotations":{this.annotationsVisible=!this.annotationsVisible,this.bus.emit("annotations:toggle",this.annotationsVisible);let n=this.radialContainer.querySelector('[data-item-id="toggle-annotations"]');n&&n.replaceChildren(F(this.annotationsVisible?fe:me));break}}}destroy(){document.removeEventListener("click",this.onDocumentClick),this.root.remove()}};var Ze={"panel.title":"Feedbacks","panel.ariaLabel":"Siteping feedback panel","panel.feedbackList":"Feedback list","panel.loading":"Loading feedbacks","panel.close":"Close panel","panel.deleteAll":"Delete all","panel.deleteAllConfirmTitle":"Delete all","panel.deleteAllConfirmMessage":"Delete all feedbacks for this project? This action cannot be undone.","panel.search":"Search...","panel.searchAria":"Search feedbacks","panel.filterAll":"All","panel.loadError":"Failed to load","panel.retry":"Retry","panel.empty":"No feedback yet","panel.showMore":"Show more","panel.showLess":"Show less","panel.resolve":"Resolve","panel.reopen":"Reopen","panel.delete":"Delete","panel.cancel":"Cancel","panel.confirmDelete":"Delete","type.question":"Question","type.change":"Change","type.bug":"Bug","type.other":"Other","fab.aria":"Siteping \u2014 Feedback menu","fab.messages":"Messages","fab.annotate":"Annotate","fab.annotations":"Annotations","annotator.instruction":"Draw a rectangle on the area to comment","annotator.cancel":"Cancel","popup.ariaLabel":"Feedback form","popup.placeholder":"Describe your feedback...","popup.textareaAria":"Feedback message","popup.submitHintMac":"\u2318+Enter to send","popup.submitHintOther":"Ctrl+Enter to send","popup.cancel":"Cancel","popup.submit":"Send","identity.title":"Identify yourself","identity.nameLabel":"Name","identity.namePlaceholder":"Your name","identity.emailLabel":"Email","identity.emailPlaceholder":"your@email.com","identity.cancel":"Cancel","identity.submit":"Continue","marker.approximate":"Approximate position (confidence: {confidence}%)","marker.aria":"Feedback #{number}: {type} \u2014 {message}","fab.badge":"{count} unresolved feedbacks","feedback.sent.confirmation":"Feedback sent successfully","feedback.error.message":"Failed to send feedback","feedback.deleted.confirmation":"Feedback deleted","badge.count":"{count} unresolved feedbacks"};var et={"panel.title":"Feedbacks","panel.ariaLabel":"Panneau de feedback Siteping","panel.feedbackList":"Liste des feedbacks","panel.loading":"Chargement des feedbacks","panel.close":"Fermer le panneau","panel.deleteAll":"Tout supprimer","panel.deleteAllConfirmTitle":"Tout supprimer","panel.deleteAllConfirmMessage":"Supprimer tous les feedbacks de ce projet ? Cette action est irr\xE9versible.","panel.search":"Rechercher...","panel.searchAria":"Rechercher dans les feedbacks","panel.filterAll":"Tous","panel.loadError":"Erreur de chargement","panel.retry":"R\xE9essayer","panel.empty":"Aucun feedback pour le moment","panel.showMore":"Voir plus","panel.showLess":"Voir moins","panel.resolve":"R\xE9soudre","panel.reopen":"Rouvrir","panel.delete":"Supprimer","panel.cancel":"Annuler","panel.confirmDelete":"Supprimer","type.question":"Question","type.change":"Changement","type.bug":"Bug","type.other":"Autre","fab.aria":"Siteping \u2014 Menu feedback","fab.messages":"Messages","fab.annotate":"Annoter","fab.annotations":"Annotations","annotator.instruction":"Tracez un rectangle sur la zone \xE0 commenter","annotator.cancel":"Annuler","popup.ariaLabel":"Formulaire de feedback","popup.placeholder":"D\xE9crivez votre retour...","popup.textareaAria":"Message de feedback","popup.submitHintMac":"\u2318+Entr\xE9e pour envoyer","popup.submitHintOther":"Ctrl+Entr\xE9e pour envoyer","popup.cancel":"Annuler","popup.submit":"Envoyer","identity.title":"Identifiez-vous","identity.nameLabel":"Nom","identity.namePlaceholder":"Votre nom","identity.emailLabel":"Email","identity.emailPlaceholder":"votre@email.com","identity.cancel":"Annuler","identity.submit":"Continuer","marker.approximate":"Position approximative (confiance : {confidence}%)","marker.aria":"Feedback n\xB0{number} : {type} \u2014 {message}","fab.badge":"{count} feedbacks non r\xE9solus","feedback.sent.confirmation":"Feedback envoy\xE9 avec succ\xE8s","feedback.error.message":"\xC9chec de l'envoi du feedback","feedback.deleted.confirmation":"Feedback supprim\xE9","badge.count":"{count} feedbacks non r\xE9solus"};var be={fr:et,en:Ze};function ee(t){let e=(t.split("-")[0]??t).toLowerCase();be[e]||console.warn(`[siteping] Unknown locale "${t}", falling back to "en"`);let n=be[e]??be.en??{};return i=>n[i]??i}function B(t,e){switch(t){case"question":return e("type.question");case"change":return e("type.change");case"bug":return e("type.bug");case"other":return e("type.other");default:return t}}var tt="siteping_identity";function nt(){try{let t=localStorage.getItem(tt);if(!t)return null;let e=JSON.parse(t);if(typeof e=="object"&&e!==null&&"name"in e&&typeof e.name=="string"&&"email"in e&&typeof e.email=="string"){let n=e;if(n.name&&n.email)return n}return null}catch{return null}}function it(t){try{localStorage.setItem(tt,JSON.stringify(t))}catch{}}function Dt(t,e){if(t===e)return 0;if(t.length===0)return e.length;if(e.length===0)return t.length;if(t.length>e.length){let r=t;t=e,e=r}let n=t.length,i=e.length,s=new Array(n+1);for(let r=0;r<=n;r++)s[r]=r;let o=new Array(n+1);for(let r=1;r<=i;r++){o[0]=r;for(let l=1;l<=n;l++){let c=s[l-1]??0;o[l]=t[l-1]===e[r-1]?c:1+Math.min(c,s[l]??0,o[l-1]??0)}let a=s;s=o,o=a}return s[n]??0}function $(t,e){if(t===e)return 1;let n=Math.max(t.length,e.length);return n===0?1:1-Dt(t,e)/n}function ye(t,e,n=.6){if(!e||!t)return 0;if(t.includes(e))return 1;let i=e.length;if(i>t.length){let a=$(t,e);return a>=n?a:0}let s=0,o=t.length>500?t.slice(0,500):t,r=o.length-i;for(let a=0;a<=r;a++){let l=o.slice(a,a+i),c=$(l,e);if(c>s&&(s=c),s>=.95)break}return s>=n?s:0}var Ht=300,Ot=.3;function ve(t,e){if(!e.textSnippet)return!0;let n=(t.textContent?.trim()??"").slice(0,500);return ye(n,e.textSnippet,.5)>Ot}function jt(t){if(t.elementId){let e=document.getElementById(t.elementId);if(e&&e.tagName===t.elementTag&&ve(e,t))return{element:e,confidence:1,strategy:"id"}}try{let e=document.querySelector(t.cssSelector);if(e&&e.tagName===t.elementTag&&ve(e,t))return{element:e,confidence:.95,strategy:"css"}}catch{}try{let n=document.evaluate(t.xpath,document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue;if(n instanceof Element&&n.tagName===t.elementTag&&ve(n,t))return{element:n,confidence:.9,strategy:"xpath"}}catch{}return zt(t)}function zt(t){let e=t.elementTag.toLowerCase(),n=document.querySelectorAll(e);if(n.length===0)return null;let i=null,s=0,o=Math.min(n.length,Ht);for(let r=0;r<o;r++){let a=n[r];if(!a)continue;let l=_t(a,t);if(l>s&&(s=l,i=a,s>=.85))break}return!i||s<.4?null:{element:i,confidence:Math.min(s,.85),strategy:"scan"}}function _t(t,e){let n=0,i=0,s=(t.textContent?.trim()??"").slice(0,500);if(e.textSnippet&&(i+=40,n+=ye(s,e.textSnippet,.5)*40),e.fingerprint&&(i+=20,n+=Ne(t,e.fingerprint)*20),e.textPrefix||e.textSuffix){i+=20;let o=0,r=0;if(e.textPrefix){let a=N(t,"before");o+=a?$(a,e.textPrefix):0,r++}if(e.textSuffix){let a=N(t,"after");o+=a?$(a,e.textSuffix):0,r++}r>0&&(n+=o/r*20)}if(e.neighborText){i+=20;let o=U(t);n+=o?$(o,e.neighborText)*20:0}return i>0?n/i:0}function te(t,e){let n=jt(t);if(!n)return null;let i=n.element.getBoundingClientRect(),s=new DOMRect(i.x+e.xPct*i.width,i.y+e.yPct*i.height,e.wPct*i.width,e.hPct*i.height);return{element:n.element,rect:s,confidence:n.confidence,strategy:n.strategy}}function xe(t){return{cssSelector:t.cssSelector,xpath:t.xpath,textSnippet:t.textSnippet,elementTag:t.elementTag,elementId:t.elementId??void 0,textPrefix:t.textPrefix,textSuffix:t.textSuffix,fingerprint:t.fingerprint,neighborText:t.neighborText}}function ne(t){return{xPct:t.xPct,yPct:t.yPct,wPct:t.wPct,hPct:t.hPct}}var st=13;function ot(t){return{top:t.top+window.scrollY-st,left:t.right+window.scrollX-st}}function j(t,e){let n=t.entries[e],i=t.elementIndices[e];if(!(!n||i===void 0))return n.elements[i]}var rt=300,at=200,Kt=.7,Yt=28,lt=32,ie=class{constructor(e,n,i,s){this.colors=e;this.tooltip=n;this.bus=i;this.t=s;this.container=h("div",{style:"position:absolute;top:0;left:0;pointer-events:none;z-index:2147483646;"}),this.container.id="siteping-markers",document.body.appendChild(this.container),this.bus.on("annotations:toggle",o=>{this.container.style.display=o?"block":"none"}),this.resizeHandler=()=>this.scheduleReposition(),window.addEventListener("resize",this.resizeHandler,{passive:!0}),this.scrollHandler=()=>this.scheduleReposition(),window.addEventListener("scroll",this.scrollHandler,{passive:!0,capture:!0}),this.mutationObserver=new MutationObserver(o=>{if(o.length>20){this.scheduleReposition();return}let r=!1;for(let a of o)if(!(this.container.contains(a.target)||this.tooltip.contains(a.target))){r=!0;break}r&&this.scheduleReposition()}),this.mutationObserver.observe(document.body,{childList:!0,subtree:!0,attributes:!1,characterData:!1}),this.onDocumentClickForClusters=o=>{this.container.contains(o.target)||this.collapseAllClusters()},document.addEventListener("click",this.onDocumentClickForClusters)}colors;tooltip;bus;t;container;entries=[];highlightElements=[];pinnedFeedback=null;onDocumentClick=null;repositionTimer=null;mutationObserver=null;scrollHandler=null;resizeHandler=null;anchorCache=new Map;clusters=[];onDocumentClickForClusters=null;get count(){return this.entries.length}scheduleReposition(){this.repositionTimer||("requestIdleCallback"in window?this.repositionTimer=window.requestIdleCallback(()=>{this.repositionTimer=null,this.repositionAll()},{timeout:at+100}):this.repositionTimer=+setTimeout(()=>{this.repositionTimer=null,this.repositionAll()},at))}repositionAll(){for(let e of this.entries)for(let n=0;n<e.feedback.annotations.length;n++){let i=e.elements[n];if(!i)continue;let s=e.feedback.annotations[n];if(!s)continue;let o=`${e.feedback.id}:${n}`,a=this.anchorCache.get(o)?.deref(),l;if(a?.isConnected){let d=a.getBoundingClientRect(),p=ne(s);l={element:a,rect:new DOMRect(d.left+p.xPct*d.width,d.top+p.yPct*d.height,p.wPct*d.width,p.hPct*d.height),confidence:1,strategy:"css"}}else l=te(xe(s),ne(s)),l?.element&&this.anchorCache.set(o,new WeakRef(l.element));if(!l){i.style.display="none";continue}let c=ot(l.rect);e.baseTop=c.top,e.baseLeft=c.left,i.style.display="flex",this.applyConfidenceStyle(i,l.confidence,e.feedback)}this.applyClusterPositions()}applyClusterPositions(){for(let e of this.clusters)e.expanded?this.applyFanPositions(e):this.applyStackPositions(e)}render(e){this.clear(),e.forEach((n,i)=>{let s=this.buildEntry(n,i+1);this.entries.push(s)}),this.buildClusters()}addFeedback(e,n){let i=this.buildEntry(e,n);for(let s of i.elements)s.style.animation="sp-marker-in 0.35s cubic-bezier(0.34,1.56,0.64,1) both";this.entries.push(i),this.buildClusters()}buildEntry(e,n){let i={feedback:e,elements:[],baseTop:0,baseLeft:0};for(let s of e.annotations){let o=te(xe(s),ne(s));if(!o)continue;let r=ot(o.rect);i.baseTop=r.top,i.baseLeft=r.left;let a=this.createMarker(n,e,r);this.applyConfidenceStyle(a,o.confidence,e),this.container.appendChild(a),i.elements.push(a)}return i}buildClusters(){for(let i of this.container.querySelectorAll(".sp-cluster-badge"))i.remove();let e=[];for(let i of this.entries)for(let s=0;s<i.elements.length;s++)e.push({entry:i,elIdx:s});let n=new Set;this.clusters=[];for(let i=0;i<e.length;i++){if(n.has(i))continue;let s=e[i];if(!s)continue;let o={entries:[s.entry],elementIndices:[s.elIdx],expanded:!1};n.add(i);for(let r=i+1;r<e.length;r++){if(n.has(r))continue;let a=s.entry,l=e[r];if(!l)continue;let c=l.entry;Math.sqrt((a.baseLeft-c.baseLeft)**2+(a.baseTop-c.baseTop)**2)<Yt&&(o.entries.push(c),o.elementIndices.push(l.elIdx),n.add(r))}this.clusters.push(o)}for(let i of this.clusters)i.entries.length<=1||(this.applyStackPositions(i),this.addClusterBadge(i))}applyStackPositions(e){let n=e.entries[0];if(!n)return;let{baseTop:i,baseLeft:s}=n,o=e.entries.length<=1;for(let r=0;r<e.entries.length;r++){let a=j(e,r);a&&(a.style.top=`${i+(o?0:r*3)}px`,a.style.left=`${s+(o?0:r*3)}px`,a.style.zIndex=String(r+1))}}applyFanPositions(e){let n=e.entries[0];if(!n)return;let{baseTop:i,baseLeft:s}=n,o=e.entries.length,r=(o-1)*lt,a=s-r/2;for(let l=0;l<o;l++){let c=j(e,l);c&&(c.style.top=`${i}px`,c.style.left=`${a+l*lt}px`,c.style.zIndex=String(10+l))}}addClusterBadge(e){let n=j(e,e.entries.length-1);if(!n)return;let i=h("div",{class:"sp-cluster-badge",style:`
132
132
  position:absolute;top:-6px;right:-6px;
133
133
  min-width:16px;height:16px;padding:0 4px;
134
134
  border-radius:9999px;
@@ -168,7 +168,7 @@
168
168
  opacity:0;
169
169
  box-shadow:0 0 16px ${s}20;
170
170
  transition:opacity ${rt}ms ease;
171
- `});this.container.appendChild(r),this.highlightElements.push(r),r.offsetHeight,r.style.opacity="1"}}pinHighlight(e){this.unpinHighlight(),this.showHighlight(e),this.pinnedFeedback=e,this.onDocumentClick=n=>{this.container.contains(n.target)||this.unpinHighlight()},document.addEventListener("click",this.onDocumentClick,{capture:!0})}unpinHighlight(){this.onDocumentClick&&(document.removeEventListener("click",this.onDocumentClick,{capture:!0}),this.onDocumentClick=null),this.pinnedFeedback=null,this.clearHighlight()}clearHighlight(){for(let e of this.highlightElements)e.style.opacity="0",setTimeout(()=>e.remove(),rt);this.highlightElements=[]}removeHighlightElements(){for(let e of this.highlightElements)e.remove();this.highlightElements=[]}clear(){this.unpinHighlight(),this.container.replaceChildren(),this.entries=[],this.clusters=[],this.anchorCache.clear()}destroy(){this.unpinHighlight(),this.repositionTimer&&("cancelIdleCallback"in window&&window.cancelIdleCallback(this.repositionTimer),clearTimeout(this.repositionTimer)),this.resizeHandler&&window.removeEventListener("resize",this.resizeHandler),this.scrollHandler&&window.removeEventListener("scroll",this.scrollHandler,{capture:!0}),this.onDocumentClickForClusters&&document.removeEventListener("click",this.onDocumentClickForClusters),this.mutationObserver?.disconnect(),this.container.remove()}};var se=class{constructor(e,n,i,s,o,r,a,l){this.colors=n;this.bus=i;this.client=s;this.projectName=o;this.markers=r;this.t=a;this.locale=l;this.root=h("div",{class:"sp-panel"}),this.root.setAttribute("role","complementary"),this.root.setAttribute("aria-label",this.t("panel.ariaLabel")),this.root.setAttribute("aria-hidden","true");let c=h("div",{class:"sp-panel-header"}),d=h("span",{class:"sp-panel-title"});b(d,this.t("panel.title")),this.closeBtn=document.createElement("button"),this.closeBtn.className="sp-panel-close",this.closeBtn.setAttribute("aria-label",this.t("panel.close")),this.closeBtn.appendChild(F(G)),this.closeBtn.addEventListener("click",()=>this.close()),this.deleteAllBtn=document.createElement("button"),this.deleteAllBtn.className="sp-btn-delete-all",this.deleteAllBtn.setAttribute("aria-label",this.t("panel.deleteAll")),this.deleteAllBtn.appendChild(F(ge));let p=document.createElement("span");b(p,` ${this.t("panel.deleteAll")}`),this.deleteAllBtn.appendChild(p),this.deleteAllBtn.addEventListener("click",()=>this.confirmDeleteAll());let f=h("div",{class:"sp-panel-header-right"});f.appendChild(this.deleteAllBtn),f.appendChild(this.closeBtn),c.appendChild(d),c.appendChild(f);let m=h("div",{class:"sp-filters"}),y=h("div",{class:"sp-search-wrap"}),T=F(ze);T.setAttribute("class","sp-search-icon"),this.searchInput=document.createElement("input"),this.searchInput.type="text",this.searchInput.className="sp-search",this.searchInput.placeholder=this.t("panel.search"),this.searchInput.setAttribute("aria-label",this.t("panel.searchAria")),this.searchInput.addEventListener("input",()=>{this.searchTimeout&&clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>this.loadFeedbacks().catch(()=>{}),200)}),y.appendChild(T),y.appendChild(this.searchInput);let k=h("div",{class:"sp-chips"}),C=[{value:"all",label:this.t("panel.filterAll")},{value:"question",label:this.t("type.question")},{value:"change",label:this.t("type.change")},{value:"bug",label:this.t("type.bug")},{value:"other",label:this.t("type.other")}];for(let v of C){let g=document.createElement("button");g.className=`sp-chip ${v.value==="all"?"sp-chip--active":""}`,v.value!=="all"&&(g.style.borderColor=I(v.value,this.colors)),b(g,v.label),g.dataset.filter=v.value,g.setAttribute("aria-pressed",v.value==="all"?"true":"false"),g.addEventListener("click",()=>this.toggleFilter(v.value,k)),k.appendChild(g)}m.appendChild(y),m.appendChild(k),this.listContainer=h("div",{class:"sp-list"}),this.listContainer.setAttribute("role","list"),this.listContainer.setAttribute("aria-label",this.t("panel.feedbackList")),this.root.appendChild(c),this.root.appendChild(m),this.root.appendChild(this.listContainer),e.appendChild(this.root),this.onListClick=v=>{let g=v.target,x=g.closest("[data-action]");if(x){v.stopPropagation();let w=x.closest(".sp-card");if(!w)return;let S=w.dataset.feedbackId,E=this.feedbacks.find(L=>L.id===S);if(!E)return;let A=x.dataset.action;if(A==="expand"){let L=w.querySelector(".sp-card-message");if(!L)return;let _=L.classList.toggle("sp-card-message--expanded");b(x,_?this.t("panel.showLess"):this.t("panel.showMore")),x.setAttribute("aria-expanded",String(_))}else if(A==="resolve"){if(this.pendingMutations.has(E.id))return;let L=x;this.toggleResolve(E,L).catch(()=>{})}else if(A==="delete"){if(this.pendingMutations.has(E.id))return;let L=x;this.deleteFeedback(E,L).catch(()=>{})}return}let u=g.closest(".sp-card");if(u){let w=u.dataset.feedbackId,S=this.feedbacks.find(E=>E.id===w);if(S&&S.annotations.length>0){let E=S.annotations[0];if(!E)return;window.scrollTo({left:E.scrollX,top:E.scrollY,behavior:"smooth"}),this.markers.pinHighlight(S)}}},this.listContainer.addEventListener("click",this.onListClick),this.onListKeydown=v=>{let g=v;if(g.key!=="Enter"&&g.key!==" ")return;let x=g.target,u=x.closest(".sp-card");if(!u||x!==u)return;g.preventDefault();let w=u.dataset.feedbackId,S=this.feedbacks.find(E=>E.id===w);if(S&&S.annotations.length>0){let E=S.annotations[0];if(!E)return;window.scrollTo({left:E.scrollX,top:E.scrollY,behavior:"smooth"}),this.markers.pinHighlight(S)}},this.listContainer.addEventListener("keydown",this.onListKeydown),this.onListMouseover=v=>{let x=v.target.closest(".sp-card");if(!x)return;let u=x.dataset.feedbackId;u&&this.markers.highlight(u)},this.listContainer.addEventListener("mouseover",this.onListMouseover),this.onListMouseout=v=>{let g=v.relatedTarget;g&&this.listContainer.contains(g)||this.markers.highlight("")},this.listContainer.addEventListener("mouseout",this.onListMouseout),this.bus.on("panel:toggle",v=>{v?this.open():this.close()}),e.addEventListener("keydown",v=>{let g=v;if(g.key==="Escape"&&this.isOpen){this.close();return}if(g.key==="Tab"&&this.isOpen){let x=this.root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if(x.length===0)return;let u=x[0],w=x[x.length-1];if(!u||!w)return;let S=e.activeElement;g.shiftKey&&S===u?(g.preventDefault(),w.focus()):!g.shiftKey&&S===w&&(g.preventDefault(),u.focus())}}),this.onMarkerClick=(v=>{this.scrollToFeedback(v.detail.feedbackId)}),document.addEventListener("sp-marker-click",this.onMarkerClick)}colors;bus;client;projectName;markers;t;locale;root;listContainer;searchInput;closeBtn;deleteAllBtn;activeFilters=new Set(["all"]);feedbacks=[];isOpen=!1;searchTimeout=null;loadController=null;pendingMutations=new Set;onMarkerClick;onListClick;onListKeydown;onListMouseover;onListMouseout;async open(){this.isOpen||(this.isOpen=!0,this.root.classList.add("sp-panel--open"),this.root.setAttribute("aria-hidden","false"),this.bus.emit("open"),await this.loadFeedbacks(),requestAnimationFrame(()=>{this.searchInput?this.searchInput.focus():this.closeBtn.focus()}))}close(){if(!this.isOpen)return;this.isOpen=!1,this.root.classList.remove("sp-panel--open"),this.root.setAttribute("aria-hidden","true"),this.bus.emit("close"),this.root.getRootNode().querySelector(".sp-fab")?.focus()}showLoading(){this.listContainer.replaceChildren();let e=h("div",{class:"sp-loading"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-label",this.t("panel.loading"));let n=h("div",{class:"sp-spinner"});e.appendChild(n),this.listContainer.appendChild(e)}showError(){this.listContainer.replaceChildren();let e=h("div",{class:"sp-empty"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite");let n=h("div",{class:"sp-empty-text"});b(n,this.t("panel.loadError"));let i=document.createElement("button");i.className="sp-btn-ghost",i.style.marginTop="8px",b(i,this.t("panel.retry")),i.addEventListener("click",()=>this.loadFeedbacks().catch(()=>{})),e.appendChild(n),e.appendChild(i),this.listContainer.appendChild(e)}async loadFeedbacks(){this.loadController?.abort(),this.loadController=new AbortController;let{signal:e}=this.loadController,n=this.searchInput.value.trim()||void 0,i=this.activeFilters.has("all")?void 0:Array.from(this.activeFilters)[0],s={limit:50};i&&(s.type=i),n&&(s.search=n);let o=this.feedbacks.length>0;o||this.showLoading();try{let{feedbacks:r}=await this.client.getFeedbacks(this.projectName,s);if(e.aborted)return;this.feedbacks=r,this.renderList(),this.markers.render(r)}catch(r){if(e.aborted)return;o||this.showError(),this.bus.emit("feedback:error",r instanceof Error?r:new Error(String(r)))}}renderList(){if(this.listContainer.replaceChildren(),this.feedbacks.length===0){let e=h("div",{class:"sp-empty"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite");let n=h("div",{class:"sp-empty-text"});b(n,this.t("panel.empty")),e.appendChild(n),this.listContainer.appendChild(e);return}this.feedbacks.forEach((e,n)=>{let i=this.createCard(e,n+1);i.style.setProperty("--sp-card-i",String(n)),this.listContainer.appendChild(i)})}createCard(e,n){let i=e.status==="resolved",s=I(e.type,this.colors),o=h("div",{class:`sp-card ${i?"sp-card--resolved":""}`});o.setAttribute("role","listitem"),o.setAttribute("tabindex","0"),o.setAttribute("aria-label",`Feedback #${n}: ${B(e.type,this.t)} \u2014 ${e.message.slice(0,80)}`),o.dataset.feedbackId=e.id;let r=h("div",{class:"sp-card-bar"});r.style.background=i?"#9ca3af":s;let a=h("div",{class:"sp-card-body"}),l=h("div",{class:"sp-card-header"}),c=h("span",{class:"sp-card-number"});b(c,`#${n}`);let d=h("span",{class:"sp-badge"}),p=P(e.type,this.colors);d.style.background=p,d.style.color=s,b(d,B(e.type,this.t));let f=h("span",{class:"sp-card-date"});b(f,X(e.createdAt,this.locale)),l.appendChild(c),l.appendChild(d),l.appendChild(f);let m=h("div",{class:"sp-card-message"});b(m,e.message);let y=document.createElement("button");y.className="sp-card-expand",y.dataset.action="expand",b(y,this.t("panel.showMore")),y.style.display="none",y.setAttribute("aria-expanded","false"),requestAnimationFrame(()=>{m.scrollHeight>m.clientHeight&&(y.style.display="block")});let T=h("div",{class:"sp-card-footer"}),k=document.createElement("button");if(k.className="sp-btn-resolve",k.dataset.action="resolve",i){k.appendChild(F(Ue));let g=document.createElement("span");b(g,` ${this.t("panel.reopen")}`),k.appendChild(g)}else{k.appendChild(F(_e));let g=document.createElement("span");b(g,` ${this.t("panel.resolve")}`),k.appendChild(g)}let C=document.createElement("button");C.className="sp-btn-delete",C.dataset.action="delete",C.appendChild(F(ge));let v=document.createElement("span");return b(v,` ${this.t("panel.delete")}`),C.appendChild(v),T.appendChild(k),T.appendChild(C),a.appendChild(l),a.appendChild(m),a.appendChild(y),a.appendChild(T),o.appendChild(r),o.appendChild(a),o}async deleteFeedback(e,n){this.pendingMutations.add(e.id),n.disabled=!0;try{await this.client.deleteFeedback(e.id),this.bus.emit("feedback:deleted",e.id),await this.loadFeedbacks()}catch(i){this.pendingMutations.delete(e.id),n.disabled=!1,this.bus.emit("feedback:error",i instanceof Error?i:new Error(String(i)))}finally{this.pendingMutations.has(e.id)&&setTimeout(()=>this.pendingMutations.delete(e.id),300)}}async confirmDeleteAll(){if(await this.showConfirmDialog(this.t("panel.deleteAllConfirmTitle"),this.t("panel.deleteAllConfirmMessage"))){this.deleteAllBtn.disabled=!0;try{await this.client.deleteAllFeedbacks(this.projectName),this.bus.emit("feedback:all-deleted"),await this.loadFeedbacks()}catch(n){this.bus.emit("feedback:error",n instanceof Error?n:new Error(String(n)))}finally{this.deleteAllBtn.disabled=!1}}}showConfirmDialog(e,n){return new Promise(i=>{let s=h("div",{class:"sp-confirm-backdrop"}),o=`sp-confirm-title-${Date.now()}`,r=`sp-confirm-msg-${Date.now()}`,a=h("div",{class:"sp-confirm-dialog"});a.setAttribute("role","alertdialog"),a.setAttribute("aria-modal","true"),a.setAttribute("aria-labelledby",o),a.setAttribute("aria-describedby",r);let l=h("div",{class:"sp-confirm-title"});l.id=o,b(l,e);let c=h("div",{class:"sp-confirm-message"});c.id=r,b(c,n);let d=h("div",{class:"sp-confirm-actions"}),p=document.createElement("button");p.type="button",p.className="sp-btn-ghost",b(p,this.t("panel.cancel"));let f=document.createElement("button");f.type="button",f.className="sp-btn-danger",b(f,this.t("panel.confirmDelete"));let m=!1,y=k=>{m||(m=!0,s.removeEventListener("keydown",T),s.style.opacity="0",a.style.transform="translateY(8px) scale(0.97)",setTimeout(()=>{s.remove(),i(k)},200))},T=k=>{let C=k;if(C.key==="Escape"){y(!1);return}C.key==="Tab"&&(C.preventDefault(),s.getRootNode().activeElement===p?f.focus():p.focus())};s.addEventListener("keydown",T),p.addEventListener("click",()=>y(!1)),f.addEventListener("click",()=>y(!0)),s.addEventListener("click",k=>{k.target===s&&y(!1)}),d.appendChild(p),d.appendChild(f),a.appendChild(l),a.appendChild(c),a.appendChild(d),s.appendChild(a),this.root.getRootNode()instanceof ShadowRoot?this.root.getRootNode().appendChild(s):this.root.appendChild(s),requestAnimationFrame(()=>{s.style.opacity="1",a.style.transform="translateY(0) scale(1)",p.focus()})})}async toggleResolve(e,n){this.pendingMutations.add(e.id),n.disabled=!0;try{let i=e.status!=="resolved";await this.client.resolveFeedback(e.id,i),await this.loadFeedbacks()}catch(i){this.pendingMutations.delete(e.id),n.disabled=!1,this.bus.emit("feedback:error",i instanceof Error?i:new Error(String(i)))}finally{this.pendingMutations.has(e.id)&&setTimeout(()=>this.pendingMutations.delete(e.id),300)}}toggleFilter(e,n){this.activeFilters.clear(),this.activeFilters.add(e);let i=n.querySelectorAll(".sp-chip");for(let s of i){let o=this.activeFilters.has(s.dataset.filter??"");s.classList.toggle("sp-chip--active",o),s.setAttribute("aria-pressed",String(o))}this.loadFeedbacks().catch(()=>{})}scrollToFeedback(e){let n=CSS.escape(e),i=this.listContainer.querySelector(`[data-feedback-id="${n}"]`);i&&(i.scrollIntoView({behavior:"smooth",block:"center"}),i.classList.add("sp-anim-flash"),i.addEventListener("animationend",()=>{i.classList.remove("sp-anim-flash")},{once:!0}))}async refresh(){this.isOpen&&await this.loadFeedbacks()}destroy(){this.loadController?.abort(),this.searchTimeout&&clearTimeout(this.searchTimeout),this.listContainer.removeEventListener("click",this.onListClick),this.listContainer.removeEventListener("keydown",this.onListKeydown),this.listContainer.removeEventListener("mouseover",this.onListMouseover),this.listContainer.removeEventListener("mouseout",this.onListMouseout),document.removeEventListener("sp-marker-click",this.onMarkerClick),this.root.remove()}};function ke(t){return{cssSelector:t.anchor.cssSelector,xpath:t.anchor.xpath,textSnippet:t.anchor.textSnippet,elementTag:t.anchor.elementTag,elementId:t.anchor.elementId,textPrefix:t.anchor.textPrefix,textSuffix:t.anchor.textSuffix,fingerprint:t.anchor.fingerprint,neighborText:t.anchor.neighborText,xPct:t.rect.xPct,yPct:t.rect.yPct,wPct:t.rect.wPct,hPct:t.rect.hPct,scrollX:t.scrollX,scrollY:t.scrollY,viewportW:t.viewportW,viewportH:t.viewportH,devicePixelRatio:t.devicePixelRatio}}var oe=class{constructor(e,n){this.store=e;this.projectName=n}store;projectName;async sendFeedback(e){let n=await this.store.createFeedback({projectName:e.projectName,type:e.type,message:e.message,status:"open",url:e.url,viewport:e.viewport,userAgent:e.userAgent,authorName:e.authorName,authorEmail:e.authorEmail,clientId:e.clientId,annotations:e.annotations.map(ke)});return we(n)}async getFeedbacks(e,n){let{feedbacks:i,total:s}=await this.store.getFeedbacks({projectName:e,page:n?.page,limit:n?.limit,type:n?.type,status:n?.status,search:n?.search});return{feedbacks:i.map(we),total:s}}async resolveFeedback(e,n){let i=await this.store.updateFeedback(e,{status:n?"resolved":"open",resolvedAt:n?new Date:null});return we(i)}async deleteFeedback(e){await this.store.deleteFeedback(e)}async deleteAllFeedbacks(e){await this.store.deleteAllFeedbacks(e)}};function we(t){return{id:t.id,projectName:t.projectName,type:t.type,message:t.message,status:t.status,url:t.url,viewport:t.viewport,userAgent:t.userAgent,authorName:t.authorName,authorEmail:t.authorEmail,resolvedAt:t.resolvedAt?.toISOString()??null,createdAt:t.createdAt.toISOString(),updatedAt:t.updatedAt.toISOString(),annotations:t.annotations.map(Wt)}}function Wt(t){return{id:t.id,feedbackId:t.feedbackId,cssSelector:t.cssSelector,xpath:t.xpath,textSnippet:t.textSnippet,elementTag:t.elementTag,elementId:t.elementId,textPrefix:t.textPrefix,textSuffix:t.textSuffix,fingerprint:t.fingerprint,neighborText:t.neighborText,xPct:t.xPct,yPct:t.yPct,wPct:t.wPct,hPct:t.hPct,scrollX:t.scrollX,scrollY:t.scrollY,viewportW:t.viewportW,viewportH:t.viewportH,devicePixelRatio:t.devicePixelRatio,createdAt:t.createdAt.toISOString()}}var qt="linear(0, 0.006, 0.025, 0.06, 0.11, 0.17, 0.25, 0.34, 0.45, 0.56, 0.67, 0.78, 0.88, 0.95, 1.01, 1.04, 1.05, 1.04, 1.02, 1, 0.99, 1)",Ee="cubic-bezier(0.16, 1, 0.3, 1)",Ce="cubic-bezier(0.34, 1.56, 0.64, 1)",Ut="cubic-bezier(0.25, 1, 0.5, 1)",ct=`
171
+ `});this.container.appendChild(r),this.highlightElements.push(r),r.offsetHeight,r.style.opacity="1"}}pinHighlight(e){this.unpinHighlight(),this.showHighlight(e),this.pinnedFeedback=e,this.onDocumentClick=n=>{this.container.contains(n.target)||this.unpinHighlight()},document.addEventListener("click",this.onDocumentClick,{capture:!0})}unpinHighlight(){this.onDocumentClick&&(document.removeEventListener("click",this.onDocumentClick,{capture:!0}),this.onDocumentClick=null),this.pinnedFeedback=null,this.clearHighlight()}clearHighlight(){for(let e of this.highlightElements)e.style.opacity="0",setTimeout(()=>e.remove(),rt);this.highlightElements=[]}removeHighlightElements(){for(let e of this.highlightElements)e.remove();this.highlightElements=[]}clear(){this.unpinHighlight(),this.container.replaceChildren(),this.entries=[],this.clusters=[],this.anchorCache.clear()}destroy(){this.unpinHighlight(),this.repositionTimer&&("cancelIdleCallback"in window&&window.cancelIdleCallback(this.repositionTimer),clearTimeout(this.repositionTimer)),this.resizeHandler&&window.removeEventListener("resize",this.resizeHandler),this.scrollHandler&&window.removeEventListener("scroll",this.scrollHandler,{capture:!0}),this.onDocumentClickForClusters&&document.removeEventListener("click",this.onDocumentClickForClusters),this.mutationObserver?.disconnect(),this.container.remove()}};var se=class{constructor(e,n,i,s,o,r,a,l){this.colors=n;this.bus=i;this.client=s;this.projectName=o;this.markers=r;this.t=a;this.locale=l;this.root=h("div",{class:"sp-panel"}),this.root.setAttribute("role","complementary"),this.root.setAttribute("aria-label",this.t("panel.ariaLabel")),this.root.setAttribute("aria-hidden","true");let c=h("div",{class:"sp-panel-header"}),d=h("span",{class:"sp-panel-title"});b(d,this.t("panel.title")),this.closeBtn=document.createElement("button"),this.closeBtn.className="sp-panel-close",this.closeBtn.setAttribute("aria-label",this.t("panel.close")),this.closeBtn.appendChild(F(G)),this.closeBtn.addEventListener("click",()=>this.close()),this.deleteAllBtn=document.createElement("button"),this.deleteAllBtn.className="sp-btn-delete-all",this.deleteAllBtn.setAttribute("aria-label",this.t("panel.deleteAll")),this.deleteAllBtn.appendChild(F(ge));let p=document.createElement("span");b(p,` ${this.t("panel.deleteAll")}`),this.deleteAllBtn.appendChild(p),this.deleteAllBtn.addEventListener("click",()=>this.confirmDeleteAll());let f=h("div",{class:"sp-panel-header-right"});f.appendChild(this.deleteAllBtn),f.appendChild(this.closeBtn),c.appendChild(d),c.appendChild(f);let m=h("div",{class:"sp-filters"}),y=h("div",{class:"sp-search-wrap"}),T=F(ze);T.setAttribute("class","sp-search-icon"),this.searchInput=document.createElement("input"),this.searchInput.type="text",this.searchInput.className="sp-search",this.searchInput.placeholder=this.t("panel.search"),this.searchInput.setAttribute("aria-label",this.t("panel.searchAria")),this.searchInput.addEventListener("input",()=>{this.searchTimeout&&clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>this.loadFeedbacks().catch(()=>{}),200)}),y.appendChild(T),y.appendChild(this.searchInput);let k=h("div",{class:"sp-chips"}),C=[{value:"all",label:this.t("panel.filterAll")},{value:"question",label:this.t("type.question")},{value:"change",label:this.t("type.change")},{value:"bug",label:this.t("type.bug")},{value:"other",label:this.t("type.other")}];for(let v of C){let g=document.createElement("button");g.className=`sp-chip ${v.value==="all"?"sp-chip--active":""}`,v.value!=="all"&&(g.style.borderColor=I(v.value,this.colors)),b(g,v.label),g.dataset.filter=v.value,g.setAttribute("aria-pressed",v.value==="all"?"true":"false"),g.addEventListener("click",()=>this.toggleFilter(v.value,k)),k.appendChild(g)}m.appendChild(y),m.appendChild(k),this.listContainer=h("div",{class:"sp-list"}),this.listContainer.setAttribute("role","list"),this.listContainer.setAttribute("aria-label",this.t("panel.feedbackList")),this.root.appendChild(c),this.root.appendChild(m),this.root.appendChild(this.listContainer),e.appendChild(this.root),this.onListClick=v=>{let g=v.target,x=g.closest("[data-action]");if(x){v.stopPropagation();let w=x.closest(".sp-card");if(!w)return;let S=w.dataset.feedbackId,E=this.feedbacks.find(L=>L.id===S);if(!E)return;let A=x.dataset.action;if(A==="expand"){let L=w.querySelector(".sp-card-message");if(!L)return;let _=L.classList.toggle("sp-card-message--expanded");b(x,_?this.t("panel.showLess"):this.t("panel.showMore")),x.setAttribute("aria-expanded",String(_))}else if(A==="resolve"){if(this.pendingMutations.has(E.id))return;let L=x;this.toggleResolve(E,L).catch(()=>{})}else if(A==="delete"){if(this.pendingMutations.has(E.id))return;let L=x;this.deleteFeedback(E,L).catch(()=>{})}return}let u=g.closest(".sp-card");if(u){let w=u.dataset.feedbackId,S=this.feedbacks.find(E=>E.id===w);if(S&&S.annotations.length>0){let E=S.annotations[0];if(!E)return;window.scrollTo({left:E.scrollX,top:E.scrollY,behavior:"smooth"}),this.markers.pinHighlight(S)}}},this.listContainer.addEventListener("click",this.onListClick),this.onListKeydown=v=>{let g=v;if(g.key!=="Enter"&&g.key!==" ")return;let x=g.target,u=x.closest(".sp-card");if(!u||x!==u)return;g.preventDefault();let w=u.dataset.feedbackId,S=this.feedbacks.find(E=>E.id===w);if(S&&S.annotations.length>0){let E=S.annotations[0];if(!E)return;window.scrollTo({left:E.scrollX,top:E.scrollY,behavior:"smooth"}),this.markers.pinHighlight(S)}},this.listContainer.addEventListener("keydown",this.onListKeydown),this.onListMouseover=v=>{let x=v.target.closest(".sp-card");if(!x)return;let u=x.dataset.feedbackId;u&&this.markers.highlight(u)},this.listContainer.addEventListener("mouseover",this.onListMouseover),this.onListMouseout=v=>{let g=v.relatedTarget;g&&this.listContainer.contains(g)||this.markers.highlight("")},this.listContainer.addEventListener("mouseout",this.onListMouseout),this.bus.on("panel:toggle",v=>{v?this.open():this.close()}),e.addEventListener("keydown",v=>{let g=v;if(g.key==="Escape"&&this.isOpen){this.close();return}if(g.key==="Tab"&&this.isOpen){let x=this.root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');if(x.length===0)return;let u=x[0],w=x[x.length-1];if(!u||!w)return;let S=e.activeElement;g.shiftKey&&S===u?(g.preventDefault(),w.focus()):!g.shiftKey&&S===w&&(g.preventDefault(),u.focus())}}),this.onMarkerClick=(v=>{this.scrollToFeedback(v.detail.feedbackId)}),document.addEventListener("sp-marker-click",this.onMarkerClick)}colors;bus;client;projectName;markers;t;locale;root;listContainer;searchInput;closeBtn;deleteAllBtn;activeFilters=new Set(["all"]);feedbacks=[];isOpen=!1;searchTimeout=null;loadController=null;pendingMutations=new Set;onMarkerClick;onListClick;onListKeydown;onListMouseover;onListMouseout;async open(){this.isOpen||(this.isOpen=!0,this.root.classList.add("sp-panel--open"),this.root.setAttribute("aria-hidden","false"),this.bus.emit("open"),await this.loadFeedbacks(),requestAnimationFrame(()=>{this.searchInput?this.searchInput.focus():this.closeBtn.focus()}))}close(){if(!this.isOpen)return;this.isOpen=!1,this.root.classList.remove("sp-panel--open"),this.root.setAttribute("aria-hidden","true"),this.bus.emit("close"),this.root.getRootNode().querySelector(".sp-fab")?.focus()}showLoading(){this.listContainer.replaceChildren();let e=h("div",{class:"sp-loading"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-label",this.t("panel.loading"));let n=h("div",{class:"sp-spinner"});e.appendChild(n),this.listContainer.appendChild(e)}showError(){this.listContainer.replaceChildren();let e=h("div",{class:"sp-empty"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite");let n=h("div",{class:"sp-empty-text"});b(n,this.t("panel.loadError"));let i=document.createElement("button");i.className="sp-btn-ghost",i.style.marginTop="8px",b(i,this.t("panel.retry")),i.addEventListener("click",()=>this.loadFeedbacks().catch(()=>{})),e.appendChild(n),e.appendChild(i),this.listContainer.appendChild(e)}async loadFeedbacks(){this.loadController?.abort(),this.loadController=new AbortController;let{signal:e}=this.loadController,n=this.searchInput.value.trim()||void 0,i=this.activeFilters.has("all")?void 0:Array.from(this.activeFilters)[0],s={limit:50};i&&(s.type=i),n&&(s.search=n);let o=this.feedbacks.length>0;o||this.showLoading();try{let{feedbacks:r}=await this.client.getFeedbacks(this.projectName,s);if(e.aborted)return;this.feedbacks=r,this.renderList(),this.markers.render(r)}catch(r){if(e.aborted)return;o||this.showError(),this.bus.emit("feedback:error",r instanceof Error?r:new Error(String(r)))}}renderList(){if(this.listContainer.replaceChildren(),this.feedbacks.length===0){let e=h("div",{class:"sp-empty"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite");let n=h("div",{class:"sp-empty-text"});b(n,this.t("panel.empty")),e.appendChild(n),this.listContainer.appendChild(e);return}this.feedbacks.forEach((e,n)=>{let i=this.createCard(e,n+1);i.style.setProperty("--sp-card-i",String(n)),this.listContainer.appendChild(i)})}createCard(e,n){let i=e.status==="resolved",s=I(e.type,this.colors),o=h("div",{class:`sp-card ${i?"sp-card--resolved":""}`});o.setAttribute("role","listitem"),o.setAttribute("tabindex","0"),o.setAttribute("aria-label",`Feedback #${n}: ${B(e.type,this.t)} \u2014 ${e.message.slice(0,80)}`),o.dataset.feedbackId=e.id;let r=h("div",{class:"sp-card-bar"});r.style.background=i?"#9ca3af":s;let a=h("div",{class:"sp-card-body"}),l=h("div",{class:"sp-card-header"}),c=h("span",{class:"sp-card-number"});b(c,`#${n}`);let d=h("span",{class:"sp-badge"}),p=P(e.type,this.colors);d.style.background=p,d.style.color=s,b(d,B(e.type,this.t));let f=h("span",{class:"sp-card-date"});b(f,X(e.createdAt,this.locale)),l.appendChild(c),l.appendChild(d),l.appendChild(f);let m=h("div",{class:"sp-card-message"});b(m,e.message);let y=document.createElement("button");y.className="sp-card-expand",y.dataset.action="expand",b(y,this.t("panel.showMore")),y.style.display="none",y.setAttribute("aria-expanded","false"),requestAnimationFrame(()=>{m.scrollHeight>m.clientHeight&&(y.style.display="block")});let T=h("div",{class:"sp-card-footer"}),k=document.createElement("button");if(k.className="sp-btn-resolve",k.dataset.action="resolve",i){k.appendChild(F(Ue));let g=document.createElement("span");b(g,` ${this.t("panel.reopen")}`),k.appendChild(g)}else{k.appendChild(F(_e));let g=document.createElement("span");b(g,` ${this.t("panel.resolve")}`),k.appendChild(g)}let C=document.createElement("button");C.className="sp-btn-delete",C.dataset.action="delete",C.appendChild(F(ge));let v=document.createElement("span");return b(v,` ${this.t("panel.delete")}`),C.appendChild(v),T.appendChild(k),T.appendChild(C),a.appendChild(l),a.appendChild(m),a.appendChild(y),a.appendChild(T),o.appendChild(r),o.appendChild(a),o}async deleteFeedback(e,n){this.pendingMutations.add(e.id);let i=this.setButtonLoading(n);try{await this.client.deleteFeedback(e.id),this.bus.emit("feedback:deleted",e.id),await this.loadFeedbacks()}catch(s){i(),this.bus.emit("feedback:error",s instanceof Error?s:new Error(String(s)))}finally{this.pendingMutations.delete(e.id)}}async confirmDeleteAll(){if(await this.showConfirmDialog(this.t("panel.deleteAllConfirmTitle"),this.t("panel.deleteAllConfirmMessage"))){this.deleteAllBtn.disabled=!0;try{await this.client.deleteAllFeedbacks(this.projectName),this.bus.emit("feedback:all-deleted"),await this.loadFeedbacks()}catch(n){this.bus.emit("feedback:error",n instanceof Error?n:new Error(String(n)))}finally{this.deleteAllBtn.disabled=!1}}}showConfirmDialog(e,n){return new Promise(i=>{let s=h("div",{class:"sp-confirm-backdrop"}),o=`sp-confirm-title-${Date.now()}`,r=`sp-confirm-msg-${Date.now()}`,a=h("div",{class:"sp-confirm-dialog"});a.setAttribute("role","alertdialog"),a.setAttribute("aria-modal","true"),a.setAttribute("aria-labelledby",o),a.setAttribute("aria-describedby",r);let l=h("div",{class:"sp-confirm-title"});l.id=o,b(l,e);let c=h("div",{class:"sp-confirm-message"});c.id=r,b(c,n);let d=h("div",{class:"sp-confirm-actions"}),p=document.createElement("button");p.type="button",p.className="sp-btn-ghost",b(p,this.t("panel.cancel"));let f=document.createElement("button");f.type="button",f.className="sp-btn-danger",b(f,this.t("panel.confirmDelete"));let m=!1,y=k=>{m||(m=!0,s.removeEventListener("keydown",T),s.style.opacity="0",a.style.transform="translateY(8px) scale(0.97)",setTimeout(()=>{s.remove(),i(k)},200))},T=k=>{let C=k;if(C.key==="Escape"){y(!1);return}C.key==="Tab"&&(C.preventDefault(),s.getRootNode().activeElement===p?f.focus():p.focus())};s.addEventListener("keydown",T),p.addEventListener("click",()=>y(!1)),f.addEventListener("click",()=>y(!0)),s.addEventListener("click",k=>{k.target===s&&y(!1)}),d.appendChild(p),d.appendChild(f),a.appendChild(l),a.appendChild(c),a.appendChild(d),s.appendChild(a),this.root.getRootNode()instanceof ShadowRoot?this.root.getRootNode().appendChild(s):this.root.appendChild(s),requestAnimationFrame(()=>{s.style.opacity="1",a.style.transform="translateY(0) scale(1)",p.focus()})})}setButtonLoading(e){let n=Array.from(e.childNodes).map(i=>i.cloneNode(!0));return e.disabled=!0,e.replaceChildren(h("div",{class:"sp-spinner sp-spinner--sm"})),()=>{e.replaceChildren(...n),e.disabled=!1}}async toggleResolve(e,n){this.pendingMutations.add(e.id);let i=this.setButtonLoading(n);try{let s=e.status!=="resolved";await this.client.resolveFeedback(e.id,s),await this.loadFeedbacks()}catch(s){i(),this.bus.emit("feedback:error",s instanceof Error?s:new Error(String(s)))}finally{this.pendingMutations.delete(e.id)}}toggleFilter(e,n){this.activeFilters.clear(),this.activeFilters.add(e);let i=n.querySelectorAll(".sp-chip");for(let s of i){let o=this.activeFilters.has(s.dataset.filter??"");s.classList.toggle("sp-chip--active",o),s.setAttribute("aria-pressed",String(o))}this.loadFeedbacks().catch(()=>{})}scrollToFeedback(e){let n=CSS.escape(e),i=this.listContainer.querySelector(`[data-feedback-id="${n}"]`);i&&(i.scrollIntoView({behavior:"smooth",block:"center"}),i.classList.add("sp-anim-flash"),i.addEventListener("animationend",()=>{i.classList.remove("sp-anim-flash")},{once:!0}))}async refresh(){this.isOpen&&await this.loadFeedbacks()}destroy(){this.loadController?.abort(),this.searchTimeout&&clearTimeout(this.searchTimeout),this.listContainer.removeEventListener("click",this.onListClick),this.listContainer.removeEventListener("keydown",this.onListKeydown),this.listContainer.removeEventListener("mouseover",this.onListMouseover),this.listContainer.removeEventListener("mouseout",this.onListMouseout),document.removeEventListener("sp-marker-click",this.onMarkerClick),this.root.remove()}};function ke(t){return{cssSelector:t.anchor.cssSelector,xpath:t.anchor.xpath,textSnippet:t.anchor.textSnippet,elementTag:t.anchor.elementTag,elementId:t.anchor.elementId,textPrefix:t.anchor.textPrefix,textSuffix:t.anchor.textSuffix,fingerprint:t.anchor.fingerprint,neighborText:t.anchor.neighborText,xPct:t.rect.xPct,yPct:t.rect.yPct,wPct:t.rect.wPct,hPct:t.rect.hPct,scrollX:t.scrollX,scrollY:t.scrollY,viewportW:t.viewportW,viewportH:t.viewportH,devicePixelRatio:t.devicePixelRatio}}var oe=class{constructor(e,n){this.store=e;this.projectName=n}store;projectName;async sendFeedback(e){let n=await this.store.createFeedback({projectName:e.projectName,type:e.type,message:e.message,status:"open",url:e.url,viewport:e.viewport,userAgent:e.userAgent,authorName:e.authorName,authorEmail:e.authorEmail,clientId:e.clientId,annotations:e.annotations.map(ke)});return we(n)}async getFeedbacks(e,n){let{feedbacks:i,total:s}=await this.store.getFeedbacks({projectName:e,page:n?.page,limit:n?.limit,type:n?.type,status:n?.status,search:n?.search});return{feedbacks:i.map(we),total:s}}async resolveFeedback(e,n){let i=await this.store.updateFeedback(e,{status:n?"resolved":"open",resolvedAt:n?new Date:null});return we(i)}async deleteFeedback(e){await this.store.deleteFeedback(e)}async deleteAllFeedbacks(e){await this.store.deleteAllFeedbacks(e)}};function we(t){return{id:t.id,projectName:t.projectName,type:t.type,message:t.message,status:t.status,url:t.url,viewport:t.viewport,userAgent:t.userAgent,authorName:t.authorName,authorEmail:t.authorEmail,resolvedAt:t.resolvedAt?.toISOString()??null,createdAt:t.createdAt.toISOString(),updatedAt:t.updatedAt.toISOString(),annotations:t.annotations.map(Wt)}}function Wt(t){return{id:t.id,feedbackId:t.feedbackId,cssSelector:t.cssSelector,xpath:t.xpath,textSnippet:t.textSnippet,elementTag:t.elementTag,elementId:t.elementId,textPrefix:t.textPrefix,textSuffix:t.textSuffix,fingerprint:t.fingerprint,neighborText:t.neighborText,xPct:t.xPct,yPct:t.yPct,wPct:t.wPct,hPct:t.hPct,scrollX:t.scrollX,scrollY:t.scrollY,viewportW:t.viewportW,viewportH:t.viewportH,devicePixelRatio:t.devicePixelRatio,createdAt:t.createdAt.toISOString()}}var qt="linear(0, 0.006, 0.025, 0.06, 0.11, 0.17, 0.25, 0.34, 0.45, 0.56, 0.67, 0.78, 0.88, 0.95, 1.01, 1.04, 1.05, 1.04, 1.02, 1, 0.99, 1)",Ee="cubic-bezier(0.16, 1, 0.3, 1)",Ce="cubic-bezier(0.34, 1.56, 0.64, 1)",Ut="cubic-bezier(0.25, 1, 0.5, 1)",ct=`
172
172
  /* ---- Keyframes ---- */
173
173
 
174
174
  @keyframes sp-fab-in {
@@ -894,6 +894,11 @@
894
894
  pointer-events: none;
895
895
  }
896
896
 
897
+ .sp-spinner--sm {
898
+ width: 14px;
899
+ height: 14px;
900
+ }
901
+
897
902
  /* ---- Delete All (header) ---- */
898
903
 
899
904
  .sp-panel-header-right {